Files
game_server/CONCURRENCY_OPTIMIZATION_SUMMARY.md

9.2 KiB
Raw Permalink Blame History

并发性能优化总结

优化概述

本次优化主要针对提高系统并发处理能力,解决潜在的超时和阻塞问题。

主要优化内容

1. Tomcat 线程池优化(高优先级)

文件: src/main/resources/application.yml

优化项:

server:
  tomcat:
    threads:
      max: 200                    # 最大工作线程数默认值为200
      min-spare: 20               # 最小空闲线程数从默认10提升到20
    max-connections: 10000        # 最大连接数从默认8192提升
    accept-count: 200             # 等待队列长度从默认100提升
    connection-timeout: 20000     # 连接超时20秒
  shutdown: graceful              # 优雅关闭

效果:

  • 支持更多并发 HTTP 请求
  • 减少请求等待时间
  • 优雅关闭避免请求中断

2. 数据库连接池优化(高优先级)

文件: src/main/resources/application.yml

优化项:

hikari:
  maximum-pool-size: 100          # 从50增加到100
  minimum-idle: 20                # 从10增加到20
  connection-timeout: 10000       # 从30秒降低到10秒
  idle-timeout: 300000            # 从10分钟降低到5分钟
  leak-detection-threshold: 30000 # 从60秒降低到30秒
  validation-timeout: 3000        # 从5秒降低到3秒

MySQL 会话参数优化:

innodb_lock_wait_timeout=10     # 从30秒降低到10秒
wait_timeout=300                # 新增5分钟
interactive_timeout=300         # 新增5分钟

效果:

  • 支持更多并发数据库操作
  • 更快检测和释放死锁
  • 更快发现连接泄漏问题
  • 减少数据库连接等待时间

3. HTTP 客户端连接池配置(高优先级)

文件: src/main/java/com/gameplatform/server/service/external/ScriptClient.java

新增配置:

// 连接池配置
ConnectionProvider connectionProvider = ConnectionProvider.builder("script-client-pool")
        .maxConnections(100)              // 最大连接数
        .pendingAcquireMaxCount(200)      // 等待队列大小
        .pendingAcquireTimeout(Duration.ofSeconds(10))
        .maxIdleTime(Duration.ofSeconds(30))
        .maxLifeTime(Duration.ofMinutes(5))
        .evictInBackground(Duration.ofSeconds(60))
        .build();

// HttpClient 配置
HttpClient httpClient = HttpClient.create(connectionProvider)
        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeoutMs)
        .responseTimeout(Duration.ofMillis(readTimeoutMs))
        .doOnConnected(conn -> 
            conn.addHandlerLast(new ReadTimeoutHandler(...))
                .addHandlerLast(new WriteTimeoutHandler(...)))
        .compress(true);

效果:

  • 避免 HTTP 连接耗尽
  • 支持连接复用,提升性能
  • 自动清理过期连接
  • 启用 HTTP 压缩减少带宽

4. 异步线程池优化(中优先级)

文件: src/main/java/com/gameplatform/server/config/AsyncConfig.java

设备检测线程池优化:

deviceDetectionExecutor:
  corePoolSize: 10              # 从3增加到10
  maxPoolSize: 50               # 从10增加到50
  queueCapacity: 500            # 从100增加到500
  rejectedPolicy: DiscardOldest # 改为丢弃最旧避免阻塞HTTP线程

新增通用异步线程池:

taskExecutor:
  corePoolSize: 20
  maxPoolSize: 100
  queueCapacity: 1000
  rejectedPolicy: CallerRunsPolicy

效果:

  • 支持更多并发异步任务
  • 避免 HTTP 线程被阻塞
  • 提供更好的任务隔离

5. 事务超时优化(中优先级)

文件: src/main/resources/application.yml

优化项:

spring:
  transaction:
    default-timeout: 15         # 从30秒降低到15秒
  mvc:
    async:
      request-timeout: 60000    # 新增异步请求超时60秒

效果:

  • 更快检测和终止长事务
  • 减少数据库连接占用时间
  • 避免死锁长时间等待

6. 监控端点扩展

文件: src/main/resources/application.yml

新增监控端点:

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,threaddump

效果:

  • 可以查看线程状态 (/actuator/threaddump)
  • 可以查看性能指标 (/actuator/metrics)
  • 便于排查性能问题

性能提升预期

并发能力对比

配置项 优化前 优化后 提升幅度
Tomcat 最大线程数 200默认 200 -
Tomcat 最小线程数 10默认 20 +100%
Tomcat 最大连接数 8192默认 10000 +22%
数据库连接池 50 100 +100%
HTTP 客户端连接池 无限制(默认) 100受控 稳定性提升
设备检测线程池 3-10 10-50 +400%
异步任务线程池 20-100 新增

