解决 线程池超时的问题。

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
datasource:
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
username: root
# password: cstcom.123!
@@ -82,19 +83,24 @@ spring:
validationTimeout: 5000 # 连接验证的超时时间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"
# 连接泄漏检测(毫秒)- 如果连接超过此时间未归还,会记录警告
leakDetectionThreshold: 60000 # 60秒
# 保持连接活跃(毫秒)- 定期发送keepalive查询保持连接活跃
keepaliveTime: 300000 # 5分钟
# 缩短keepaliveTime到2分钟更频繁地检测连接是否有效避免使用已关闭的连接
keepaliveTime: 120000 # 2分钟定期发送keepalive查询保持连接活跃
# 连接池名称(便于监控和调试)
poolName: HikariPool-Main
# 连接初始化配置
initializationFailTimeout: 1 # 初始化失败时立即失败,不等待
# 是否允许连接池自动提交
autoCommit: true
# 连接注册JMX可选用于监控
registerMbeans: false
output:
ansi:
enabled: always