新闻详情

新闻详情

首页 / 资讯中心 / 详情

HikariCP连接池Connection timed out排查实战:从原理到参数调优

发布时间:2026/10/2 16:15:28来源:尧图网络
HikariCP连接池Connection timed out排查实战:从原理到参数调优
如果你的服务日志里突然刷出一整屏HikariPool-1 - Connection is not available, request timed out after 30000ms先别急着把连接池参数调大。我第一次遇到Hikari数据库连接池连接失败的时候第一反应就是把maximum-pool-size从20改成200结果问题不但没解决数据库负载反而被拖得更高最后整个服务直接雪崩。这篇文章会把那次完整的排查过程、HikariCP的工作机制、以及最终的参数调整方案全部讲清楚适合正在被连接池问题折磨的Java后端开发者也适合想系统搞懂连接池原理的Spring Boot使用者。1. 故障初现从告警到HikariPool日志刷屏1.1 线上第一现场长什么样那次事故发生在下午两点多先是监控告警群开始刷消息接口错误率超过5%P99延迟从正常的50毫秒左右飙到8秒。我登录服务器看了一眼应用日志发现核心报错几乎长这样java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30000ms at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:696) at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:207) ...这里有两个关键信息需要你先看懂。第一个是HikariPool-1这个编号代表当前应用里第几个HikariCP数据源实例如果你的项目配置了多个数据源就可能出现HikariPool-1、HikariPool-2这样的区分排查时要先确认报错的到底是哪个库不要拿着A库的连接配置去查B库的问题。第二个是request timed out after 30000ms这是HikariCP默认的connectionTimeout意思是应用线程在30秒内没有从连接池里拿到可用连接直接超时抛异常。从现象看这是典型的“拿不到连接”而不是“数据库连不上”。但如果只看这一行日志就下结论很容易误判。我见过不少同事遇到这个报错就认为是数据库宕机跑过去重启数据库结果重启完问题依旧因为根因根本不在数据库那一层。1.2 Hikari连接失败的常见报错形态连接池问题不是只有这一种表现排查前先对号入座能省很多时间。下面这几种是我实际踩过或者帮同事排查过的典型形态报错特征日志关键片段大概率方向获取连接超时Connection is not available, request timed out after 30000ms池内连接被借完且新连接创建跟不上初始化失败HikariPool-1 - Exception during pool initialization启动时数据库不可达、账号密码错误、驱动类缺失连接被拒绝Communications link failure/Connection refused网络不通、端口未监听、防火墙拦截连接被重置Connection reset/Broken pipe数据库重启、空闲连接被服务端断开、TCP超时连接泄漏提示Connection leak detected代码中连接未归还泄露超过leakDetectionThreshold这里面最迷惑人的是“连接被重置”这一类因为它的报错可能出现在任意一次SQL执行过程中看起来像是偶发网络问题实际上往往是连接池里的空闲连接已经被数据库或者中间代理断开了但池子还以为连接是好的下一次拿出去用的时候才发现坏了。1.3 影响范围一个连接池满半个服务跟着遭殃连接池满不只是“慢”这么简单它会沿着调用链传导最终把整个应用拖垮。打个比方连接池就像银行柜台假设只有10个窗口每个窗口办一笔业务要30分钟外面的客户只能排队干等。更糟的是等待取号的人越多后面新来的客户也进不来连银行大门都被堵死了。在技术上这个“大门”就是Tomcat之类的Web容器线程池。当所有工作线程都阻塞在getConnection()等待连接时新的HTTP请求没有线程可用于是接口大规模超时超时又引发调用方重试重试带来更多请求形成恶性循环。我这次遇到的场景就是这样最开始只是数据库连接不够十几次重试之后整个服务的线程池也被塞满了。所以遇到连接池问题第一步不是改代码而是先做“熔断式”止损比如临时把流量切走或者重启部分节点先把雪崩止住再回来冷静排查根因。2. 连接池原理解析先弄懂HikariCP再动手查2.1 HikariCP的工作机制HikariCP是当前Java生态里性能最好的数据库连接池之一Spring Boot 2.x之后默认使用它。它之所以快主要靠几个底层优化把字节码做得极精简、用FastList代替ArrayList、以及用SynchronousQueue作为连接handoff队列减少线程切换和锁竞争。从使用者的角度看它的工作流程其实不复杂连接池启动时根据minimumIdle参数预先创建一批空闲连接。业务线程调用getConnection()获取连接池子会优先分配空闲连接。如果没有空闲连接在connectionTimeout允许的时间窗口内尝试新创建连接。创建连接超时或失败抛SQLTransientConnectionException。连接使用完毕后由调用方归还到池中进入空闲状态。空闲连接超过idleTimeout或整体存活超过maxLifetime会被池子废弃并替换。这里有个非常核心的点HikariCP获取连接的路径上connectionTimeout、maximumPoolSize、minimumIdle这三个参数是联动的。如果你把maximumPoolSize设得很大但数据库端max_connections不够大连接池初始化阶段就会持续报错如果你把minimumIdle设得跟maximumPoolSize一样大应用一启动就会占满这么多连接多个服务实例叠加后数据库很难扛住。2.2 连接失败的本质三分类排查Hikari连接失败我习惯先把问题归成三类分类不同处理方式天差地别类型A创建新连接本身失败。表现为“初始化失败”或“首次获取连接就报错”原因往往是数据库IP/端口不通、账号密码错误、驱动类没加载、serverTimezone等连接参数配置错误。类型B连接池无法在超时时间内提供连接。表现为“request timed out”原因往往是池子里的连接被借完且验证了新建连接也不行数据库连接数打满或者数据库负载过高导致每次建连接都超过30秒。类型C已有连接被破坏。表现为“偶发连接重置”“通信链路异常”原因往往是MySQL的wait_timeout比HikariCP的maxLifetime短空闲连接被数据库主动断开或者防火墙/NAT设备把长期空闲的TCP连接回收了又或者是MySQL实例发生过重启所有旧连接全部失效。我这次的事故严格来说是类型B为主、类型C为次。很典型也很值得拆开细说。2.3 关键参数默认值以及最容易被忽略的坑HikariCP的参数网上能查到很多但真正跟连接失败强相关的就那几个我整理了一个速查表参数默认值含义和连接失败的关系maximumPoolSize10池中最大连接数设得超过数据库上限会直接失败minimumIdle等于maximumPoolSize最小空闲连接数设太大导致应用长期占用连接connectionTimeout30000ms获取连接的最大等待时间太小容易误报超时太大拖垮线程idleTimeout600000ms空闲连接存活时间仅当minimumIdle小于maximumPoolSize时生效maxLifetime1800000ms连接最大存活时间必须小于数据库的wait_timeoutvalidationTimeout5000ms连接有效性检测超时表达式验证失败时会导致借出坏连接leakDetectionThreshold0不开启连接泄漏检测阈值开启后可定位连接未归还的代码keepaliveTime0不开启空闲连接探活间隔开启后能减少被中间设备断开的情况最容易踩的坑是maxLifetime和数据库wait_timeout的关系。MySQL默认的wait_timeout是28800秒也就是8小时一般HikariCP默认的30分钟不会碰到它。但有些云数据库或者DBA会把wait_timeout改得很短比如3600秒甚至600秒。如果HikariCP的maxLifetime反而更长连接池里那些长期空闲的连接就会被MySQL主动关掉而HikariCP并不知道下次借出时执行SQL就直接报“Connection is not available”或者“Communications link failure”。这种问题用“重启大法”解决不了只能靠参数对齐。3. 实战排查我这次事故的完整定位过程3.1 第一站先看数据库侧状态而不是改应用参数那次看过应用日志后我没有马上动代码而是先登到数据库上看了几个关键状态。连接数打没打满是最快能确认的方向。SHOW GLOBAL STATUS LIKE Threads_connected; SHOW VARIABLES LIKE max_connections; SHOW PROCESSLIST;结果很扎眼Threads_connected已经到151而max_connections恰好是151连接数被打到上限。SHOW PROCESSLIST里一眼望去全是Sleep状态和少量长时间运行的查询。这里要提醒一句Sleep状态的连接都是空闲连接但空闲不代表无害——它们同样占用MySQL的线程和内存资源。接着用这条SQL看了连接来源分布SELECT host, user, db, command, COUNT(*) FROM information_schema.processlist GROUP BY host, user, db, command ORDER BY COUNT(*) DESC;结果发现同一个应用服务器IP下有大量连接而我们那个服务明明是集群部署、有好几个节点。综合判断下来基本可以确认数据库连接数被应用节点占满新的应用请求拿不到连接最终超时。3.2 第二站网络与端口层排除“连不上”和“连不上但要确认”虽然已经确认连接数打满我依然顺手做了网络层验证因为报错日志里如果出现Communications link failure网络问题是不能忽略的。当时我用了最原始也最有效的一套ping 数据库IP telnet 数据库IP 3306网络通、端口通排除网络故障。这步看起来简单但我特别建议每个排查连接失败的人都按这个顺序来。很多远程服务连接失败的问题本质上都可以拆成三层来看网络通不通、服务活没活、配置对不对。顺序错了最容易浪费时间。比如有人一看到连接报错就去改连接池结果数据库IP早就变了完全白忙。另外还要确认驱动的兼容性。项目用的是MySQL 8.0如果代码里还在用com.mysql.jdbc.Driver这种老驱动启动时就会报错MySQL 8之后驱动类名改成com.mysql.cj.jdbc.Driver而且还要显式配置serverTimezone否则报时区错误。3.3 第三站应用侧数据源配置问题逐渐浮出水面回到应用侧看配置问题就很清楚了。当时的配置长这样spring: datasource: hikari: maximum-pool-size: 50 minimum-idle: 50 connection-timeout: 30000注意这两个参数maximum-pool-size: 50minimum-idle: 50。这意味着每个应用节点启动后会一直保持50个空闲连接集群一共4个节点光是这个服务就固定占了200个连接。数据库max_connections总共才151这还没算其他服务、监控工具、运维后台等连接的占用怎么可能不爆。这里也暴露了一个很常见的认知误区很多人以为连接池越大越好觉得连接多吞吐高。实际上每个MySQL连接背后都是一个线程线程越多上下文切换越频繁数据库性能反而下降而且连接是共享资源多个服务之间必须通盘考虑。盲目调大连接池跟“堵车就多修路”一样短期看好像有道理最后会发现路修得再多也架不住同时涌进来的车流量因为真正的瓶颈可能在别处。3.4 第四站慢SQL和连接泄漏放大问题的帮凶连接数打满只是表象为什么连接会被占用那么久不释放我继续翻了PROCESSLIST发现有几条SQL的Time都超过了20秒看Info字段是一条没走索引的查询全表扫描了一张几百万行的表。每个这样的慢SQL都会把一个连接占住20多秒在高并发下几个慢SQL就能把连接池的可用连接全部耗尽。顺带还排查了连接泄漏的问题。HikariCP提供了一个很有用的参数leakDetectionThreshold如果业务代码里获取连接后没有归还超过这个阈值就会在日志中输出泄漏堆栈。当时我用下面这段临时配置验证了一下spring: datasource: hikari: leak-detection-threshold: 60000如果日志出现Connection leak detected加上一段堆栈基本就是代码中某个地方把Connection拿走后忘了关。这次的日志里没发现泄漏说明主要问题不在泄漏而是“慢SQL 连接池配置过大 数据库连接数上限小”三件事撞在一起。4. 解决方案参数调优、代码改造与监控兜底4.1 针对根因的参数调整定位清楚之后修复方案就比较直接了。我没有把连接池调大反而调小了。关键思路是先明确数据库能承受多少连接再反推每个应用节点该分配多少连接。首先数据库端把max_connections适当放宽但不能无脑放宽。它跟内存和CPU相关不能只改一个数字。我用的是下面的方式先在线调整再持久化到配置文件SET GLOBAL max_connections 300;然后在my.cnf里设置max_connections 300 wait_timeout 600 interactive_timeout 600这里把wait_timeout调成600秒的意思是空闲超过10分钟的连接数据库主动断开一定程度上能减少空闲连接长期占用的内存。但这样一来HikariCP的maxLifetime就必须小于600秒否则应用侧还持有已失效连接。我最终给应用设置的参数是下面这套spring: datasource: hikari: pool-name: BizDataSourceHikariPool minimum-idle: 5 maximum-pool-size: 20 idle-timeout: 300000 max-lifetime: 580000 connection-timeout: 30000 validation-timeout: 5000 leak-detection-threshold: 60000 keepalive-time: 30000解释一下关键项minimum-idle: 5意味着应用空闲时只保留5个连接maximum-pool-size: 20限制单节点最大连接数4个节点满打满算也就80个连接给数据库留足了余量。max-lifetime: 580000也就是580秒小于之前数据库设置的600秒wait_timeout从源头避免“连接被数据库先断开”的尴尬。keepalive-time: 30000让连接池每30秒对空闲连接做一次探活降低被网络设备回收的风险。4.2 代码侧同时治理慢SQL参数改好了慢SQL不处理连接迟早还是会被打满。那条全表扫描的SQL我通过EXPLAIN确认是索引缺失加了一个联合索引ALTER TABLE xxx ADD INDEX idx_user_create_time (user_id, create_time);加完之后那条查询从20多秒降到几十毫秒。这里也建议每个团队都开启MySQL慢查询日志把执行时间超过1秒的SQL都记录下来定期复盘。连接池本身是个“漏斗”真正能提升吞吐的是让每个连接的使用时间变短而不是单纯把漏斗加宽。4.3 监控、告警和容量规划事故处理完之后只改参数是不够的还得保证下次能提前发现。我做了下面这几件事第一接入连接池监控。Spring Boot Actuator结合Micrometer可以把HikariCP的指标暴露给Prometheus再在Grafana里配面板。重点看这几个指标hikaricp_connections_active、hikaricp_connections_pending、hikaricp_connections_idle、hikaricp_connection_timeout_total。其中pending大于0就说明有线程在等连接是个很准的前兆信号。第二配置告警。connection_timeout_total在5分钟内持续增长说明连接获取已经出现超时需要立刻看数据库连接数和慢SQL。连接池使用率超过80%也要告警别等到100%才响应。第三做容量规划。连接池大小不是拍脑袋定的而是要结合这几个因素数据库max_connections、应用节点数量、单节点QPS、单条SQL平均执行时间。我后来整理了一个简单的估算方法假设数据库能支持300个连接预留30%给运维和监控剩下210个分配给应用应用有4个节点每个节点连接池上限大概在50以内再结合压测结果逐步调整。原则上从一个小值开始压测找到拐点就停而不是一开始就给很大的值。4.4 参数不是万能药代码质量同样重要还有一类连接池问题纯粹靠参数救不回来那就是代码层面的连接管理问题。几个高频坑我得单独拎出来说用try-with-resources确保Connection、Statement、ResultSet全部正确关闭尤其是ResultSet很多人会漏。事务内不要做远程调用包括RPC、消息队列、外部HTTP请求。事务会一直持有数据库连接如果你在事务里调了外部接口等5秒这个连接就被白占5秒并发一高连接池瞬间就被“假占用”打满。尽量缩短事务边界把非必要的查询挪到事务外。我见过最夸张的一个案例一个方法上打了Transactional方法内部循环调用第三方接口每个接口等2秒循环10次一个事务把连接占住20秒。这种代码不管连接池调多大最终都会出问题。5. 常见问题速查从症状直接定位到方案5.1 高频连接失败问题对照表把这次的经验和以往排查过的案例放在一起整理了下表可以直接当作排查手册用症状直接原因标准处理路径应用启动就报HikariPool-1 Exception during pool initialization数据库不可达、账号密码错、驱动类不对先telnet IP端口再SHOW GRANTS最后检查URL和驱动名运行期大量request timed out after 30000ms连接池连接耗尽查Threads_connected和max_connections查慢SQL再调连接池偶发Connection reset/Communications link failure空闲连接被数据库/防火墙断开调maxLifetime小于wait_timeout开启keepaliveTime升级驱动连接池有连接但执行SQL就报错连接已被服务端失效检查MySQL是否重启过检查NAT超时时间必要时重启应用节点日志出现Connection leak detected代码获取连接后未归还开启leakDetectionThreshold用堆栈定位泄漏代码数据库连接数持续高位但不超时最小空闲连接数设得过大调低minimumIdle避免多个节点叠加占用5.2 我踩过的一些坑希望你绕开第一个坑一上来就调大maximumPoolSize。我刚开始排查Hikari问题时就犯过这个错不仅没解决反而让数据库更快触顶。正确顺序永远是先查数据库侧状态再回看应用配置。第二个坑只改连接池不盯慢SQL。连接池只是个通道真正让通道堵住的是长时间占用的连接。如果你看到连接数打满第一反应应该是去看PROCESSLIST里有没有长时间运行的SQL而不是只想着扩池子。第三个坑时间类参数没有联动。connectionTimeout、maxLifetime、idleTimeout、keepaliveTime这些参数要放在一起看单独调一个很容易顾此失彼。比如只把maxLifetime调得很短连接重建变频繁数据库压力反而更大。第四个坑不关注HikariCP自身日志。应用日志里HikariCP会周期性打印pool stats里面包含total、active、idle、waiting等数据。默认是INFO级别很多人没注意。下次再出问题先翻这一段可以直观看到连接池当时的状态。写在最后那次事故处理完之后我给自己定了一条排查规矩遇到数据库连接池相关的问题永远先回答三个问题——数据库当前连接数是多少、谁占用了连接、连接被占用是因为慢SQL还是配置不合理。顺序对了问题往往能在一刻钟内定位顺序反了可能会在错误的方向上折腾一整天。后来接手的新服务上线前我也会强制检查一遍数据源配置数据库端max_connections是多少应用节点有几个连接池参数是不是跟数据库上限匹配maxLifetime有没有小于数据库wait_timeout。这套检查清单比任何事后救火都管用。HikariCP本身是个非常好用的连接池但连接是整条链路里最容易被忽略的共享资源——它不是越多越好而是刚好够用最好。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

