云数据库高并发下连接池耗尽的排查与处理全流程
【摘要】 连接池耗尽是高并发场景最常见的数据库故障之一。本文从报错识别、会话定位、泄漏检测、参数调优到架构改造,梳理一套可复用的排查处理流程。
一、先确认现象与报错
连接池耗尽的报错形态很多,但本质都是「应用在池子里借不到连接」。典型的有:
- HikariCP:
Connection is not available, request timed out after 30000ms - Druid:
wait millis 60000, active 20, maxActive 20 - 自研池:
Timeout waiting for idle object
第一步要在数据库侧确认是「应用侧池子太小」还是「连接真的被占满」:MySQL 执行 show processlist,PostgreSQL 查 pg_stat_activity,看活跃会话数与会话状态。如果数据库侧连接数并不高,那大概率是应用侧的池参数或连接泄漏;如果数据库侧已经打满,就要先排查慢 SQL 与锁等待。
二、定位连接被谁占用
分三个方向同时查:
- 应用侧线程栈:在业务高峰期连续抓几次 jstack / thread dump,看阻塞在
getConnection的线程栈。如果阻塞点集中在某个业务方法,说明是这段代码占用连接过久。 - 开启泄漏检测:HikariCP 设置
leakDetectionThreshold=60000,Druid 开启removeAbandoned。触发时日志会直接打印「借了连接却没还」的调用栈,这是定位泄漏最快的方式。 - 检查长事务:未提交的事务、大事务,以及把耗时外部调用(发短信、调第三方 HTTP、文件上传)包在事务里,都会让连接被长时间占用。这一类问题在压测时往往不暴露,上线后才集中爆发。
三、参数层面怎么调
- 池大小不是越大越好。常用经验值
connections = core_count * 2 + effective_spindle_count,一般从 20~50 起步压测调整。更重要的是:所有应用实例的maxPoolSize之和必须明显小于数据库的max_connections,否则数据库反而先被压垮。 - maxLifetime 要略小于数据库侧的空闲连接上限,避免拿到已被服务端断开的连接产生大量重连。
- connectionTimeout 不宜过大,快速失败比长时间挂死更好,配合上游限流才有意义。
- 必须加监控:活跃连接数、等待线程数、获取连接耗时三个指标要能看出水位上涨趋势,HikariCP + Micrometer 即可做到。
四、代码与架构层面
- 消灭「借了不还」:连接统一通过 try-with-resources 或框架事务管理器获取与释放,禁止手写 raw JDBC 不关闭。
- 把慢操作移出事务:外部 HTTP 调用、消息发送、文件处理都不要包在
@Transactional里。 - 读多写少的查询走只读从库或缓存,减少主库连接占用。
- 写入高峰考虑批量化、消息削峰、读写分离,必要时分库分表。
五、以华为云 RDS for MySQL 为例
在控制台的「性能洞察」里,可以直接看到哪类 SQL 占用会话与 CPU 最多,定位效率比纯手工分析高很多。若连接数确实到了实例瓶颈,优先升配或启用数据库代理做读写分离,而不是单纯把应用连接池调大;短时突发则建议用弹性伸缩配合应用侧限流,保护数据库不被瞬时洪峰打挂。
小结
连接池耗尽不是「把池子调大」就能解决的问题。正确的顺序是:先分清是应用侧还是数据库侧 → 用泄漏检测和线程栈找到占用源 → 再调参数 → 最后才是架构改造。监控指标要在问题发生前就装好,否则故障现场一过就无从下手。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)