SQL 如何监控 max_connections 被占满的告警与临时扩容

应通过监控连接使用率趋势而非瞬时值来实时预警:PG用pg_stat_activity计数与max_connections比值≥85%持续2分钟告警;MySQL结合Threads_connected、Threads_running及滑动窗口分析,避免误判业务波动。

sql 如何监控 max_connections 被占满的告警与临时扩容

如何实时发现 max_connections 即将耗尽

PostgreSQL 和 MySQL 的连接数被打满时,新连接会直接拒绝,错误通常是 FATAL: remaining connection slots are reserved for non-replication superuser connections(PG)或 Too many connections(MySQL)。不能等报错才响应,得提前预警。

关键不是查当前用了多少,而是看「趋势」+「临界阈值」。建议在监控系统中配置:

  • PostgreSQL:每 30 秒采集 SELECT COUNT(*) FROM pg_stat_activity;,对比 SHOW max_connections;,当使用率 ≥ 85% 持续 2 分钟触发告警
  • MySQL:用 SHOW STATUS LIKE 'Threads_connected';SHOW VARIABLES LIKE 'max_connections';,注意 Threads_connected 包含空闲连接,需结合 Threads_running 判断真实压力
  • 避免只看瞬时值——短时 spike 可能是正常业务波动,要叠加滑动窗口(如 5 分钟内最大值 / 平均值)

临时扩容 max_connections 的安全操作路径

动态调大 max_connections 不是简单改个参数重启就行,它受底层资源硬约束。不检查就扩,可能引发 OOM 或内核拒绝分配内存。

执行前必须确认:

  • PostgreSQL:检查 shared_bufferswork_mem 是否已随连接数线性增长——每个连接默认至少占用几 MB 内存,max_connections 从 100 扩到 500,若 work_mem=4MB,理论内存新增约 (500−100)×4MB = 1.6GB
  • MySQL:确认 table_open_cacheinnodb_buffer_pool_instances 等关联参数是否需同步调整,否则可能卡在文件描述符或 mutex 竞争上
  • 操作系统层:用 ulimit -n 查当前进程允许打开的文件数,max_connections 必须 ≤ 该值 × 0.8(留出日志、socket 等其他句柄空间)

线上临时扩容推荐分两步走:ALTER SYSTEM SET max_connections = 300; SELECT pg_reload_conf();(PG),或修改 my.cnfmysqladmin shutdown && mysqld_safe &(MySQL,无法在线生效)。

为什么连接数容易被“假占满”

真正活跃的连接可能只有十几个,但 pg_stat_activity 显示几百个——这通常不是配置太小,而是应用没正确释放连接。

常见诱因:

  • 应用端未调用 connection.close() 或未进 finally 块,尤其在异常分支里漏关
  • 连接池配置不合理:比如 HikariCP 的 maximumPoolSize 设为 100,但 connection-timeout 过长(如 30s),导致请求堆积后大量连接卡在“获取中”状态
  • 数据库端存在长事务或锁等待:state = 'idle in transaction'wait_event = 'Lock' 的连接会持续占 slot,需用 pg_blocking_pids(pid) 定位源头

这类问题扩 max_connections 只是掩盖症状,必须配合 pg_stat_activity 中的 backend_startstate_changequery_start 字段做时间差分析。

可赞AI

可赞AI

文字一秒可视化,免费AI办公神器

下载

告警后快速止损的应急命令清单

告警响了,第一反应不是改配置,而是先释放可杀的连接保服务。

PostgreSQL(谨慎执行):

SELECT pid, usename, application_name, state, now() - backend_start AS uptime, now() - state_change AS idle_time, query
FROM pg_stat_activity
WHERE state IN ('idle in transaction', 'idle') AND now() - state_change > interval '5 minutes';

确认无误后批量终止:

SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle in transaction' AND now() - state_change > interval '5 minutes';

MySQL 类似:

KILL [CONNECTION] [thread_id]; -- 先查 SHOW PROCESSLIST; 找出 Command='Sleep' 且 Time > 300 的

注意:pg_terminate_backend() 对超级用户连接无效;MySQL 的 KILL 不会回滚事务,只断开连接,后续需人工检查数据一致性。

真正难的不是扩容动作本身,而是区分“该扩”还是“该修”——连上去看到 200 个 idle 连接,90% 的情况该翻应用日志,而不是去改 max_connections 配置文件

https://www.php.cn/faq/2034692.html

发表回复

Your email address will not be published. Required fields are marked *