feat: 优化异步线程池配置,增加设备检测和通用任务线程池的核心与最大线程数,提升并发处理能力;更新数据库连接池配置,增强连接管理和性能
This commit is contained in:
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. **缺少监控和告警** - 难以及时发现问题
|
||||
|
||||
建议按优先级逐步实施优化措施。
|
||||
|
||||
Reference in New Issue
Block a user