生产环境排查 MySQL 数据库连接池耗尽(HikariCP Connection is not available)偶发超时实

举报
yd_260072176 发表于 2026/11/11 11:11:41 2026/11/11
【摘要】 一、生产故障表象与突发告警在某次核心业务高峰期,多台业务微服务节点同时触发高频错误告警:HikariPool-1 - Connection is not available, request timed out after 30000ms。与此同时,客户端大量用户请求出现转圈超时,HTTP 504 错误率飙升,业务链路呈现雪崩式阻塞。值班人员紧急检查数据库主机资源,发现 MySQL 实例 C...

一、生产故障表象与突发告警

在某次核心业务高峰期,多台业务微服务节点同时触发高频错误告警:HikariPool-1 - Connection is not available, request timed out after 30000ms。与此同时,客户端大量用户请求出现转圈超时,HTTP 504 错误率飙升,业务链路呈现雪崩式阻塞。

值班人员紧急检查数据库主机资源,发现 MySQL 实例 CPU 使用率仅 18%,内存利用率 42%,网络带宽与磁盘 I/O 均处于极低负载水位,并未发生数据库单机性能崩溃。然而应用端应用线程却全部卡死在获取数据库连接环节。

二、成因下钻与排障定位链路

1. 第一步:MySQL 端连接数与活动事务排查

首先通过 DBA 账号登录 MySQL 实例,核对当前活动连接状态:

mysql> SHOW GLOBAL STATUS LIKE 'Threads_connected';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_connected | 150   |
+-------------------+-------+
mysql> SHOW VARIABLES LIKE 'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 2000  |
+-----------------+-------+

数据表明 MySQL 实例最大连接数设定为 2000,当前实际连接仅 150,说明数据库底层并未发生全局连接溢出。问题聚焦于业务进程内部连接池分配耗尽。

2. 第二步:抓取应用 JStack 堆栈锁定阻塞线程

在告警的 Java 服务节点上快速导出线程快照:

$ jstack -l <PID> > /tmp/thread_dump.txt

分析堆栈文件,发现高达 80 多个工作线程处于 WAITING (parking) 状态,均停留在 HikariCP 的连接等待锁上:

"http-nio-8080-exec-42" #78 daemon prio=5 tid=0x00007f9c waiting on condition
  java.lang.Thread.State: WAITING (parking)
    at jdk.internal.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x0000000718b56000> (a java.util.concurrent.SynchronousQueue$TransferStack)
    at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:181)

3. 第三步:追踪长事务与锁占用(未提交事务陷阱)

查询当前挂起的 InnoDB 事务清单:

SELECT trx_id, trx_state, trx_started, 
       TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS duration_sec, 
       trx_query 
FROM information_schema.innodb_trx 
ORDER BY duration_sec DESC;

结果捕获到数个持续运行超过 120 秒的活跃事务,其 trx_query 为空(说明当前 SQL 已执行完毕,但代码未执行 commit 释放连接)。逆向审查对应业务代码发现:开发人员在 Spring 的 @Transactional 事务注解方法内部,嵌入了同步的外部第三方支付平台 HTTP 调用与下游消息队列同步发送逻辑。当第三方接口网络出现抖动延迟长达数十秒时,数据库连接被当前线程牢牢占用不释放,迅速挤占了 HikariCP 默认配置的全部最大连接(maximumPoolSize=10),导致后续所有快速查询被无辜卡死。

三、生产级配置调优与架构治理

1. 事务边界精细化隔离(严禁事务内混入 RPC/I/O)

重构业务逻辑,将远程 RPC/HTTP 调用与本地数据库事务彻底解耦,采用编程式事务(TransactionTemplate)精准控制事务边界:

// 错误写法:整个大方法加 @Transactional,内含远程 HTTP 调用
// 正确写法:缩小事务边界至仅包含数据库写操作
public void processOrder(OrderDTO dto) {
    // 1. 外部网络 I/O 不持有数据库连接
    PaymentResult result = paymentClient.callThirdParty(dto);
    
    // 2. 仅在纯数据库写阶段开启事务
    transactionTemplate.execute(status -> {
        orderRepository.updateStatus(dto.getId(), result.getStatus());
        orderHistoryRepository.insertLog(dto.getId(), "PAY_SUCCESS");
        return true;
    });
}

2. HikariCP 参数生产化加固与泄漏检测

针对高并发场景,精细化配置 HikariCP 核心参数,开启泄露监测并合理调配连接生命周期:

# HikariCP 生产环境核心配置
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.minimum-idle=10
# 连接最大等待时间(毫秒),避免线程永久阻塞
spring.datasource.hikari.connection-timeout=30000
# 连接最长存活周期(必须比 MySQL wait_timeout 小 2-3 分钟)
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.idle-timeout=600000
# 关键:开启连接泄露探测,超过 5 秒未归还打印 Warning 堆栈
spring.datasource.hikari.leak-detection-threshold=5000

配置 leak-detection-threshold=5000 后,一旦某处业务代码获取连接超过 5 秒未归还,HikariCP 将在应用日志中自动打印抓取该连接时的完整代码调用栈,为长事务定位提供毫秒级证据支持。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。