连接池满了加连接没用|一次连接泄漏的定位复盘

简介: 异步导出打满连接池,加连接无效。讲清池对象与会话的关系,先分清容量不足还是借了不还,用 Threads_connected/Threads_running 和 processlist 定位,覆盖异常分支、异步跨线程、ResultSet 未关三类高发点,给出 KILL 边界与 try-with-resources 根治。

大家好,我是数据库小学妹👋 我踩过的坑,你别再踩。

有回报表导出改了异步,接口秒回「任务已提交」。业务侧看着挺好,可连接池的告警开始响。我以为导出量大,先把它往上调了一截。加了还是满,业务量也没涨。

最想不通的是,很多连接挂在库里。状态是 Sleep,时间越来越长。业务说早就结束了,连接却没回来。后来才想明白,池子满不一定是池子小,也可能是有人借了没还。

先分清:不够用,还是不归还

连接池满,只有两种可能。一种是真不够用。并发上来,或者慢查询占着连接不放。这时连接都在跑,Threads_running 也高。另一种是借了不还。连接被拿走,代码没走到归还那一步。业务逻辑早结束了,连接还在池外漂着。这时 Threads_connected 高,Threads_running 却很低。

两种现象长得像,处置完全相反。不够用要扩容或优化 SQL。不归还,加多少池子都只是拖时间。

信号 不够用(容量/慢 SQL) 借了不还(泄漏)
Threads_connected 高 高
Threads_running 也高 低,大量 Sleep
连接空闲时间 短 越来越长
加连接池 有效 短暂缓解,很快又满
重启应用 会好,根因仍在 SQL 或流量 会好,但复发的时点没变

连接池里漏的到底是什么

这里得先掰开一个概念。连接池里的「连接」,和数据库里的「会话」,不是一回事。

应用 getConnection(),拿到的是池里的一个对象。它背后握着一条真实的数据库会话。用完 close(),对象被收回,会话留着复用。平时这两步是配对的。泄漏就卡在这一步。池对象被借走,close() 没执行。数据库那边一条会话一直开着,池这边这条也一直算「借出中」。两头都不释放。

所以加池子大小只是加了分母。泄漏还在,只是从五十条漏到一百条,满了的时间往后挪。这也解释了为什么重启管用。重启把进程里的池对象清空,数据库会话跟着断。可代码不改,过一阵又漏回来。

怎么确认是泄漏

先看两个数。

SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Threads_running';

前者是已建立连接数,后者是正在执行 SQL 的连接数。前者高、后者低,差值一大,基本就是泄漏。两个都高,先往慢查询和突发流量查。

接着看连接都挂在哪。

SELECT host, command, COUNT(*) AS cnt, MAX(time) AS max_idle
FROM information_schema.processlist
WHERE user = 'app_user'
GROUP BY host, command
ORDER BY cnt DESC;

command 是 Sleep 或 Query,time 是连接在当前状态的秒数。Sleep 的 time 是空闲了多久,Query 的 time 是这条 SQL 跑了多久。两个语义别混,一个是占着不用,一个是正在用。

光看状态还不够,得看那会话到底在干什么。

SELECT t.processlist_id, t.processlist_host, t.processlist_command,
       t.processlist_time, e.sql_text
FROM performance_schema.threads t
LEFT JOIN performance_schema.events_statements_current e
  ON e.thread_id = t.thread_id
WHERE t.processlist_user = 'app_user'
ORDER BY t.processlist_time DESC
LIMIT 20;

Sleep 的连接,这里能看到它最后一条 SQL。往往就是泄漏前借它的那次操作,直接指向问题代码。

有长事务挂着,连接也回不去。

SELECT trx_id, trx_state, trx_started, trx_mysql_thread_id, trx_query
FROM information_schema.innodb_trx
ORDER BY trx_started ASC;

trx_state 是 RUNNING,trx_query 是空,trx_started 又很早,说明事务开了没提交,连接被它锁着。这种不算严格意义的泄漏,但表现一样,连接回不去。

国产数据库里面,金仓KES也有对应的视图。sys_stat_activity里能看到每个会话的状态、空闲时长和最后执行的SQL,用法和processlist类似。如果手上有KES Studio或KEMCC,还能直接下钻到会话级别看连接到底卡在哪一步,不用自己拼多个系统表。

