Skip to content
清晨的一缕阳光
返回

性能优化实战

性能优化实战

性能优化方法论

优化原则

80/20 法则

数据驱动

循序渐进

优化流程

1. 建立性能基线

2. 性能监控分析

3. 定位性能瓶颈

4. 制定优化方案

5. 实施优化

6. 验证优化效果

7. 持续监控

JVM 性能优化

1. 内存优化

堆内存配置

# 生产环境配置
-Xms4g -Xmx4g              # 堆内存大小
-Xmn2g                     # 新生代大小
-XX:MetaspaceSize=256m     # 元空间初始大小
-XX:MaxMetaspaceSize=512m  # 元空间最大大小

垃圾回收器选择

# G1 GC(推荐)
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:G1HeapRegionSize=16m

# ZGC(低延迟)
-XX:+UseZGC
-XX:ZCollectionInterval=5

内存优化建议

2. GC 优化

GC 日志分析

# 开启 GC 日志
-Xlog:gc*:file=gc.log:time,uptime,level,tags

# 分析工具
gceviz -f gc.log

GC 调优参数

# G1 GC 调优
-XX:InitiatingHeapOccupancyPercent=45  # 触发并发标记的堆占用率
-XX:ConcGCThreads=4                     # 并发 GC 线程数
-XX:ParallelGCThreads=8                 # 并行 GC 线程数
-XX:MaxGCPauseMillis=200                # 最大 GC 停顿时间

GC 优化建议

3. 线程优化

线程池配置

@Bean
public ThreadPoolTaskExecutor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    
    // 核心线程数 = CPU 核心数 * 2
    executor.setCorePoolSize(Runtime.getRuntime().availableProcessors() * 2);
    
    // 最大线程数 = CPU 核心数 * 4
    executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 4);
    
    // 队列容量
    executor.setQueueCapacity(200);
    
    // 线程空闲时间
    executor.setKeepAliveSeconds(60);
    
    // 线程名前缀
    executor.setThreadNamePrefix("async-");
    
    // 拒绝策略
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    
    return executor;
}

Tomcat 线程池

server:
  tomcat:
    threads:
      max: 200        # 最大工作线程数
      min-spare: 10   # 最小空闲线程数
    max-connections: 8192  # 最大连接数
    accept-count: 100      # 等待队列长度

数据库优化

1. SQL 优化

索引优化

-- 创建复合索引
CREATE INDEX idx_user_status_time ON orders (user_id, status, create_time);

-- 覆盖索引
SELECT user_id, status FROM orders WHERE user_id = 1;

-- 避免全表扫描
EXPLAIN SELECT * FROM orders WHERE user_id = 1;

SQL 优化建议

分页优化

-- 不推荐(大数据量时慢)
SELECT * FROM orders ORDER BY create_time DESC LIMIT 100000, 10;

-- 推荐(使用覆盖索引)
SELECT * FROM orders o
INNER JOIN (
    SELECT id FROM orders ORDER BY create_time DESC LIMIT 100000, 10
) tmp ON o.id = tmp.id;

2. 连接池优化

HikariCP 配置

spring:
  datasource:
    hikari:
      # 最小空闲连接数
      minimum-idle: 10
      
      # 最大连接数
      maximum-pool-size: 50
      
      # 空闲连接超时(毫秒)
      idle-timeout: 30000
      
      # 连接超时(毫秒)
      connection-timeout: 30000
      
      # 连接最大生命周期(毫秒)
      max-lifetime: 1800000
      
      # 连接测试查询
      connection-test-query: SELECT 1

连接池优化建议

3. 缓存优化

Redis 缓存

@Configuration
public class RedisConfig {
    
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(10))  // 默认 TTL 10 分钟
            .serializeKeysWith(RedisSerializationContext.SerializationPair
                .fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(RedisSerializationContext.SerializationPair
                .fromSerializer(new GenericJackson2JsonRedisSerializer()));
        
        return RedisCacheManager.builder(factory)
            .cacheDefaults(config)
            .withCacheConfiguration("user", 
                config.entryTtl(Duration.ofMinutes(30)))  // 用户缓存 30 分钟
            .withCacheConfiguration("order", 
                config.entryTtl(Duration.ofMinutes(60)))  // 订单缓存 60 分钟
            .build();
    }
}

多级缓存

