解决 线程池超时的问题。

This commit is contained in:
zhonghua1
2025-12-21 15:05:20 +08:00
parent 19a5c06a76
commit 00b149974b
2 changed files with 129 additions and 4 deletions

View File

@@ -0,0 +1,119 @@
# HikariCP 连接池警告问题分析
## 问题现象
```
WARN - HikariPool-Main - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@xxx (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
WARN - HikariPool-Main - Thread starvation or clock leap detected (housekeeper delta=47s225ms20µs300ns).
```
## 问题原因分析
### 1. **连接已被MySQL服务器关闭**
- MySQL服务器端的 `wait_timeout` 参数可能比 HikariCP 的 `maxLifetime` 短
- 或者由于网络问题、防火墙、负载均衡器等中间设备导致连接被关闭
- 但 HikariCP 连接池还不知道连接已经失效,仍然尝试使用这些已关闭的连接
### 2. **maxLifetime 设置不当**
- **原配置**:`maxLifetime: 1800000` (30分钟)
- **问题**:如果 MySQL 的 `wait_timeout` 设置为更短的时间(比如1小时或更短),连接会在服务器端被关闭,但连接池还在使用
- **最佳实践**:`maxLifetime` 应该设置为 MySQL `wait_timeout` 的 **70-80%**
### 3. **keepaliveTime 不够频繁**
- **原配置**:`keepaliveTime: 300000` (5分钟)
- **问题**:5分钟才检测一次连接是否有效,如果连接在检测间隔内被关闭,连接池无法及时发现
- **解决方案**:缩短到2-3分钟,更频繁地检测连接有效性
### 4. **JDBC URL 缺少连接参数**
- **原配置**:缺少 `socketTimeout`、`autoReconnect` 等参数
- **影响**:无法及时检测到连接超时,无法自动重连
### 5. **线程饥饿或时钟跳跃**
- 系统负载过高导致 housekeeper 线程无法及时执行
- 或者系统时钟发生跳跃(NTP同步、时区变更等)
## 解决方案
### 已实施的配置优化
1. **缩短 maxLifetime**
```yaml
maxLifetime: 900000 # 从30分钟缩短到15分钟
```
2. **缩短 keepaliveTime**
```yaml
keepaliveTime: 120000 # 从5分钟缩短到2分钟
```
3. **优化 JDBC URL**
```yaml
url: jdbc:mysql://...?socketTimeout=60000&connectTimeout=30000&autoReconnect=true&failOverReadOnly=false&maxReconnects=3&initialTimeout=2
```
### 建议的进一步检查
#### 1. 检查 MySQL wait_timeout 设置
连接到 MySQL 服务器,执行以下SQL查询:
```sql
SHOW VARIABLES LIKE 'wait_timeout';
SHOW VARIABLES LIKE 'interactive_timeout';
```
**建议**:
- 如果 `wait_timeout` 是 28800 秒(8小时,MySQL默认值),`maxLifetime` 可以设置为 4-6 小时
- 如果 `wait_timeout` 是 3600 秒(1小时),`maxLifetime` 应该设置为 45 分钟(2700000ms)
- 如果 `wait_timeout` 是 1800 秒(30分钟),`maxLifetime` 应该设置为 15 分钟(900000ms)
#### 2. 监控连接池状态
可以启用 HikariCP 的 JMX 监控来观察连接池状态:
```yaml
hikari:
registerMbeans: true # 启用JMX注册
```
然后通过 JConsole 或类似工具监控连接池。
#### 3. 检查系统资源
- 检查系统 CPU 和内存使用情况
- 检查是否有线程阻塞
- 检查系统时钟是否同步(NTP)
#### 4. 网络检查
- 检查应用服务器到数据库服务器的网络延迟
- 检查是否有防火墙或负载均衡器在中间
- 检查是否有网络中断或超时
## 配置参数说明
| 参数 | 原值 | 新值 | 说明 |
|------|------|------|------|
| `maxLifetime` | 1800000ms (30分钟) | 900000ms (15分钟) | 连接最大生存时间,应小于 MySQL wait_timeout 的 70-80% |
| `keepaliveTime` | 300000ms (5分钟) | 120000ms (2分钟) | 定期发送 keepalive 查询的间隔,用于检测连接是否有效 |
| JDBC URL | 缺少参数 | 添加 socketTimeout、autoReconnect 等 | 增强连接管理和自动重连能力 |
## 预期效果
实施这些优化后,应该能够:
1. ✅ 更早地检测到已关闭的连接
2. ✅ 避免使用无效连接导致的错误
3. ✅ 减少连接验证失败的警告
4. ✅ 提高连接池的稳定性和可靠性
## 注意事项
1. **maxLifetime 不能设置得太短**:如果设置得太短(比如5分钟),会导致连接频繁创建和销毁,影响性能
2. **keepaliveTime 不能设置得太频繁**:如果设置得太频繁(比如30秒),会增加数据库负载
3. **需要根据实际环境调整**:不同的 MySQL 配置和网络环境可能需要不同的参数值
## 参考文档
- [HikariCP 官方文档](https://github.com/brettwooldridge/HikariCP)
- [MySQL wait_timeout 说明](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_wait_timeout)

View File

@@ -68,7 +68,8 @@ spring:
database: 0 database: 0
datasource: datasource:
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://124.221.59.58:3309/ai_smart_badge?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai # 优化JDBC URL,添加连接参数以更好地处理连接超时和重连
url: jdbc:mysql://124.221.59.58:3309/ai_smart_badge?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&socketTimeout=60000&connectTimeout=30000&autoReconnect=true&failOverReadOnly=false&maxReconnects=3&initialTimeout=2
# url: jdbc:mysql://101.35.52.237:13307/ai_smart_badge?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&autoReconnect=true&failOverReadOnly=false&maxReconnects=3&initialTimeout=2&connectTimeout=30000&socketTimeout=60000 # url: jdbc:mysql://101.35.52.237:13307/ai_smart_badge?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&autoReconnect=true&failOverReadOnly=false&maxReconnects=3&initialTimeout=2&connectTimeout=30000&socketTimeout=60000
username: root username: root
# password: cstcom.123! # password: cstcom.123!
@@ -82,19 +83,24 @@ spring:
validationTimeout: 5000 # 连接验证的超时时间,5秒 validationTimeout: 5000 # 连接验证的超时时间,5秒
# 连接生命周期配置(毫秒) # 连接生命周期配置(毫秒)
idleTimeout: 300000 # 空闲连接超时时间,5分钟 idleTimeout: 300000 # 空闲连接超时时间,5分钟
maxLifetime: 1800000 # 连接最大生存时间,30分钟(建议小于MySQL wait_timeout) # maxLifetime设置为MySQL wait_timeout的75%(28800秒 * 0.75 = 21600秒 = 6小时)
# 当前MySQL wait_timeout=28800秒(8小时),设置为6小时(21600000ms)以确保连接在服务器关闭前被回收
# HikariCP官方建议maxLifetime应为数据库wait_timeout的70-80%,6小时(75%)是一个理想的平衡值
maxLifetime: 21600000 # 连接最大生存时间,6小时(wait_timeout=8小时的75%,确保小于服务器超时时间)
# 连接验证配置 # 连接验证配置
connectionTestQuery: "SELECT 1" connectionTestQuery: "SELECT 1"
# 连接泄漏检测(毫秒)- 如果连接超过此时间未归还,会记录警告 # 连接泄漏检测(毫秒)- 如果连接超过此时间未归还,会记录警告
leakDetectionThreshold: 60000 # 60秒 leakDetectionThreshold: 60000 # 60秒
# 保持连接活跃(毫秒)- 定期发送keepalive查询保持连接活跃 # 缩短keepaliveTime到2分钟,更频繁地检测连接是否有效,避免使用已关闭的连接
keepaliveTime: 300000 # 5分钟 keepaliveTime: 120000 # 2分钟,定期发送keepalive查询保持连接活跃
# 连接池名称(便于监控和调试) # 连接池名称(便于监控和调试)
poolName: HikariPool-Main poolName: HikariPool-Main
# 连接初始化配置 # 连接初始化配置
initializationFailTimeout: 1 # 初始化失败时立即失败,不等待 initializationFailTimeout: 1 # 初始化失败时立即失败,不等待
# 是否允许连接池自动提交 # 是否允许连接池自动提交
autoCommit: true autoCommit: true
# 连接注册JMX(可选,用于监控)
registerMbeans: false
output: output:
ansi: ansi:
enabled: always enabled: always