三个高发点

第一类,异常分支没归还。最常见。

// 错误:异常抛出时,conn 不会关
Connection conn = dataSource.getConnection();
try {
   
    PreparedStatement ps = conn.prepareStatement(sql);
    ps.executeQuery();
} catch (SQLException e) {
   
    log.error("query failed", e);
    throw new BizException(e);
}
// finally 没写,异常路径更没有

正常路径忘了关,异常路径更不会关。一次两次看不出来,累积起来就是泄漏。

第二类,连接被交给异步线程。这正是我踩的那个。

// 错误:连接借给异步线程,请求已返回,连接还占着
public void export(Long id) {
   
    Connection conn = dataSource.getConnection();
    CompletableFuture.runAsync(() -> {
   
        // 长时间查数据、写文件
        // 从头到尾没 close
    });
    // 接口秒回,业务「结束」了
}

接口返回了,业务看着结束了。可异步线程还攥着连接。一个导出任务占一条,跑得越久占得越死。

第三类,ResultSet 或游标没关。很多人记得关连接,忘了关结果集。

// 错误:ResultSet 没关,等于连接一直被占
ResultSet rs = ps.executeQuery();
while (rs.next()) {
    ... }
rs = null;  // 置空不等于关闭

流式查询尤其危险。结果集没读完或没关,连接就一直被占着。ORM 里的懒加载、游标,本质也是这一类。

止血和根治

止血先看能不能扛到低峰。能扛就等低峰重启。扛不住,再考虑在库里处理。

处理前先分清两条命令。KILL QUERY id 只终止这条连接正在跑的语句,连接还在。KILL CONNECTION id 才把整个会话断掉。

-- 先查,再决定杀谁
SELECT id, user, host, command, time, info
FROM information_schema.processlist
WHERE command = 'Sleep' AND time > 3600;

kill 之前一定先确认来源。还有个点容易忽略。你把数据库会话杀了,应用池那边还以为连接是好的。下次拿出来用,可能直接报 Communications link failure。所以真要杀,杀完最好配合应用重启或连接验证,别让池子继续发死连接。

根治在代码。连接的借和还,必须成对。

// 正确:try-with-resources,异常也会归还
try (Connection conn = dataSource.getConnection();
     PreparedStatement ps = conn.prepareStatement(sql);
     ResultSet rs = ps.executeQuery()) {
   
    while (rs.next()) {
    ... }
} catch (SQLException e) {
   
    log.error("query failed", e);
    throw new BizException(e);
}

异步任务里也一样。连接要么在任务内部借、内部还,要么别跨线程传。别让一个连接活过它该活的作用域。

再配一个泄漏探针。HikariCP 的 leak-detection-threshold,连接被借走超时没还,就打警告带调用栈。

spring.datasource.hikari:
  leak-detection-threshold: 60000  # 60 秒未归还就打日志

它只报警,不帮你关。阈值设成业务正常最长用时的两三倍,太长没意义,太短全是误报。生产上开着,成本很低。

这里有个常被误解的点。maxLifetime 不是给泄漏兜底的。它主要回收池里空闲的连接。一条被借走一直没还的连接,它管不着。所以别指望配个 maxLifetime 就能治泄漏。

加连接之前,先问一句

池子满了,第一反应是加参数。这条我踩过。加连接能把故障往后拖,但拖不掉根。

判断顺序其实很简单。先看 Threads_running,高就往慢 SQL 查;低就往泄漏查。低的时候再加池子,只是把泄漏藏得更深。下一次来得更晚,也更猛。

监控也提前定好。盯四个数:活跃连接、空闲连接、等待线程、获取超时次数。空闲长期是 0,等待开始出现,超时计数抬头,就是池子在喊救命。

连接池不是容量越大越安全。它是一笔账,借出去的每一条都得记着还。漏掉的那条,不会自己回来。

避坑清单

池子满了,别急着加连接。先分清是不够用,还是借了不还。前者扩容,后者改代码,方向反了白忙。

连接一定要在借它的那个作用域里还。别跨线程传,别塞进异步任务,别指望 GC 帮你关。ResultSet 和游标也一样。

