解决 线程池超时的问题。
This commit is contained in:
119
HikariCP连接池问题分析.md
Normal file
119
HikariCP连接池问题分析.md
Normal 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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user