登录
首页 >  数据库 >  MySQL

MySQL 连接数打满排查实战:从连接池到 PROCESSLIST 定位慢请求

来源:17golang原创

时间:2026-06-13 06:07:00 404浏览 收藏

线上 MySQL 连接数打满时,业务侧看到的通常是接口超时、偶发 500、连接池等待变长。很多人第一反应是把 max_connections 调大,但这只能暂时缓解,真正要找的是:谁把连接占住了,连接是在排队、慢查询、还是长事务里卡住。

本文用一次订单服务连接数告警做例子,按“看全局指标、看活跃连接、看事务、看应用连接池”的顺序排查。目标不是背命令,而是建立一条遇到问题能照着走的链路。

摘要

本文会完成四个目标:判断连接数是否真的到顶、用 PROCESSLIST 找出连接状态、定位长时间占用连接的事务或查询、给出连接池和限流兜底建议。适合正在维护 MySQL 业务库、管理后台和高并发接口的后端开发者阅读。

适合人群

  • 遇到过 “too many connections” 或连接池等待超时的开发者。
  • 需要把数据库告警和应用请求链路对应起来的后端同学。
  • 想把连接数问题从“调大参数”推进到“定位根因”的团队。

目录

  • 先确认连接数压力来自哪里
  • 用 PROCESSLIST 看连接状态
  • 排查长事务和慢请求占用
  • 应用连接池如何兜底
  • 上线后的观察项

先确认连接数压力来自哪里

连接数告警出现时,不要只看当前连接数,还要看活跃连接数。大量 Sleep 连接通常指向连接池配置或空闲连接回收问题;大量 QueryLockedSending data 则更可能是慢请求或锁等待。

SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Threads_running';
SHOW VARIABLES LIKE 'max_connections';

Threads_connected 表示当前已建立连接数量,Threads_running 更接近正在工作的连接数量。如果前者很高、后者不高,优先看连接池和空闲连接;如果两者都高,就要继续看正在跑的 SQL 和等待状态。

MySQL 连接数打满排查总览:应用连接池、活跃查询、长事务和数据库连接上限之间的压力传递关系

用 PROCESSLIST 看连接状态

下一步查看当前连接在做什么。生产环境里建议先筛选非空闲连接,避免被大量空闲连接淹没。

SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO
FROM information_schema.PROCESSLIST
WHERE COMMAND != 'Sleep'
ORDER BY TIME DESC
LIMIT 20;

重点观察三列:

  • COMMAND:连接是在查询、空闲、复制还是其他状态。
  • TIME:当前状态持续了多少秒,时间越长越值得看。
  • STATE:是否出现等待锁、发送数据、复制到临时表等状态。

如果排在前面的连接都来自同一个接口、同一台应用机器,说明问题很可能在某个入口流量或某段 SQL 上。如果来自多个服务,就要回到连接池配置和数据库总体负载一起看。

排查长事务和慢请求占用

连接数打满不一定是瞬时流量,也可能是长事务长期占着连接。尤其是接口里先开启事务,再调用外部服务、生成文件、发送消息,就会把数据库连接拖住。

SELECT trx_id,
       trx_started,
       trx_mysql_thread_id,
       TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS trx_seconds
FROM information_schema.innodb_trx
ORDER BY trx_started
LIMIT 10;

拿到 trx_mysql_thread_id 后,可以回到 PROCESSLIST 查对应连接。这样就能知道长事务来自哪个账号、哪个主机、当前在什么状态。

MySQL PROCESSLIST 诊断路径:筛选非空闲连接、按持续时间排序、关联长事务并定位到具体应用接口

把事务边界缩短

事务里只放必须保持一致的数据库读写,不要把远程接口、文件处理、复杂计算放在事务里。事务越短,连接被占用的时间越短,锁等待也更容易下降。

把慢查询拉回索引和条件

如果活跃连接主要卡在同一类查询上,就要继续看执行计划、索引和筛选条件。连接数问题经常只是表象,底层根因是某条 SQL 把连接拖得太久。

应用连接池如何兜底

数据库端要排查,应用端也要设置边界。连接池不是越大越好,如果每个服务实例都开很大的池,扩容应用时反而更容易把数据库连接打满。

  • 最大连接数按实例数折算。 例如数据库可用连接 800,应用 20 个实例,单实例连接池就不能随手配置 100。
  • 等待时间要有上限。 连接拿不到时快速失败或降级,避免请求堆积。
  • 空闲连接要回收。 低峰期保留太多空闲连接,会挤占其他服务空间。
  • 入口要有限流。 当连接池等待变长时,优先保护核心接口。

一个简单的估算方式是:

单实例最大连接数 = floor(数据库可用连接数 * 0.7 / 应用实例数)

这里的 0.7 是预留空间,给管理连接、任务脚本、其他服务和突发情况留余量。实际值还要结合请求耗时和并发量压测。

上线后的观察项

  • 连接池等待时间。 如果等待时间上升,说明应用侧已经感受到数据库压力。
  • Threads_connected 与 Threads_running。 前者看连接占用,后者看活跃压力。
  • 慢查询数量。 突增时要关联接口发布时间、流量入口和 SQL 模板。
  • 长事务数量。 持续超过几十秒的事务要重点关注。
  • 错误率和超时率。 数据库连接问题通常会先体现在接口延迟和错误率上。

常见坑

  • 只调大 max_connections。 连接变多会增加数据库压力,根因不解决会再次打满。
  • 忽略空闲连接。 大量空闲连接可能来自连接池最小连接数过大或回收策略不合理。
  • 事务里做慢操作。 事务边界太大,会同时放大连接占用和锁等待。
  • 没有按服务拆指标。 只看数据库总连接数,很难判断是哪一个应用实例在放大问题。

总结

MySQL 连接数打满时,正确路径是先看全局连接和活跃连接,再用 PROCESSLIST 找连接状态,接着关联长事务、慢请求和应用连接池配置。参数可以临时止血,但长期稳定要靠缩短连接占用时间、控制入口并发、让每个服务都有明确的连接预算。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>