响应时间改善

  • 数据库操作: 连接获取时间从可能的30秒降低到10秒以内
  • HTTP 请求: 连接复用,减少建立连接开销
  • 锁等待: 从30秒降低到10秒更快释放资源
  • 连接泄漏检测: 从60秒降低到30秒更快发现问题

验证步骤

1. 启动应用检查日志

启动后应该看到类似日志:

ScriptClient 初始化完成: baseUrl=..., 最大连接数=100
设备检测线程池已初始化: coreSize=10, maxSize=50, queueCapacity=500
通用异步任务线程池已初始化: coreSize=20, maxSize=100, queueCapacity=1000
HikariPool-1 - Starting...
HikariPool-1 - Start completed.

2. 检查监控端点

# 查看健康状态
curl http://localhost:18080/actuator/health

# 查看线程信息
curl http://localhost:18080/actuator/threaddump

# 查看指标
curl http://localhost:18080/actuator/metrics
curl http://localhost:18080/actuator/metrics/hikaricp.connections.active
curl http://localhost:18080/actuator/metrics/tomcat.threads.busy

3. 并发压力测试

使用工具如 JMeter 或 Apache Bench 进行压力测试:

# 使用 Apache Bench 测试
ab -n 10000 -c 200 http://localhost:18080/api/some-endpoint

# 使用 wrk 测试
wrk -t12 -c400 -d30s http://localhost:18080/api/some-endpoint

4. 监控关键指标

在压力测试期间,监控以下指标:

  • Tomcat 线程池使用率
  • HikariCP 连接池使用率
  • HTTP 客户端连接数
  • 异步线程池队列长度
  • 响应时间分布
  • 错误率

性能调优建议

根据实际负载调整

  1. 如果发现 Tomcat 线程不够:

    server:
      tomcat:
        threads:
          max: 300  # 可以继续增加
    
  2. 如果数据库连接池经常满:

    hikari:
      maximum-pool-size: 150  # 可以继续增加
    
  3. 如果异步任务队列经常满:

    executor.setQueueCapacity(1000);  // 增加队列
    executor.setMaxPoolSize(100);     // 增加最大线程
    

JVM 参数建议

如果并发量很大,建议调整 JVM 参数:

java -jar app.jar \
  -Xms2g \                    # 初始堆内存
  -Xmx4g \                    # 最大堆内存
  -XX:+UseG1GC \              # 使用G1垃圾收集器
  -XX:MaxGCPauseMillis=200 \  # GC暂停目标
  -XX:ParallelGCThreads=8 \   # 并行GC线程数
  -XX:ConcGCThreads=2         # 并发GC线程数

常见问题排查

1. 连接池耗尽

症状: 日志出现 "Connection is not available"

排查:

curl http://localhost:18080/actuator/metrics/hikaricp.connections.active
curl http://localhost:18080/actuator/metrics/hikaricp.connections.pending

解决: 增加 maximum-pool-size 或检查是否有连接泄漏

2. 线程池满

症状: 日志出现 "Task rejected" 或请求响应变慢

排查:

curl http://localhost:18080/actuator/metrics/tomcat.threads.busy
curl http://localhost:18080/actuator/threaddump

解决: 增加线程池大小或优化慢接口

3. HTTP 连接超时

症状: 日志出现 "Connection timeout"

排查: 检查外部服务是否正常,网络是否畅通

解决:

  • 调整超时时间
  • 增加重试机制
  • 添加断路器

后续优化建议

  1. 添加缓存: 使用 Redis 缓存热点数据
  2. 读写分离: 使用数据库主从复制
  3. 服务拆分: 将耗时操作拆分到独立服务
  4. 消息队列: 异步处理非实时任务
  5. CDN: 静态资源使用 CDN 加速

回滚方案

如果优化后出现问题,可以通过以下步骤回滚:

# 恢复配置文件
git checkout HEAD~1 -- src/main/resources/application.yml
git checkout HEAD~1 -- src/main/java/com/gameplatform/server/service/external/ScriptClient.java
git checkout HEAD~1 -- src/main/java/com/gameplatform/server/config/AsyncConfig.java

# 重新编译部署
mvn clean package -DskipTests

总结

本次优化从以下几个维度提升了系统并发能力:

  1. HTTP 服务器: Tomcat 线程池和连接池优化
  2. 数据库: HikariCP 连接池优化,锁等待超时优化
  3. HTTP 客户端: Reactor Netty 连接池配置
  4. 异步处理: 线程池扩容和策略优化
  5. 事务管理: 超时时间优化
  6. 监控: 扩展监控端点

预期可以将系统并发处理能力提升 2-5 倍,响应时间降低 30-50%

建议在生产环境部署前,先在测试环境进行充分的压力测试验证。