@Component
public class MultiLevelCache {
    
    @Autowired
    private CacheManager localCache;  // Caffeine
    
    @Autowired
    private CacheManager redisCache;  // Redis
    
    public <T> T get(String key, Class<T> type) {
        // 1. 本地缓存
        T value = localCache.getCache("local").get(key, type);
        if (value != null) {
            return value;
        }
        
        // 2. Redis 缓存
        value = redisCache.getCache("redis").get(key, type);
        if (value != null) {
            // 回写本地缓存
            localCache.getCache("local").put(key, value);
            return value;
        }
        
        return null;
    }
}

网络优化

1. HTTP 优化

连接复用

feign:
  httpclient:
    enabled: true
    max-connections: 200        # 最大连接数
    max-connections-per-route: 50  # 每路由最大连接数
    time-to-live: 60000         # 连接存活时间(毫秒)

压缩配置

feign:
  compression:
    request:
      enabled: true
      mime-types: text/xml,application/xml,application/json
      min-request-size: 2048
    response:
      enabled: true

2. Nginx 优化

负载均衡

upstream backend {
    least_conn;  # 最少连接数
    server backend1:8080 weight=5;
    server backend2:8080 weight=3;
    server backend3:8080 backup;
    
    keepalive 32;  # 长连接数
}

server {
    listen 80;
    
    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        
        # 超时配置
        proxy_connect_timeout 10s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        
        # 缓冲配置
        proxy_buffer_size 4k;
        proxy_buffers 4 32k;
        proxy_busy_buffers_size 64k;
    }
}

3. TCP 优化

Linux 内核参数

# /etc/sysctl.conf

# TCP 连接复用
net.ipv4.tcp_tw_reuse = 1

# 端口范围
net.ipv4.ip_local_port_range = 1024 65535

# 连接队列
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# 缓冲区
net.core.rmem_default = 262144
net.core.rmem_max = 67108864
net.core.wmem_default = 262144
net.core.wmem_max = 67108864

# 应用配置
sysctl -p

代码优化

1. 集合优化

选择合适集合

// 频繁查询,不修改 → ArrayList
List<String> list = new ArrayList<>();

// 频繁插入删除 → LinkedList
List<String> list = new LinkedList<>();

// 频繁查询 → HashMap
Map<String, String> map = new HashMap<>();

// 有序 → TreeMap
Map<String, String> map = new TreeMap<>();

// 线程安全 → ConcurrentHashMap
Map<String, String> map = new ConcurrentHashMap<>();

集合初始化

// 指定初始容量,避免扩容
List<String> list = new ArrayList<>(100);
Map<String, String> map = new HashMap<>(64);

// 使用 Collections 工具类
List<String> immutableList = Collections.unmodifiableList(list);

2. 流处理优化

并行流

// 数据量大时使用并行流
List<String> result = list.parallelStream()
    .filter(s -> s.length() > 5)
    .map(String::toUpperCase)
    .collect(Collectors.toList());

// 注意线程安全
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
list.parallelStream().forEach(s -> map.put(s, s.length()));

流式处理

// 避免中间操作产生新集合
list.stream()
    .filter(s -> s != null)
    .map(String::trim)
    .filter(s -> !s.isEmpty())
    .collect(Collectors.toList());

3. 异步优化

CompletableFuture

// 串行执行(慢)
User user = userService.getUser(id);
Order order = orderService.getOrder(id);
Product product = productService.getProduct(id);

// 并行执行(快)
CompletableFuture<User> userFuture = CompletableFuture.supplyAsync(() -> 
    userService.getUser(id));

CompletableFuture<Order> orderFuture = CompletableFuture.supplyAsync(() -> 
    orderService.getOrder(id));

CompletableFuture<Product> productFuture = CompletableFuture.supplyAsync(() -> 
    productService.getProduct(id));

CompletableFuture.allOf(userFuture, orderFuture, productFuture).join();

User user = userFuture.get();
Order order = orderFuture.get();
Product product = productFuture.get();

架构优化

1. 读写分离

主从配置

spring:
  datasource:
    dynamic:
      primary: master
      datasource:
        master:
          url: jdbc:mysql://master:3306/db
          username: root
          password: root
        slave1:
          url: jdbc:mysql://slave1:3306/db
          username: root
          password: root
        slave2:
          url: jdbc:mysql://slave2:3306/db
          username: root
          password: root

