Files
game_server/TIMEOUT_AND_BLOCKING_ISSUES_ANALYSIS.md

280 lines
7.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 超时和阻塞问题分析与解决方案
## 问题概述
经过全面检查,发现以下几个可能导致超时和阻塞的问题:
## 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. **缺少监控和告警** - 难以及时发现问题
建议按优先级逐步实施优化措施。