华为云 RDS for MySQL 报 Too many connections:连接数打满的定位与处理清单
华为云 RDS for MySQL 报 Too many connections:连接数打满的定位与处理清单
应用突然报 ERROR 1040 (HY000): Too many connections,新请求全部连不上库,这是 RDS for MySQL 上很常见的一类故障。很多人第一反应是把 max_connections 调大,但连接数打满往往只是表象,背后多半是连接泄漏、空闲连接堆积、慢 SQL 或连接风暴。这篇按「先止血、再定位、后预防」的顺序整理一份排查清单。
一、先确认是不是真的打满了
在还能连上的会话里(或者用控制台的工具)执行:
show status like 'Threads_connected';
show global variables like 'max_connections';
Threads_connected 接近或等于 max_connections,就可以确认是连接数打满。
控制台侧可以在实例的「智能DBA助手 > 实时性能」里看「当前活跃连接数」和「数据库总连接数」,切到历史趋势能看出是缓慢爬升还是瞬间飙升,两种情况的原因方向完全不同。
二、先止血:释放问题连接
- 进入实例的「智能DBA助手 > 实时会话」,按 Command 列筛出
Sleep状态的会话,结合 Time 列找长时间空闲的连接;也可以按客户端 IP 统计,看是哪台应用机器占得最多。 - 选中空闲连接或问题会话,用「Kill会话」释放(支持批量)。
- 如果是某条高频 SQL 把连接拖住,可以在「智能DBA助手 > SQL分析与优化」里用「SQL限流」临时限制它的并发。
也可以用 SQL 先看一眼空闲超过 60 秒的连接:
select id, user, host, db, command, time, state
from information_schema.processlist
where command = 'Sleep' and time > 60
order by time desc;
注意:Kill 只是止血,不找到根因的话,连接很快又会涨回来。
三、按曲线形态定位原因
1. 缓慢上涨到上限
常见原因:
- 连接泄漏:代码里拿了连接没归还(异常分支没 close、事务没结束)。按客户端 IP 统计,泄漏的那台机器连接数通常只涨不降。
- 空闲连接堆积:
wait_timeout/interactive_timeout默认 28800 秒(8 小时),应用侧连接池又没配空闲回收,Sleep 连接越积越多。 - 长事务未提交:会话一直挂着事务,连接被占住。可以查
information_schema.innodb_trx里trx_started很早的事务。
2. 瞬间飙升
常见原因:
- 连接风暴:应用集中启动时每个实例都初始化一大批连接;流量突增导致连接池快速扩容;连接池 maxTotal / maximumPoolSize 配置之和超过了实例上限;异常重试逻辑没有退避,失败后疯狂重连。
- 数据库变慢导致排队:慢 SQL、锁等待、IO 瓶颈让每个请求占用连接的时间变长,连接数被动堆高。这时要去看慢 SQL 分析、锁与事务、IO 监控,而不是只盯连接数。
一个容易忽略的点:连接池数量要按「应用实例数 × 每实例最大连接数」算总账。比如 20 个 Pod、每个池子上限 50,理论峰值就是 1000,扩容 Pod 时这个数会跟着涨。
四、要不要调大 max_connections
可以调,但要清楚边界:
- 修改位置:实例详情左侧「参数修改」,找到
max_connections修改;官方文档说明该参数修改后立即生效,无需重启。如果改的是「参数管理」里的自定义参数模板,需要执行「应用」才会对实例生效。 - 设成
default时,上限随实例内存规格变化(官方 FAQ 给出的默认值例如 4GB 约 1500、8GB 约 2500、16GB 约 5000)。 - 连接不是免费的。官方给的估算是单个连接大约占 1MB(thread_stack、join/sort/read buffer 等加起来),可用内存 = 总内存 − Buffer Pool − 约 1GB。盲目调大可能换来内存吃紧和性能下降。
- 实际可用连接数还受单进程最大打开文件数限制,可以看
show variables like 'open_files_limit';。
如果业务确实需要更多连接,又受内存约束,就考虑规格升配。升配期间实例可访问,但会有秒级连接闪断,放在业务低峰期做。
五、预防:把连接管起来
- 连接池上限:所有应用实例的连接池上限之和,控制在实例
max_connections的 70%~80% 以内,给运维和突发留余量。 - 空闲超时对齐:
wait_timeout/interactive_timeout可以按业务调到 600~1800 秒;同时让客户端连接池的空闲回收时间小于数据库的wait_timeout,否则池子里会留下已被服务端断开的「僵尸连接」,借出去就报错。 - 重试要退避:连接失败的重试加上指数退避和上限,避免故障时自己把数据库打爆。
- 告警前置:给「连接数使用率」配告警,阈值同样设在 70%~80%,比等到 1040 报错再处理主动得多。
- 定期巡检:按客户端 IP 看连接分布,发现某个服务连接只增不减,优先查泄漏。
六、速查表
| 现象 | 可能原因 | 怎么确认 |
|---|---|---|
| 连接数缓慢爬升、很少回落 | 连接泄漏 | 实时会话按 IP 统计,某来源只增不减 |
| 大量 Sleep 连接、Time 很大 | wait_timeout 过大、池子不回收 | processlist 筛 Sleep,看 Time |
| 连接被占住且有未提交事务 | 长事务 | innodb_trx 看 trx_started |
| 发布或扩容瞬间打满 | 连接池初始化/总量超限 | 对照发布时间与连接曲线,核算池子总账 |
| 故障时连接越来越多 | 重试无退避 | 应用日志里的重连频率 |
| 连接数和慢 SQL 同时上涨 | 数据库变慢导致排队 | 慢 SQL 分析、锁等待、IO 监控 |
小结
遇到 Too many connections,我习惯先 Kill 空闲和问题会话止血,再看连接曲线是「慢涨」还是「突增」来分方向,最后才考虑调 max_connections 或升配。把连接池总量、空闲超时和告警阈值这三件事配好,大部分连接数打满的问题都能提前避开。
参考文档:
- 点赞
- 收藏
- 关注作者
评论(0)