Skip to content

线上数据库连接池爆满问题排查 ​

  • 标签:后端、线上问题排查

🏛 业务架构师 ​

数据库连接池爆满的典型表现是应用日志刷 Get connection timeout,接口批量超时。我的处理顺序是先止血保业务,再找根因。

第一步:快速止血(分钟级)

  • 看监控确认影响面,核心交易不可用就是 P1,先考虑回滚最近变更(连接池参数改动、新上线的慢 SQL)
  • 临时适度调大连接池上限(要确认数据库侧 max_connections 有余量,两边要配平:所有应用实例的池上限之和 ≤ 数据库总连接数的 80%,剩下留给运维和紧急操作)

第二步:定位根因(四个方向按概率排查)

  1. 慢 SQL 占住连接不还(最常见):Druid 监控页看 active 连接正在执行的 SQL;SHOW PROCESSLIST 看堆积;典型根因是缺索引的全表扫描、大事务、行锁等待
  2. 连接泄漏:代码拿了连接没归还(异常路径没 close)、事务忘提交——表现是活跃连接只涨不跌,重启才释放
  3. 流量突增:连接池配置没跟上业务增长,QPS 曲线核对,是营销活动还是异常流量
  4. 下游变慢的连锁:Redis 挂了导致请求全落到 DB,DB 变慢 → 连接持有时间变长 → 池爆满,根因在别的组件

第三步:根治与预防

  • 慢 SQL 治理常态化(慢查询日志 + 工单流程)
  • 连接池参数规范化:maxWait 短一点快速失败,别让请求排队 30 秒还挂着
  • 配置连接池告警水位(使用率 80% 告警),别等爆了才知道
  • 压测验证池上限与业务峰值的匹配

业务视角:连接池是数据库的"最后一道闸门",它爆掉意味着所有依赖这个库的业务一起停摆。我主张每个核心库都要有容量红线文档:峰值 QPS、连接数、慢 SQL 基线,变更前对着检查。

🏗 系统架构师 ​

线上连接池爆满我处理过,标准排查路径是"现象 → 谁占着 → 为什么释放不掉"。

第一步:确认现象与占用者

  • 应用报 Connection is not available, request timed out after 30000ms(HikariCP 典型日志)
  • show processlist 看连接数是否真打满 max_connections,Sleep 连接多还是 Active 多——Sleep 多说明连接被借走没还(应用侧泄漏或池配置过大),Active 多说明 SQL 慢

第二步:定位连接卡在哪

  • dump 线程栈:jstack 看 BLOCKED/WAITING 线程是否卡在 getConnection,找到持有连接的线程在干什么(常见:慢 SQL、没关 ResultSet、事务里调外部接口)
  • 开 HikariCP 的 leakDetectionThreshold(如 60s),日志会打出泄漏堆栈,一抓一个准
  • MySQL 侧 performance_schema 查每个连接当前 SQL 与执行时长

第三大常见根因(按概率排):

  1. 慢 SQL / 大事务:事务里夹 RPC 调用,连接一占几秒,池瞬间被抽干——治理手段是事务瘦身,RPC 移出事务
  2. 连接池配置不合理:池 max 设得比 max_connections / 应用节点数 还大,多节点一起就把 DB 打满
  3. 忘关连接:手动 JDBC 没 try-with-resources
  4. 突发流量或重试风暴:上游超时重试放大并发

止血与预防:止血先摘流量、杀 Sleep 连接、必要时重启应用释放;预防上连接池参数按 节点数 × maxPool ≤ maxConnections × 0.8 反推,配合慢 SQL 监控与连接池水位告警(active/total 持续 > 90% 报警)。

💻 全栈开发专家 ​

连接池爆满,我按"现象 → 定位 → 根因"三步走。

第一步:确认在哪排队

  • HikariCP 日志出现 Connection is not available, request timed out after 30000ms。
  • 看指标:hikaricp.connections.active 打满 maximumPoolSize、connections.pending 堆积。
  • DB 侧 SHOW PROCESSLIST 看这批连接在执行什么,SHOW ENGINE INNODB STATUS 看锁等待。

第二步:找根因(常见四类)

  1. 慢 SQL 拖住连接:一条 SQL 3s,QPS 100 就能吃光 30 个连接。查慢查询日志,加索引。
  2. 连接泄漏:手动拿了 Connection/Statement 没 close,或事务方法里抛异常没回滚释放。开 Hikari 泄漏检测立刻现形:
yaml
spring.datasource.hikari.leak-detection-threshold: 60000

日志会打印持有连接未归还的堆栈,一看就知道是哪行代码。 3. 池配置过小:maximumPoolSize 挡不住峰值,压测数据说话。经验公式:core * 2 + spindisk数 只是起点,实际以 connections.pending 是否持续大于 0 为准。 4. 长事务 + 大事务:@Transactional 方法里调外部 HTTP/RPC,一个连接被占十几秒。查 information_schema.INNODB_TRX 的 trx_started,把远程调用挪出事务,这是我们最常见的事故根因。

止血与预防 临时扩 pool 只治标;根治靠慢 SQL 治理 + 事务瘦身 + 泄漏检测常开 + pending 指标告警。