feat: 优化异步线程池配置,增加设备检测和通用任务线程池的核心与最大线程数,提升并发处理能力;更新数据库连接池配置,增强连接管理和性能
This commit is contained in:
361
CONCURRENCY_OPTIMIZATION_SUMMARY.md
Normal file
361
CONCURRENCY_OPTIMIZATION_SUMMARY.md
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
# 并发性能优化总结
|
||||||
|
|
||||||
|
## 优化概述
|
||||||
|
|
||||||
|
本次优化主要针对提高系统并发处理能力,解决潜在的超时和阻塞问题。
|
||||||
|
|
||||||
|
## 主要优化内容
|
||||||
|
|
||||||
|
### 1. ✅ Tomcat 线程池优化(高优先级)
|
||||||
|
|
||||||
|
**文件**: `src/main/resources/application.yml`
|
||||||
|
|
||||||
|
**优化项**:
|
||||||
|
```yaml
|
||||||
|
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`
|
||||||
|
|
||||||
|
**优化项**:
|
||||||
|
```yaml
|
||||||
|
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`
|
||||||
|
|
||||||
|
**新增配置**:
|
||||||
|
```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`
|
||||||
|
|
||||||
|
**设备检测线程池优化**:
|
||||||
|
```java
|
||||||
|
deviceDetectionExecutor:
|
||||||
|
corePoolSize: 10 # 从3增加到10
|
||||||
|
maxPoolSize: 50 # 从10增加到50
|
||||||
|
queueCapacity: 500 # 从100增加到500
|
||||||
|
rejectedPolicy: DiscardOldest # 改为丢弃最旧,避免阻塞HTTP线程
|
||||||
|
```
|
||||||
|
|
||||||
|
**新增通用异步线程池**:
|
||||||
|
```java
|
||||||
|
taskExecutor:
|
||||||
|
corePoolSize: 20
|
||||||
|
maxPoolSize: 100
|
||||||
|
queueCapacity: 1000
|
||||||
|
rejectedPolicy: CallerRunsPolicy
|
||||||
|
```
|
||||||
|
|
||||||
|
**效果**:
|
||||||
|
- 支持更多并发异步任务
|
||||||
|
- 避免 HTTP 线程被阻塞
|
||||||
|
- 提供更好的任务隔离
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. ✅ 事务超时优化(中优先级)
|
||||||
|
|
||||||
|
**文件**: `src/main/resources/application.yml`
|
||||||
|
|
||||||
|
**优化项**:
|
||||||
|
```yaml
|
||||||
|
spring:
|
||||||
|
transaction:
|
||||||
|
default-timeout: 15 # 从30秒降低到15秒
|
||||||
|
mvc:
|
||||||
|
async:
|
||||||
|
request-timeout: 60000 # 新增,异步请求超时60秒
|
||||||
|
```
|
||||||
|
|
||||||
|
**效果**:
|
||||||
|
- 更快检测和终止长事务
|
||||||
|
- 减少数据库连接占用时间
|
||||||
|
- 避免死锁长时间等待
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. ✅ 监控端点扩展
|
||||||
|
|
||||||
|
**文件**: `src/main/resources/application.yml`
|
||||||
|
|
||||||
|
**新增监控端点**:
|
||||||
|
```yaml
|
||||||
|
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. 检查监控端点
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 查看健康状态
|
||||||
|
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 进行压力测试:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 使用 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 线程不够**:
|
||||||
|
```yaml
|
||||||
|
server:
|
||||||
|
tomcat:
|
||||||
|
threads:
|
||||||
|
max: 300 # 可以继续增加
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **如果数据库连接池经常满**:
|
||||||
|
```yaml
|
||||||
|
hikari:
|
||||||
|
maximum-pool-size: 150 # 可以继续增加
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **如果异步任务队列经常满**:
|
||||||
|
```java
|
||||||
|
executor.setQueueCapacity(1000); // 增加队列
|
||||||
|
executor.setMaxPoolSize(100); // 增加最大线程
|
||||||
|
```
|
||||||
|
|
||||||
|
### JVM 参数建议
|
||||||
|
|
||||||
|
如果并发量很大,建议调整 JVM 参数:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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"
|
||||||
|
|
||||||
|
**排查**:
|
||||||
|
```bash
|
||||||
|
curl http://localhost:18080/actuator/metrics/hikaricp.connections.active
|
||||||
|
curl http://localhost:18080/actuator/metrics/hikaricp.connections.pending
|
||||||
|
```
|
||||||
|
|
||||||
|
**解决**: 增加 `maximum-pool-size` 或检查是否有连接泄漏
|
||||||
|
|
||||||
|
### 2. 线程池满
|
||||||
|
|
||||||
|
**症状**: 日志出现 "Task rejected" 或请求响应变慢
|
||||||
|
|
||||||
|
**排查**:
|
||||||
|
```bash
|
||||||
|
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 加速
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 回滚方案
|
||||||
|
|
||||||
|
如果优化后出现问题,可以通过以下步骤回滚:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 恢复配置文件
|
||||||
|
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%**。
|
||||||
|
|
||||||
|
建议在生产环境部署前,先在测试环境进行充分的压力测试验证。
|
||||||
|
|
||||||
306
DEPLOYMENT_CHECKLIST.md
Normal file
306
DEPLOYMENT_CHECKLIST.md
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
# 并发优化部署检查清单
|
||||||
|
|
||||||
|
## 📋 部署前检查
|
||||||
|
|
||||||
|
### 1. 代码变更确认
|
||||||
|
- [x] `application.yml` - Tomcat 线程池配置
|
||||||
|
- [x] `application.yml` - HikariCP 连接池配置
|
||||||
|
- [x] `application.yml` - 事务超时配置
|
||||||
|
- [x] `application.yml` - 监控端点配置
|
||||||
|
- [x] `ScriptClient.java` - HTTP 连接池配置
|
||||||
|
- [x] `AsyncConfig.java` - 异步线程池配置
|
||||||
|
|
||||||
|
### 2. 依赖检查
|
||||||
|
确保 `pom.xml` 包含必要的依赖:
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.projectreactor.netty</groupId>
|
||||||
|
<artifactId>reactor-netty</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 编译检查
|
||||||
|
```bash
|
||||||
|
mvn clean compile
|
||||||
|
# 确保没有编译错误
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 部署步骤
|
||||||
|
|
||||||
|
### 1. 备份当前版本
|
||||||
|
```bash
|
||||||
|
# 备份配置文件
|
||||||
|
cp src/main/resources/application.yml application.yml.backup
|
||||||
|
|
||||||
|
# 备份当前 JAR 包
|
||||||
|
cp target/gameplatform-server-*.jar gameplatform-server-backup.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 编译新版本
|
||||||
|
```bash
|
||||||
|
mvn clean package -DskipTests
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 停止旧服务
|
||||||
|
```bash
|
||||||
|
# 找到进程
|
||||||
|
ps aux | grep gameplatform-server
|
||||||
|
|
||||||
|
# 优雅停止(如果配置了)
|
||||||
|
kill -TERM <PID>
|
||||||
|
|
||||||
|
# 或强制停止
|
||||||
|
kill -9 <PID>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 启动新服务
|
||||||
|
```bash
|
||||||
|
java -jar target/gameplatform-server-*.jar \
|
||||||
|
-Xms2g -Xmx4g \
|
||||||
|
-XX:+UseG1GC \
|
||||||
|
-XX:MaxGCPauseMillis=200 \
|
||||||
|
> logs/app.log 2>&1 &
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 启动日志检查
|
||||||
|
```bash
|
||||||
|
tail -f logs/app.log
|
||||||
|
```
|
||||||
|
|
||||||
|
**期望看到的日志**:
|
||||||
|
```
|
||||||
|
ScriptClient 初始化完成: baseUrl=..., 最大连接数=100
|
||||||
|
设备检测线程池已初始化: coreSize=10, maxSize=50, queueCapacity=500
|
||||||
|
通用异步任务线程池已初始化: coreSize=20, maxSize=100, queueCapacity=1000
|
||||||
|
HikariPool-1 - Starting...
|
||||||
|
HikariPool-1 - Start completed.
|
||||||
|
Tomcat started on port(s): 18080
|
||||||
|
Started GamePlatformServerApplication in X.XX seconds
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ 部署后验证
|
||||||
|
|
||||||
|
### 1. 健康检查
|
||||||
|
```bash
|
||||||
|
# 检查服务是否启动
|
||||||
|
curl http://localhost:18080/actuator/health
|
||||||
|
|
||||||
|
# 期望输出
|
||||||
|
{"status":"UP"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 功能验证
|
||||||
|
```bash
|
||||||
|
# 测试关键接口
|
||||||
|
curl -X POST http://localhost:18080/api/auth/login \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"username":"test","password":"test"}'
|
||||||
|
|
||||||
|
# 测试设备状态接口
|
||||||
|
curl http://localhost:18080/api/devices/status
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 监控指标检查
|
||||||
|
```bash
|
||||||
|
# 检查数据库连接池
|
||||||
|
curl http://localhost:18080/actuator/metrics/hikaricp.connections.active
|
||||||
|
curl http://localhost:18080/actuator/metrics/hikaricp.connections
|
||||||
|
|
||||||
|
# 检查 Tomcat 线程
|
||||||
|
curl http://localhost:18080/actuator/metrics/tomcat.threads.busy
|
||||||
|
curl http://localhost:18080/actuator/metrics/tomcat.threads.current
|
||||||
|
|
||||||
|
# 检查 HTTP 客户端指标
|
||||||
|
curl http://localhost:18080/actuator/metrics/reactor.netty.connection.provider
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 性能基准测试
|
||||||
|
```bash
|
||||||
|
# 简单压测(100并发,持续30秒)
|
||||||
|
ab -n 10000 -c 100 -t 30 http://localhost:18080/api/health
|
||||||
|
|
||||||
|
# 观察结果
|
||||||
|
# - 成功率应该 > 99%
|
||||||
|
# - 平均响应时间应该 < 100ms
|
||||||
|
# - 无连接错误
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 监控观察(前24小时)
|
||||||
|
|
||||||
|
### 1. 关键指标监控
|
||||||
|
|
||||||
|
| 指标 | 正常范围 | 告警阈值 |
|
||||||
|
|------|----------|----------|
|
||||||
|
| CPU 使用率 | < 60% | > 80% |
|
||||||
|
| 内存使用率 | < 70% | > 85% |
|
||||||
|
| 数据库连接数 | < 80 | > 90 |
|
||||||
|
| Tomcat 线程数 | < 150 | > 180 |
|
||||||
|
| 响应时间 P95 | < 500ms | > 1000ms |
|
||||||
|
| 错误率 | < 0.1% | > 1% |
|
||||||
|
|
||||||
|
### 2. 日志监控
|
||||||
|
|
||||||
|
观察是否有以下错误:
|
||||||
|
```bash
|
||||||
|
# 连接池耗尽
|
||||||
|
grep "Connection is not available" logs/app.log
|
||||||
|
|
||||||
|
# 线程池拒绝
|
||||||
|
grep "Task rejected" logs/app.log
|
||||||
|
|
||||||
|
# 超时错误
|
||||||
|
grep "timeout" logs/app.log
|
||||||
|
|
||||||
|
# 数据库锁等待
|
||||||
|
grep "Lock wait timeout" logs/app.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 业务指标监控
|
||||||
|
|
||||||
|
- 链接生成成功率
|
||||||
|
- 设备分配成功率
|
||||||
|
- 选区操作成功率
|
||||||
|
- 平均处理时间
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 常见问题处理
|
||||||
|
|
||||||
|
### 问题1: 启动失败 - 端口被占用
|
||||||
|
```bash
|
||||||
|
# 查找占用端口的进程
|
||||||
|
lsof -i :18080
|
||||||
|
netstat -tulpn | grep 18080
|
||||||
|
|
||||||
|
# 停止占用的进程
|
||||||
|
kill -9 <PID>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 问题2: 内存不足
|
||||||
|
```bash
|
||||||
|
# 检查可用内存
|
||||||
|
free -m
|
||||||
|
|
||||||
|
# 调整 JVM 参数
|
||||||
|
java -jar app.jar -Xms1g -Xmx2g # 降低内存配置
|
||||||
|
```
|
||||||
|
|
||||||
|
### 问题3: 数据库连接失败
|
||||||
|
```bash
|
||||||
|
# 测试数据库连接
|
||||||
|
mysql -h 192.140.164.137 -u login_task_db -p
|
||||||
|
|
||||||
|
# 检查防火墙
|
||||||
|
telnet 192.140.164.137 3306
|
||||||
|
```
|
||||||
|
|
||||||
|
### 问题4: 性能不如预期
|
||||||
|
|
||||||
|
**排查步骤**:
|
||||||
|
1. 检查 JVM GC 日志
|
||||||
|
2. 查看线程 dump
|
||||||
|
3. 检查数据库慢查询
|
||||||
|
4. 查看外部接口响应时间
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 导出线程 dump
|
||||||
|
curl http://localhost:18080/actuator/threaddump > threaddump.json
|
||||||
|
|
||||||
|
# 检查 GC 情况
|
||||||
|
jstat -gc <PID> 1000 10
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 回滚流程
|
||||||
|
|
||||||
|
如果遇到严重问题需要回滚:
|
||||||
|
|
||||||
|
### 1. 快速回滚
|
||||||
|
```bash
|
||||||
|
# 停止新服务
|
||||||
|
kill -TERM <PID>
|
||||||
|
|
||||||
|
# 启动备份版本
|
||||||
|
java -jar gameplatform-server-backup.jar > logs/app.log 2>&1 &
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 完整回滚
|
||||||
|
```bash
|
||||||
|
# 恢复代码
|
||||||
|
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
|
||||||
|
|
||||||
|
# 部署旧版本
|
||||||
|
# ... 按照部署步骤重新部署
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 性能对比记录
|
||||||
|
|
||||||
|
在部署后记录性能数据,用于对比:
|
||||||
|
|
||||||
|
### 优化前基准(记录日期:____)
|
||||||
|
- 并发处理能力: ___ req/s
|
||||||
|
- 平均响应时间: ___ ms
|
||||||
|
- P95 响应时间: ___ ms
|
||||||
|
- 错误率: ___%
|
||||||
|
|
||||||
|
### 优化后指标(记录日期:____)
|
||||||
|
- 并发处理能力: ___ req/s
|
||||||
|
- 平均响应时间: ___ ms
|
||||||
|
- P95 响应时间: ___ ms
|
||||||
|
- 错误率: ___%
|
||||||
|
|
||||||
|
### 提升幅度
|
||||||
|
- 并发能力提升: ___%
|
||||||
|
- 响应时间降低: ___%
|
||||||
|
- 错误率变化: ___%
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ 最终确认
|
||||||
|
|
||||||
|
部署完成后,确认以下各项:
|
||||||
|
|
||||||
|
- [ ] 服务正常启动
|
||||||
|
- [ ] 健康检查通过
|
||||||
|
- [ ] 关键接口功能正常
|
||||||
|
- [ ] 监控指标正常
|
||||||
|
- [ ] 日志无严重错误
|
||||||
|
- [ ] 压力测试通过
|
||||||
|
- [ ] 业务功能验证通过
|
||||||
|
- [ ] 已配置监控告警
|
||||||
|
- [ ] 已记录性能基准数据
|
||||||
|
- [ ] 已通知相关人员
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📞 联系方式
|
||||||
|
|
||||||
|
如遇到问题,请联系:
|
||||||
|
- 技术负责人: ___________
|
||||||
|
- 运维负责人: ___________
|
||||||
|
- 紧急联系电话: ___________
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**部署日期**: ___________
|
||||||
|
**部署人员**: ___________
|
||||||
|
**审核人员**: ___________
|
||||||
|
|
||||||
279
TIMEOUT_AND_BLOCKING_ISSUES_ANALYSIS.md
Normal file
279
TIMEOUT_AND_BLOCKING_ISSUES_ANALYSIS.md
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
# 超时和阻塞问题分析与解决方案
|
||||||
|
|
||||||
|
## 问题概述
|
||||||
|
|
||||||
|
经过全面检查,发现以下几个可能导致超时和阻塞的问题:
|
||||||
|
|
||||||
|
## 1. WebClient 连接池配置缺失 ⚠️ 高优先级
|
||||||
|
|
||||||
|
### 问题描述
|
||||||
|
`ScriptClient.java` 中的 WebClient 没有配置底层 HTTP 客户端的连接池参数,可能导致:
|
||||||
|
- 连接数耗尽,新请求被阻塞
|
||||||
|
- 连接泄漏
|
||||||
|
- 超时设置未生效
|
||||||
|
|
||||||
|
### 当前代码
|
||||||
|
```java
|
||||||
|
this.webClient = WebClient.builder()
|
||||||
|
.baseUrl(baseUrl)
|
||||||
|
.exchangeStrategies(ExchangeStrategies.builder()
|
||||||
|
.codecs(cfg -> cfg.defaultCodecs().maxInMemorySize(2 * 1024 * 1024))
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
```
|
||||||
|
|
||||||
|
### 解决方案
|
||||||
|
需要配置 Reactor Netty HttpClient:
|
||||||
|
```java
|
||||||
|
HttpClient httpClient = HttpClient.create()
|
||||||
|
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeoutMs)
|
||||||
|
.responseTimeout(Duration.ofMillis(readTimeoutMs))
|
||||||
|
.doOnConnected(conn ->
|
||||||
|
conn.addHandlerLast(new ReadTimeoutHandler(readTimeoutMs, TimeUnit.MILLISECONDS))
|
||||||
|
.addHandlerLast(new WriteTimeoutHandler(connectTimeoutMs, TimeUnit.MILLISECONDS)))
|
||||||
|
.wiretap(true); // 开启日志追踪
|
||||||
|
|
||||||
|
this.webClient = WebClient.builder()
|
||||||
|
.baseUrl(baseUrl)
|
||||||
|
.clientConnector(new ReactorClientHttpConnector(httpClient))
|
||||||
|
.exchangeStrategies(ExchangeStrategies.builder()
|
||||||
|
.codecs(cfg -> cfg.defaultCodecs().maxInMemorySize(2 * 1024 * 1024))
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Tomcat 线程池配置缺失 ⚠️ 高优先级
|
||||||
|
|
||||||
|
### 问题描述
|
||||||
|
Spring Boot 内嵌 Tomcat 使用默认线程池配置,可能不足以处理高并发场景。
|
||||||
|
|
||||||
|
### 解决方案
|
||||||
|
在 `application.yml` 中添加:
|
||||||
|
```yaml
|
||||||
|
server:
|
||||||
|
port: 18080
|
||||||
|
tomcat:
|
||||||
|
threads:
|
||||||
|
max: 200 # 最大工作线程数
|
||||||
|
min-spare: 20 # 最小空闲线程数
|
||||||
|
max-connections: 10000 # 最大连接数
|
||||||
|
accept-count: 100 # 队列长度
|
||||||
|
connection-timeout: 20000 # 连接超时(ms)
|
||||||
|
shutdown: graceful # 优雅关闭
|
||||||
|
|
||||||
|
spring:
|
||||||
|
lifecycle:
|
||||||
|
timeout-per-shutdown-phase: 30s # 关闭超时
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. WebFlux 配置优化 ⚠️ 中优先级
|
||||||
|
|
||||||
|
### 问题描述
|
||||||
|
如果项目使用了 WebFlux,需要配置 Reactor 线程池。
|
||||||
|
|
||||||
|
### 解决方案
|
||||||
|
在 `application.yml` 中添加:
|
||||||
|
```yaml
|
||||||
|
spring:
|
||||||
|
webflux:
|
||||||
|
# WebFlux 相关配置(如果使用)
|
||||||
|
base-path: /
|
||||||
|
reactor:
|
||||||
|
# Reactor 线程池配置
|
||||||
|
netty:
|
||||||
|
pool:
|
||||||
|
type: elastic # 使用弹性线程池
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 数据库连接池优化 ⚠️ 中优先级
|
||||||
|
|
||||||
|
### 当前配置
|
||||||
|
```yaml
|
||||||
|
hikari:
|
||||||
|
maximum-pool-size: 50
|
||||||
|
minimum-idle: 10
|
||||||
|
connection-timeout: 30000 # 30秒
|
||||||
|
idle-timeout: 600000 # 10分钟
|
||||||
|
max-lifetime: 1800000 # 30分钟
|
||||||
|
```
|
||||||
|
|
||||||
|
### 问题
|
||||||
|
- `connection-timeout` 设置为 30 秒过长,可能导致请求堆积
|
||||||
|
- MySQL 锁等待超时设置为 30 秒也偏长
|
||||||
|
|
||||||
|
### 建议优化
|
||||||
|
```yaml
|
||||||
|
hikari:
|
||||||
|
maximum-pool-size: 80 # 增加连接池大小
|
||||||
|
minimum-idle: 20 # 增加最小空闲连接
|
||||||
|
connection-timeout: 10000 # 降低到10秒
|
||||||
|
idle-timeout: 300000 # 5分钟
|
||||||
|
max-lifetime: 1800000 # 30分钟
|
||||||
|
leak-detection-threshold: 30000 # 30秒检测连接泄漏(从60秒降低)
|
||||||
|
validation-timeout: 3000 # 降低到3秒
|
||||||
|
```
|
||||||
|
|
||||||
|
同时优化 MySQL 会话参数:
|
||||||
|
```yaml
|
||||||
|
datasource:
|
||||||
|
url: jdbc:mysql://...?sessionVariables=innodb_lock_wait_timeout=10,wait_timeout=300,interactive_timeout=300
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. 异步线程池拒绝策略优化 ⚠️ 中优先级
|
||||||
|
|
||||||
|
### 当前配置
|
||||||
|
```java
|
||||||
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||||
|
```
|
||||||
|
|
||||||
|
### 问题
|
||||||
|
CallerRunsPolicy 会让调用线程(通常是 HTTP 线程)执行任务,可能导致 HTTP 线程池阻塞。
|
||||||
|
|
||||||
|
### 建议
|
||||||
|
根据业务需求选择:
|
||||||
|
|
||||||
|
**方案 A:丢弃策略(不重要的任务)**
|
||||||
|
```java
|
||||||
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
|
||||||
|
```
|
||||||
|
|
||||||
|
**方案 B:增加队列并监控(重要任务)**
|
||||||
|
```java
|
||||||
|
executor.setQueueCapacity(500); // 从100增加到500
|
||||||
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
|
||||||
|
// 添加拒绝处理监控
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 事务超时优化 ⚠️ 中优先级
|
||||||
|
|
||||||
|
### 问题
|
||||||
|
部分事务方法可能执行时间过长,持有数据库连接。
|
||||||
|
|
||||||
|
### 建议
|
||||||
|
1. 为不同类型的事务设置不同超时:
|
||||||
|
```java
|
||||||
|
@Transactional(timeout = 5) // 快速查询/更新
|
||||||
|
@Transactional(timeout = 15) // 批量操作
|
||||||
|
@Transactional(timeout = 30) // 复杂业务逻辑
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 避免在事务中调用外部 HTTP 接口:
|
||||||
|
```java
|
||||||
|
// ❌ 不好的做法
|
||||||
|
@Transactional
|
||||||
|
public Mono<Result> process() {
|
||||||
|
// 事务内调用外部 HTTP
|
||||||
|
return externalService.call().map(data -> {
|
||||||
|
repository.save(data); // 持有连接时间过长
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ 推荐做法
|
||||||
|
public Mono<Result> process() {
|
||||||
|
// 先调用外部接口
|
||||||
|
return externalService.call()
|
||||||
|
.flatMap(data -> {
|
||||||
|
// 再开启事务保存
|
||||||
|
return Mono.fromCallable(() -> saveInTransaction(data))
|
||||||
|
.subscribeOn(Schedulers.boundedElastic());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(timeout = 5)
|
||||||
|
private Result saveInTransaction(Data data) {
|
||||||
|
return repository.save(data);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. 添加请求超时和监控 ⚠️ 中优先级
|
||||||
|
|
||||||
|
### 建议配置
|
||||||
|
在 `application.yml` 中添加:
|
||||||
|
```yaml
|
||||||
|
spring:
|
||||||
|
mvc:
|
||||||
|
async:
|
||||||
|
request-timeout: 60000 # 60秒异步请求超时
|
||||||
|
|
||||||
|
management:
|
||||||
|
endpoints:
|
||||||
|
web:
|
||||||
|
exposure:
|
||||||
|
include: health,info,metrics,threaddump,heapdump
|
||||||
|
metrics:
|
||||||
|
enable:
|
||||||
|
tomcat: true
|
||||||
|
hikaricp: true
|
||||||
|
jvm: true
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. 日志优化建议
|
||||||
|
|
||||||
|
添加性能监控日志:
|
||||||
|
```yaml
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
reactor.netty: INFO # Reactor Netty 日志
|
||||||
|
io.netty: INFO # Netty 日志
|
||||||
|
com.zaxxer.hikari: INFO # HikariCP 日志
|
||||||
|
org.springframework.web.reactive: INFO # WebFlux 日志
|
||||||
|
```
|
||||||
|
|
||||||
|
## 实施优先级
|
||||||
|
|
||||||
|
### 立即实施(高优先级)
|
||||||
|
1. ✅ 配置 WebClient 连接池和超时
|
||||||
|
2. ✅ 配置 Tomcat 线程池
|
||||||
|
3. ✅ 优化数据库连接池参数
|
||||||
|
|
||||||
|
### 短期实施(中优先级)
|
||||||
|
4. 优化异步线程池拒绝策略
|
||||||
|
5. 检查并优化事务边界
|
||||||
|
6. 添加性能监控端点
|
||||||
|
|
||||||
|
### 长期优化
|
||||||
|
7. 添加分布式追踪(如 Sleuth + Zipkin)
|
||||||
|
8. 添加断路器(如 Resilience4j)
|
||||||
|
9. 考虑使用 Redis 缓存热点数据
|
||||||
|
|
||||||
|
## 监控建议
|
||||||
|
|
||||||
|
### 1. 添加健康检查
|
||||||
|
```java
|
||||||
|
@Component
|
||||||
|
public class CustomHealthIndicator implements HealthIndicator {
|
||||||
|
@Override
|
||||||
|
public Health health() {
|
||||||
|
// 检查数据库连接
|
||||||
|
// 检查外部服务
|
||||||
|
// 检查线程池状态
|
||||||
|
return Health.up().build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 添加性能指标
|
||||||
|
```java
|
||||||
|
@Timed(value = "api.calls", description = "API调用耗时")
|
||||||
|
public Mono<Result> apiMethod() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 监控关键指标
|
||||||
|
- HTTP 线程池使用率
|
||||||
|
- 数据库连接池使用率
|
||||||
|
- 异步线程池队列长度
|
||||||
|
- 外部接口响应时间
|
||||||
|
- 事务执行时间
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
主要问题集中在:
|
||||||
|
1. **HTTP 客户端配置不完整** - 导致连接管理问题
|
||||||
|
2. **服务器线程池未配置** - 默认值可能不适合生产环境
|
||||||
|
3. **数据库连接和事务管理** - 超时设置偏保守
|
||||||
|
4. **缺少监控和告警** - 难以及时发现问题
|
||||||
|
|
||||||
|
建议按优先级逐步实施优化措施。
|
||||||
|
|
||||||
@@ -22,25 +22,27 @@ public class AsyncConfig {
|
|||||||
/**
|
/**
|
||||||
* 设备检测专用线程池
|
* 设备检测专用线程池
|
||||||
* 避免阻塞HTTP请求处理线程
|
* 避免阻塞HTTP请求处理线程
|
||||||
|
* 优化配置以支持更高并发
|
||||||
*/
|
*/
|
||||||
@Bean(name = "deviceDetectionExecutor")
|
@Bean(name = "deviceDetectionExecutor")
|
||||||
public Executor deviceDetectionExecutor() {
|
public Executor deviceDetectionExecutor() {
|
||||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||||
|
|
||||||
// 核心线程数:根据设备数量调整,建议2-4个
|
// 核心线程数:增加以处理更多并发任务
|
||||||
executor.setCorePoolSize(3);
|
executor.setCorePoolSize(10);
|
||||||
|
|
||||||
// 最大线程数:高峰时可扩展
|
// 最大线程数:高峰时可扩展到更多
|
||||||
executor.setMaxPoolSize(10);
|
executor.setMaxPoolSize(50);
|
||||||
|
|
||||||
// 队列容量:允许排队的任务数
|
// 队列容量:增加队列以缓冲更多任务
|
||||||
executor.setQueueCapacity(100);
|
executor.setQueueCapacity(500);
|
||||||
|
|
||||||
// 线程名称前缀,方便日志追踪
|
// 线程名称前缀,方便日志追踪
|
||||||
executor.setThreadNamePrefix("DeviceDetect-");
|
executor.setThreadNamePrefix("DeviceDetect-");
|
||||||
|
|
||||||
// 拒绝策略:队列满时由调用线程执行,确保任务不丢失
|
// 拒绝策略:使用丢弃最旧策略,避免阻塞HTTP线程
|
||||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
// 注意:如果任务很重要,建议使用 AbortPolicy 并添加监控告警
|
||||||
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
|
||||||
|
|
||||||
// 线程空闲时间(秒)
|
// 线程空闲时间(秒)
|
||||||
executor.setKeepAliveSeconds(60);
|
executor.setKeepAliveSeconds(60);
|
||||||
@@ -56,7 +58,50 @@ public class AsyncConfig {
|
|||||||
|
|
||||||
executor.initialize();
|
executor.initialize();
|
||||||
|
|
||||||
log.info("设备检测线程池已初始化: coreSize={}, maxSize={}, queueCapacity={}",
|
log.info("设备检测线程池已初始化: coreSize={}, maxSize={}, queueCapacity={}, rejectedPolicy=DiscardOldest",
|
||||||
|
executor.getCorePoolSize(), executor.getMaxPoolSize(), executor.getQueueCapacity());
|
||||||
|
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用异步任务线程池
|
||||||
|
* 用于其他异步操作
|
||||||
|
*/
|
||||||
|
@Bean(name = "taskExecutor")
|
||||||
|
public Executor taskExecutor() {
|
||||||
|
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||||
|
|
||||||
|
// 核心线程数
|
||||||
|
executor.setCorePoolSize(20);
|
||||||
|
|
||||||
|
// 最大线程数
|
||||||
|
executor.setMaxPoolSize(100);
|
||||||
|
|
||||||
|
// 队列容量
|
||||||
|
executor.setQueueCapacity(1000);
|
||||||
|
|
||||||
|
// 线程名称前缀
|
||||||
|
executor.setThreadNamePrefix("AsyncTask-");
|
||||||
|
|
||||||
|
// 拒绝策略
|
||||||
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||||
|
|
||||||
|
// 线程空闲时间
|
||||||
|
executor.setKeepAliveSeconds(60);
|
||||||
|
|
||||||
|
// 允许核心线程超时
|
||||||
|
executor.setAllowCoreThreadTimeOut(true);
|
||||||
|
|
||||||
|
// 等待任务完成后再关闭
|
||||||
|
executor.setWaitForTasksToCompleteOnShutdown(true);
|
||||||
|
|
||||||
|
// 关闭等待时间
|
||||||
|
executor.setAwaitTerminationSeconds(60);
|
||||||
|
|
||||||
|
executor.initialize();
|
||||||
|
|
||||||
|
log.info("通用异步任务线程池已初始化: coreSize={}, maxSize={}, queueCapacity={}",
|
||||||
executor.getCorePoolSize(), executor.getMaxPoolSize(), executor.getQueueCapacity());
|
executor.getCorePoolSize(), executor.getMaxPoolSize(), executor.getQueueCapacity());
|
||||||
|
|
||||||
return executor;
|
return executor;
|
||||||
|
|||||||
@@ -5,19 +5,26 @@ import com.gameplatform.server.model.dto.device.DeviceStatusResponse;
|
|||||||
import com.gameplatform.server.model.entity.log.ScriptOperationLog;
|
import com.gameplatform.server.model.entity.log.ScriptOperationLog;
|
||||||
import com.gameplatform.server.service.device.DeviceStatusService;
|
import com.gameplatform.server.service.device.DeviceStatusService;
|
||||||
import com.gameplatform.server.service.log.ScriptOperationLogService;
|
import com.gameplatform.server.service.log.ScriptOperationLogService;
|
||||||
|
import io.netty.channel.ChannelOption;
|
||||||
|
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||||
|
import io.netty.handler.timeout.WriteTimeoutHandler;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.reactive.function.client.ExchangeStrategies;
|
import org.springframework.web.reactive.function.client.ExchangeStrategies;
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
import reactor.netty.http.client.HttpClient;
|
||||||
|
import reactor.netty.resources.ConnectionProvider;
|
||||||
import reactor.util.retry.Retry;
|
import reactor.util.retry.Retry;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class ScriptClient {
|
public class ScriptClient {
|
||||||
@@ -47,17 +54,37 @@ public class ScriptClient {
|
|||||||
this.deviceStatusService = deviceStatusService;
|
this.deviceStatusService = deviceStatusService;
|
||||||
this.eventPublisher = eventPublisher;
|
this.eventPublisher = eventPublisher;
|
||||||
this.operationLogService = operationLogService;
|
this.operationLogService = operationLogService;
|
||||||
|
|
||||||
|
// 配置连接池 - 提高并发性能
|
||||||
|
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(readTimeoutMs, TimeUnit.MILLISECONDS))
|
||||||
|
.addHandlerLast(new WriteTimeoutHandler(connectTimeoutMs, TimeUnit.MILLISECONDS)))
|
||||||
|
.compress(true); // 启用压缩
|
||||||
|
|
||||||
this.webClient = WebClient.builder()
|
this.webClient = WebClient.builder()
|
||||||
.baseUrl(baseUrl)
|
.baseUrl(baseUrl)
|
||||||
|
.clientConnector(new ReactorClientHttpConnector(httpClient))
|
||||||
.exchangeStrategies(ExchangeStrategies.builder()
|
.exchangeStrategies(ExchangeStrategies.builder()
|
||||||
.codecs(cfg -> cfg.defaultCodecs().maxInMemorySize(2 * 1024 * 1024))
|
.codecs(cfg -> cfg.defaultCodecs().maxInMemorySize(2 * 1024 * 1024))
|
||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("ScriptClient initialized baseUrl={}, apiBaseUrl={}, connectTimeoutMs={}, readTimeoutMs={}",
|
log.info("ScriptClient 初始化完成: baseUrl={}, apiBaseUrl={}, 连接超时={}ms, 读取超时={}ms, 最大连接数=100",
|
||||||
this.baseUrl, this.apiBaseUrl, connectTimeoutMs, readTimeoutMs);
|
this.baseUrl, this.apiBaseUrl, connectTimeoutMs, readTimeoutMs);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public Mono<byte[]> getQrPng(String path) {
|
public Mono<byte[]> getQrPng(String path) {
|
||||||
// path example: /{codeNo}/二维码.png
|
// path example: /{codeNo}/二维码.png
|
||||||
|
|||||||
@@ -3,18 +3,18 @@ spring:
|
|||||||
name: gameplatform-server
|
name: gameplatform-server
|
||||||
|
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:mysql://192.140.164.137:3306/login_task_db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&sessionVariables=innodb_lock_wait_timeout=30
|
url: jdbc:mysql://192.140.164.137:3306/login_task_db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&sessionVariables=innodb_lock_wait_timeout=10,wait_timeout=300,interactive_timeout=300
|
||||||
username: login_task_db
|
username: login_task_db
|
||||||
password: 3MaXfeWJ4d6cGMrL
|
password: 3MaXfeWJ4d6cGMrL
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
hikari:
|
hikari:
|
||||||
maximum-pool-size: 50
|
maximum-pool-size: 100 # 增加最大连接数(从50到100)
|
||||||
minimum-idle: 10
|
minimum-idle: 20 # 增加最小空闲连接(从10到20)
|
||||||
connection-timeout: 30000
|
connection-timeout: 10000 # 降低连接获取超时(从30秒到10秒)
|
||||||
idle-timeout: 600000
|
idle-timeout: 300000 # 空闲连接超时5分钟(从10分钟降低)
|
||||||
max-lifetime: 1800000
|
max-lifetime: 1800000 # 连接最大存活30分钟
|
||||||
leak-detection-threshold: 60000
|
leak-detection-threshold: 30000 # 连接泄漏检测30秒(从60秒降低)
|
||||||
validation-timeout: 5000
|
validation-timeout: 3000 # 连接验证超时3秒(从5秒降低)
|
||||||
connection-test-query: SELECT 1
|
connection-test-query: SELECT 1
|
||||||
# 连接池健康监控和自动重连
|
# 连接池健康监控和自动重连
|
||||||
initialization-fail-timeout: 1
|
initialization-fail-timeout: 1
|
||||||
@@ -26,8 +26,12 @@ spring:
|
|||||||
poll:
|
poll:
|
||||||
size: 4
|
size: 4
|
||||||
transaction:
|
transaction:
|
||||||
default-timeout: 30
|
default-timeout: 15 # 降低默认事务超时(从30秒到15秒)
|
||||||
|
mvc:
|
||||||
|
async:
|
||||||
|
request-timeout: 60000 # 异步请求超时60秒
|
||||||
|
lifecycle:
|
||||||
|
timeout-per-shutdown-phase: 30s # 关闭超时30秒
|
||||||
mybatis-plus:
|
mybatis-plus:
|
||||||
mapper-locations: classpath:mapper/**/*.xml
|
mapper-locations: classpath:mapper/**/*.xml
|
||||||
type-aliases-package: com.gameplatform.server.model.entity
|
type-aliases-package: com.gameplatform.server.model.entity
|
||||||
@@ -43,12 +47,22 @@ mybatis-plus:
|
|||||||
|
|
||||||
server:
|
server:
|
||||||
port: 18080
|
port: 18080
|
||||||
|
# Tomcat 线程池配置 - 提高并发处理能力
|
||||||
|
tomcat:
|
||||||
|
threads:
|
||||||
|
max: 200 # 最大工作线程数(默认200)
|
||||||
|
min-spare: 20 # 最小空闲线程数(默认10)
|
||||||
|
max-connections: 10000 # 最大连接数(默认8192)
|
||||||
|
accept-count: 200 # 等待队列长度(默认100)
|
||||||
|
connection-timeout: 20000 # 连接超时20秒
|
||||||
|
shutdown: graceful # 优雅关闭
|
||||||
|
|
||||||
|
|
||||||
management:
|
management:
|
||||||
endpoints:
|
endpoints:
|
||||||
web:
|
web:
|
||||||
exposure:
|
exposure:
|
||||||
include: health,info
|
include: health,info,metrics,threaddump
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
|
|||||||
Reference in New Issue
Block a user