VS Code 配置 Fortran 开发环境全指南 2026/10/2 18:34:51

VS Code 配置 Fortran 开发环境全指南

简介:本资源是面向科学计算学习者与编程竞赛选手(如VNOI参赛者)的FortranVSCode开发环境实战包,解决在现代编辑器中高效编写、调试Fortran程序的核心需求。压缩包共99个文件,总计20.6MB,包含9个Fortran源码…

阅读更多 →
Java变量全解析:静态变量、实例变量与局部变量的区别与实战 2026/10/2 18:34:51

Java变量全解析:静态变量、实例变量与局部变量的区别与实战

先问一个直击灵魂的问题:你写的变量,到底住在哪、活多久、谁能碰?很多同学学Java第一周就接触“成员变量”“局部变量”“静态变量”这些词,结果写了两年代码,被面试官一句“static修饰的变量存在哪”问蒙圈。这篇文章…

阅读更多 →
CatBoost在电力短期负荷预测中的应用与特征工程实践 2026/10/2 18:34:51

CatBoost在电力短期负荷预测中的应用与特征工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
从零手搓AI工程栈:分层架构、多Provider适配与缓存降级实战 2026/10/2 18:34:44

从零手搓AI工程栈:分层架构、多Provider适配与缓存降级实战

1. 为什么我要从零手搓一套AI工程栈第一次看到ai-engineering-from-scratch这个标题,我脑子里蹦出来的不是“又一个教程仓库”,而是过去两年带团队踩过的那些坑。市面上讲AI的课程和文章多如牛毛,但绝大多数要么停留在调包层面——import ope…

阅读更多 →
农产品销售平台|基于java+ vue农产品销售平台(源码+数据库+文档) 2026/10/2 18:34:38

农产品销售平台|基于java+ vue农产品销售平台(源码+数据库+文档)

农产品销售平台 目录 基于springboot vue农产品销售平台 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取: 基于springboot vue农产品销售平台 一、前言 博主介绍&#x…

阅读更多 →
OpenCV+YOLOv5实时车位识别系统(CPU可跑) 2026/10/2 18:34:32

OpenCV+YOLOv5实时车位识别系统(CPU可跑)

简介:本资源是一个基于Python开发的智能停车场管理系统完整项目,面向计算机专业本科生、人工智能方向课程设计与毕业设计学习者,聚焦车牌识别、车位检测、智能计费与数据管理等典型AI落地场景。项目采用深度学习与计算机视觉技术,…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