最后一条是我自己踩的。我以前觉得连接池满就是容量问题,加参数最省事。直到一次异步导出把连接耗光,才发现池子开多大,都填不满一个看不见的无底洞。现在我看连接告警,先看 Threads_running,再看来源 IP,最后才动参数。这一步多花十分钟,少一晚救火。

写在最后

连接泄漏最难的地方,是它不喊疼。业务照常返回,接口照常 200。坏的地方在池子深处,一条一条地漏。等灯亮起来,往往已经漏了很久。

参数能调,代码得改。连接池满这件事,池子大小只是表象,借还成对才是根。你把它当成一笔账来管,它才不会在某天晚上,突然把账翻给你看。

你们的连接池监控了哪些指标?有没有被连接泄漏坑过?评论区聊聊。

我是数据库小学妹,帮你少走弯路少踩坑,咱们下篇见👋

相关文章
|
8天前
|
云安全 人工智能 运维
当攻击全面Agent化,你的安全防御能否跟上AI Speed?
多起客户侧AK泄露事件应急的真实观察
1320 6
|
6天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
1128 21
|
2天前
|
存储 人工智能 自然语言处理
阿里云千问办公官网登录入口:qwenwork.cn网页版免下载,注册送2000积分、登录每日再送100积分
千问办公(QwenWork)是阿里巴巴推出的一站式AI办公平台,定位"不止于对话,更注重交付"。它基于千问大模型,具备任务拆解与多步骤自动执行能力,用户一句话即可完成PPT生成、数据分析、网页搭建、视频剪辑、信息调研等复杂任务,覆盖网页端、桌面端及钉钉生态。网页版免下载,访问qwenwork.cn注册即得2000积分,每日登录再送100积分。个人版免费起用,另有付费版与企业版可选。
|
11天前
|
存储 人工智能 安全
千问办公官网入口网页版登录:qwenwork.cn 注册送2000积分、登录送100积分
阿里云千问办公(QwenWork)是AI智能工作平台,支持一句话生成PPT、表格、网页、视频及数据分析。个人免费版送2000积分+每日登录赠100分,含1GB存储、5个发布页;企业版198元/席/月起。阿里千问办公QwenWork官网:https://t.aliyun.com/U/0VCTGt 阿里AI工作平台,一句话完成数据分析、PPT 生成、视频剪辑、网页搭建等复杂任务
|
6天前
|
人工智能 开发者
Qoder CN 大使计划正式开启|无限创造,等你一起
全年免费积分、优先内测、活动支持与更多共创机会,邀请用 Qoder 把想法变成现实的你。
567 6
|
1月前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
10037 33
|
7天前
|
安全 Linux 芯片
【万字长文】Ollama下载、安装、配置、使用保姆级教程(2026最新图解)
Ollama 是一款免费开源的本地大模型运行工具,支持 DeepSeek、Qwen 等主流模型,一条命令即可下载运行。2026 最新版 v0.35.1 官方安装包(1.47GB)已提供国内直连下载,纯本地、离线可用、无广告、无隐私泄露风险。
685 1
|
17天前
|
存储 人工智能 并行计算
大模型本地部署终端选型方法论:以 Qwen3.8-27B 为例的四档分层完整流程
本文提出一套大模型本地部署终端选型方法论:定约束、定档位、定框架、定参数四步决策法,配合入门、主力、质量、无损四档分层模型。以 Qwen3.8-27B 实测数据为例,逐环节解读显存、带宽、存储、散热、系统、预算等要素,给出面向不同预算的优选方案、决策自查清单与市场观察框架。文末前瞻 AI 笔记本的 CPU+GPU 与统一内存两条路线,论证四步决策法在新品类上的延续性。
|
8天前
|
Web App开发 人工智能 JavaScript
太猛了,一个月干到15W+,给大家推荐一个最近爆火的开源逆向工具:REA
REA(Reverse Engineer Anything)是近期爆火的开源AI逆向工具,4月发布,1个月内斩获15万+ Star。它让AI Agent无需源码即可分析二进制、APK、JS/Electron、HAR包等17类目标,自动反编译、生成可运行代码,并强制返回带证据与局限的结论。全本地执行,MIT协议,支持Hopper/Ghidra/IDA等引擎,一行命令即可上手。
794 2
太猛了,一个月干到15W+,给大家推荐一个最近爆火的开源逆向工具:REA

热门文章

最新文章