读写分离注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadOnly {
}

@Aspect
@Component
public class ReadOnlyAspect {
    
    @Around("@annotation(readOnly)")
    public Object around(ProceedingJoinPoint pjp, ReadOnly readOnly) throws Throwable {
        DynamicDataSource.setSlave();
        try {
            return pjp.proceed();
        } finally {
            DynamicDataSource.setMaster();
        }
    }
}

@Service
public class UserService {
    
    @ReadOnly
    public User getUser(Long id) {
        return userRepository.findById(id);
    }
}

2. 分库分表

分片策略

@Configuration
public class ShardingConfig {
    
    @Bean
    public DataSource dataSource() {
        ShardingSphereDataSource dataSource = new ShardingSphereDataSource(
            createDataSourceMap(),
            Collections.singletonList(shardingRule),
            new Properties()
        );
        return dataSource;
    }
    
    private ShardingRuleConfiguration shardingRule() {
        ShardingRuleConfiguration shardingRule = new ShardingRuleConfiguration();
        
        // 分表策略
        shardingRule.getTables().add(orderTableRule());
        
        // 分库策略
        shardingRule.getDatabaseShardingRule().setDatabaseShardingColumn("user_id");
        shardingRule.getDatabaseShardingRule().setShardingAlgorithmName("database_inline");
        
        return shardingRule;
    }
    
    private TableRuleConfiguration orderTableRule() {
        TableRuleConfiguration tableRule = new TableRuleConfiguration("orders");
        tableRule.setActualDataNodes("ds${0..1}.orders_${0..3}");
        tableRule.setTableShardingColumn("order_id");
        tableRule.setTableShardingAlgorithmName("table_inline");
        return tableRule;
    }
}

3. 消息队列削峰

异步处理

// 同步处理(慢)
@PostMapping("/orders")
public Result<Order> createOrder(@RequestBody CreateOrderRequest request) {
    // 1. 创建订单
    Order order = orderService.create(request);
    
    // 2. 发送短信
    smsService.send(order);
    
    // 3. 发送邮件
    emailService.send(order);
    
    // 4. 更新统计
    analyticsService.update(order);
    
    return Result.success(order);
}

// 异步处理(快)
@PostMapping("/orders")
public Result<Order> createOrder(@RequestBody CreateOrderRequest request) {
    // 1. 创建订单
    Order order = orderService.create(request);
    
    // 2. 发送消息
    kafkaTemplate.send("order-created", order);
    
    return Result.success(order);
}

// 消息消费者
@KafkaListener(topics = "order-created")
public void consume(Order order) {
    // 异步处理
    smsService.send(order);
    emailService.send(order);
    analyticsService.update(order);
}

监控与调优

1. 性能监控

APM 工具

# SkyWalking Agent
-javaagent:/opt/skywalking-agent/skywalking-agent.jar
-Dskywalking.agent.service_name=user-service
-Dskywalking.collector.backend_service=oap:11800

关键指标

2. 性能测试

压测工具

# JMeter
jmeter -n -t test.jmx -l result.jtl

# wrk
wrk -t12 -c400 -d30s http://localhost:8080/api/users

# ab
ab -n 10000 -c 100 http://localhost:8080/api/users

压测指标

3. 性能分析

JProfiler

Arthas

# 查看方法执行时间
trace com.example.UserService getUser

# 查看方法调用参数
watch com.example.UserService getUser '{params, returnObj}'

# 查看 JVM 信息
dashboard

# 查看线程
thread

# 查看堆内存
heap

最佳实践

1. 性能基线

建立基线

性能预算

2. 持续优化

优化循环

监控 → 分析 → 优化 → 验证 → 监控

优化优先级

  1. 数据库优化(影响最大)
  2. 缓存优化(效果明显)
  3. 代码优化(成本最低)
  4. 架构优化(长期收益)

3. 性能文化

性能意识

知识沉淀

总结

微服务性能优化是系统性工程,需要从 JVM、数据库、缓存、网络、代码、架构等多个维度进行优化。

建立完善的性能监控体系,基于数据驱动优化,持续迭代改进。

培养性能文化,将性能意识融入开发流程,建立性能最佳实践。


分享这篇文章到:

上一篇文章
项目结构规范
下一篇文章
Java 内存模型进阶