云服务器 ECS 上数据库连接数(Connections)短时间内飙升,这通常不是“数据库坏了”,而是“应用层”或“网络层”出现了异常。作为运维或开发,遇到这种情况别慌,按以下逻辑层层剥离,基本能定位到根因。
第一步:确认是“真连接”还是“假活跃”
首先,你要区分清楚你看到的 Threads_connected 和 Threads_running 的区别。
- Threads_connected:当前建立的 TCP 连接总数。
- Threads_running:当前正在执行查询、未释放的连接数。
如果 Threads_connected 很高,但 Threads_running 很低,说明大量连接处于空闲状态(Idle)。这通常是连接池配置不当或连接泄漏导致的,而不是性能瓶颈。如果两者都高,那才是真的在扛流量或者卡死了。
第二步:排查最常见的三个“元凶”
1. 应用侧连接池泄露(最常见)
这是 80% 以上案例的根源。你的 Java/Go/Python 等应用使用了连接池(如 HikariCP, Druid, DBPool 等),但代码中获取了连接后,没有在 finally 块或上下文结束前正确 close() 或归还给池子。
- 现象:连接数随时间线性增长,直到达到数据库最大限制,随后应用报错
Too many connections。 - 验证方法:
- 查看应用日志,是否有大量的 SQL 执行超时或连接获取失败日志。
- 在应用服务器上使用
netstat -anp | grep :3306(MySQL) 或对应端口,观察连接状态。如果看到大量TIME_WAIT或CLOSE_WAIT,且进程 ID 指向你的应用服务,那就是连接没关干净。 - 注意:如果是 Nginx XX数据库,检查 Nginx 的后端连接是否也堆积。
2. 慢查询导致连接堆积
一个慢查询可能占用连接几秒钟甚至几分钟。如果并发请求量大,每个请求都触发慢查询,连接数会瞬间打满。
- 现象:
Threads_running居高不下,CPU 或 IO 负载升高。 - 验证方法:
- 开启 MySQL 的
slow_query_log,设置阈值极低(如 0.1s 或 1s),抓取当时的慢 SQL。 - 使用
SHOW FULL PROCESSLIST;命令,重点看State列。如果出现Sending data,Sorting result,Locked等状态,说明有阻塞。 - 结合阿里云 RDS/云数据库的控制台监控,查看 QPS 和 TPS 曲线,是否与连接数峰值重合。
- 开启 MySQL 的
3. DDoS 攻击或恶意扫描
不要忽略安全层面。如果连接数突然从几百飙升至几万,且来源 IP 分散,可能是遭遇了 SYN Flood 或针对数据库端口的暴力破解/扫描。
- 现象:连接来源 IP 杂乱无章,非业务时段突增,应用无明显流量增加。
- 验证方法:
- 检查安全组(Security Group)和防火墙策略。
- 查看 ECS 的安全事件中心或云盾 WAF 日志。
- 使用
tcpdump抓包分析源 IP 分布。
第三步:应急处理与长效优化方案
紧急止血(短期)
- 切断异常源:如果是特定应用实例的问题,先重启该实例的应用服务(注意:重启会断开现有连接,需确保有重试机制,避免雪崩)。
- 清理空闲连接:
- 如果是 MySQL,可以定期执行
KILL CONNECTION id;杀掉长时间空闲的连接。 - 更优雅的方式是在应用侧配置连接池的
maxLifetime和idleTimeout,强制回收陈旧连接。
- 如果是 MySQL,可以定期执行
- 临时扩容:如果确实是业务高峰(如大促),考虑临时升级数据库规格(提升 max_connections 上限),但这只是权宜之计,治标不治本。
根本解决(长期)
- 优化连接池配置:
- Java (HikariCP): 设置合理的
maximumPoolSize。公式参考:CPU核数 * 2 + 磁盘数。不要设得过大,否则上下文切换开销巨大。 - 关键参数:确保
connectionTimeout、idleTimeout、maxLifetime合理设置。特别是maxLifetime,建议设置为比数据库wait_timeout稍短的值,防止应用持有已失效的连接。
- Java (HikariCP): 设置合理的
- SQL 优化:
- 对慢查询进行索引优化。
- 避免在事务中进行远程调用、文件 IO 等非数据库操作。
- 引入读写分离,将读压力分流到只读实例。
- 架构升级:引入 Proxy 中间件:
- 对于高并发场景,建议在应用和数据库之间加一层 Proxy(如阿里云 DRDS、ShardingSphere-Proxy、MyCat 等)。
- Proxy 可以管理连接池,应用方只需保持少量长连接,由 Proxy 负责与后端数据库的多路复用。这样即使应用并发量翻倍,后端数据库的连接数也不会线性增长。
- 监控告警前置:
- 不要等连接数爆了才报警。设置阈值告警,例如:当
Threads_connected超过max_connections的 70% 时,立即通知开发人员。 - 监控维度要细化:不仅看总量,还要看各应用实例的连接分布,快速定位是哪台机器出了问题。
- 不要等连接数爆了才报警。设置阈值告警,例如:当
总结
连接数飙升本质是资源供需失衡。
- 如果是偶发,查慢 SQL 和网络抖动。
- 如果是持续上涨,查代码连接泄漏。
- 如果是突发海量,查攻击或流量洪峰。
记住,数据库不是用来做连接管理的,把连接管理交给应用层的连接池或专业的 Proxy 中间件,才是正确的架构思路。
云技术博客