HikariCP 连接池耗尽:全站接口超时的根因与解决

一个慢接口占着数据库连接不释放,连接池很快被耗尽,其他接口拿不到连接,全站跟着集体超时。本文通过一个「报表慢 SQL 拖垮全站」的真实案例,讲清楚连接池耗尽的根因(慢 SQL 霸占连接),给出 HikariCP 参数配置方法,以及「快速失败 > 无限等待」的应对思路。

一、问题案例

一个报表接口,SQL 写得糙,高峰期要跑 30 秒。平时调用不多,一直没当回事。

直到某天运营在高峰期批量导出报表,几十个请求同时打过来。几分钟后,全站所有接口集体超时——不光是报表,登录、下单、查订单全挂了。

看数据库:CPU 并不高,连接数却打满了。看应用日志,全是同一类报错:

HikariPool-1 - Connection is not available, request timed out after 30000ms

二、原理详解:连接是稀缺资源,慢 SQL 是元凶

数据库连接池里就那么多连接(HikariCP 默认 maximumPoolSize=10),一个连接同一时刻只能服务一个请求。慢 SQL 占着连接不释放,等于把公共资源霸占了:

慢 SQL(30秒)× 并发几十个 → 10 个连接全被占满
        ↓
其他接口排队等连接 → 等满 connectionTimeout → 集体超时

连接池打满只是表象,真正的病根是慢 SQL。 不治慢 SQL,光加大连接池,只是把问题往后拖——连接再多,慢 SQL 一多照样打满,还会把数据库压垮。

三、实战代码:治本 + 合理配置

第一步(治本):修慢 SQL。

给报表 SQL 加索引、拆分批、或者改成异步生成。慢 SQL 从 30 秒降到 1 秒以内,连接占用时间短了,池子自然周转得过来。

第二步:合理配置 HikariCP。

spring:
  datasource:
    hikari:
      maximum-pool-size: 20       # 最大连接数,按公式估,别拍脑袋
      connection-timeout: 5000    # 拿不到连接 5 秒就失败,别让请求干等 30 秒
      max-lifetime: 1800000       # 连接最大存活 30 分钟,防止被数据库端断开
  • maximum-pool-size:经验公式 连接数 ≈ (CPU 核数 × 2) + 磁盘数。2 核 4G 的机器,20 个左右就够;
  • connection-timeout:调小一点,拿不到连接快速失败,比排队 30 秒再超时好——至少不会拖垮其他接口;
  • max-lifetime:设成比数据库的连接超时短一点,避免连接被数据库断开后应用还在用。

四、延伸:快速失败 > 无限等待

连接池耗尽的应对思路,不是「把超时调大让请求继续等」,恰恰相反——让拿不到连接的请求快速失败,配合限流和降级:

  • 报表这种重接口,加限流(同时只允许几个请求);
  • 或者改异步(提交任务后立即返回,后台慢慢跑);
  • 前台接口拿不到连接就快速报错,别把全站都拖下水。

五、总结 + 避坑建议

  • 连接池打满,先查慢 SQL,那是病根,加连接数是治标。
  • 连接数按公式估:(核数×2)+磁盘数,别无脑调大。
  • connection-timeout 调小,拿不到连接快速失败,别让请求干等。
  • 重接口配限流或异步,别让它霸占连接池。

我是无羡(小剑),全栈偏后端的独立开发者。

作品集:无羡 · 独立开发者作品集

如果对你有帮助,欢迎点赞、收藏、关注。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