数据库监控实战:PostgreSQL / MySQL 生产监控四类故障决策树与 5 个真实事故复盘
凌晨 1 点 47 分,我被监控电话叫醒。业务值班说接口大面积超时,P99 延迟从 80ms 飙到 4 秒。我爬起来看 Grafana:主机 CPU 才 15%,内存 40%,磁盘 IO 也正常,OS 监控全绿。按"主机没挂"的经验判断,我差点让值班重启网关再观察。幸好多看了一眼数据库面板——pg_stat_activity 里 300 多个连接全是 idle in transaction,max_connections 已经打满 96%。数据库"假死"了:进程活着,但所有新请求都卡在连接池门口进不去。那次事故之后我明白了一件事:监控数据库 ≠ 监控主机。这篇文把我线上攒的经验写全——怎么用 postgres_exporter + mysqld_exporter 把数据库层盯住,四类故障怎么判断,以及我踩过的 5 个真实坑。想先补 Prometheus 部署和查询基础的,看我之前写的 Prometheus 部署 和 PromQL 查询。
为什么监控数据库 ≠ 监控主机
数据库是有状态的。主机监控看的是"资源用了多少",数据库监控要看"请求排队了多久"。资源低不代表健康——连接池耗尽、锁等待、IO 等待这些瓶颈恰恰不体现在 CPU 上,主机面板全绿,数据库可能已经瘫了。
我遇到的"假死"比"硬宕机"危险得多。硬宕机进程挂了,连接直接报错,应用能感知、能重试;假死是进程活着、端口开着、连接能建上,但每个请求都堵着等锁或等连接,表现为大面积超时——应用以为网络问题,网关以为下游慢,没人怀疑数据库。等到真查出是连接池,业务已经抖了半小时。
所以数据库监控要盯四个层面,缺一不可:
| 层面 | 主机监控能发现吗 | 为什么要单独盯 |
|---|---|---|
| 连接 | 不能 | 连接池耗尽是"假死"主因,CPU/内存正常 |
| 锁 | 不能 | 锁等待是慢查询的隐形推手,CPU 不高 |
| 复制 | 不能 | 备库延迟会导致主备切换丢数据,OS 全绿 |
| 慢查询 | 不能 | 慢查询堆积会拖垮连接和锁,指标滞后 |
链路架构:数据库 → exporter → Prometheus
生产环境我推荐一套干净的链路:exporter 用 systemd 托管跑在数据库本机,Prometheus 从 127.0.0.1 抓取(exporter 只绑本机回环,不暴露外网),告警走 Alertmanager,看板用 Grafana。数据库监控的最小权限和端口隔离这两件事,很多教程压根不提,我吃过亏。
exporter 本机 systemd 部署(以 PostgreSQL 为例)
先建监控账号——绝不复用应用账号,更不要用 root/superuser。PostgreSQL 8.x 起内置了 pg_monitor 角色,一行授权搞定:
-- 用超级用户执行一次
CREATE ROLE exporter LOGIN PASSWORD 'Str0ng-P@ss-For-Monitor';
GRANT pg_monitor TO exporter;
-- pg_monitor 自动包含 pg_read_all_stats、pg_read_all_settings、pg_stat_scan_tables
-- 覆盖了 pg_stat_activity、pg_stat_replication、pg_stat_statements、pg_stat_database 的读取
pg_monitor 是 PostgreSQL 10+ 的内置角色,比我早期手动 GRANT SELECT ON pg_stat_* TO exporter 干净得多——不用逐视图授权,升级也不漏。如果是老版本,手动授 pg_stat_activity、pg_stat_replication、pg_stat_database 的 SELECT 即可。
MySQL 建只读监控用户:
CREATE USER 'exporter'@'127.0.0.1' IDENTIFIED BY 'Str0ng-P@ss-For-Monitor';
-- 最小权限:PROCESS 看连接线程,REPLICATION CLIENT 看复制,SELECT 读库
GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'127.0.0.1';
FLUSH PRIVILEGES;
坑:别给 MySQL 监控用户 ALL PRIVILEGES。PROCESS + REPLICATION CLIENT + SELECT 已经够 mysqld_exporter 抓所有核心指标,ALL 等于把只读监控账号变成了半个管理员,被拖库时连 binlog 都能读。
systemd unit(/etc/systemd/system/postgres-exporter.service):
[Unit]
Description=Prometheus PostgreSQL Exporter
After=network.target postgresql.service
[Service]
User=prometheus
Group=prometheus
# 坑:环境变量别写进命令行,ps 会泄露密码
Environment=DATA_SOURCE_NAME="postgresql://exporter:Str0ng-P@[email protected]:5432/postgres?sslmode=disable"
# 只绑本机回环,绝不开 0.0.0.0
ExecStart=/usr/local/bin/postgres_exporter --web.listen-address=127.0.0.1:9187 --web.telemetry-path=/metrics
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
MySQL 同理(mysqld_exporter --web.listen-address=127.0.0.1:9104)。坑:exporter 端口绑 0.0.0.0 等于裸奔——我曾见到某司 exporter 开了公网,任何能访问 9104 端口的人都能看到连接数、复制延迟甚至慢查询 SQL,这是数据泄露级隐患。绑 127.0.0.1 或加防火墙限制源 IP。
docker-compose 方式(适合容器化环境,注意网络要 host 才能让 exporter 访问本机数据库):
services:
postgres-exporter:
image: prometheuscommunity/postgres-exporter:latest
network_mode: host # 坑:必须 host,bridge 模式下连不上宿主机数据库
environment:
DATA_SOURCE_NAME: "postgresql://exporter:Str0ng-P@[email protected]:5432/postgres?sslmode=disable"
command: ["--web.listen-address=127.0.0.1:9187"]
restart: always
Prometheus 抓取配置(prometheus.yml):
scrape_configs:
- job_name: postgres
static_configs:
- targets: ['127.0.0.1:9187'] # 或实际 IP,如 10.0.1.5:9187
relabel_configs:
- source_labels: [__address__]
target_label: instance
replacement: pg-prod-01 # 给实例起个可读名,不然全是 IP 不好看
- job_name: mysql
static_configs:
- targets: ['10.0.1.6:9104']
relabel_configs:
- source_labels: [__address__]
target_label: instance
replacement: mysql-prod-01
PostgreSQL 黄金指标速查
以下是我在 Grafana 面板里常驻的 PG 指标,全部来自 postgres_exporter 默认导出(无需额外参数):
| 监控目标 | 指标名 | 阈值(预警/严重) |
|---|---|---|
| 活跃连接占比 | pg_stat_database_numbackends / 查询 max_connections |
>80% / >90% |
| 连接等待 | pg_stat_database_tup_returned 增长率 |
结合慢查询看 |
| 事务吞吐 | pg_stat_database_xact_commit / xact_rollback 速率 |
环比突增看 |
| 缓存命中率 | pg_stat_database_blks_hit / (blks_hit+blks_read) |
<98% 预警 |
| 复制延迟 | pg_stat_replication_replay_lag_seconds |
>10s / >60s |
| 慢查询 | pg_stat_statements_mean_exec_time_ms(需启用扩展) |
>500ms 预警 |
| 死元组膨胀 | pg_stat_user_tables_n_dead_tup / n_live_tup |
>20% 触发 vacuum |
| 数据库年龄 | pg_database_datfrozenxid_age |
>2 亿 / >4 亿(防事务 ID 回卷) |
对应 PromQL(PG):
# 连接池占用率(numbackends / max_connections)
pg_stat_database_numbackends{datname="mydb"} / on() pg_settings_max_connections * 100
# 缓存命中率(低于 98% 说明有全表扫描压力)
sum(rate(pg_stat_database_blks_hit[5m])) / (sum(rate(pg_stat_database_blks_hit[5m])) + sum(rate(pg_stat_database_blks_read[5m]))) * 100
# 复制延迟(秒)——坑:没有 pg_replication_lag_seconds!
pg_stat_replication_replay_lag_seconds
# 死元组比例(vacuum 压力)
pg_stat_user_tables_n_dead_tup / (pg_stat_user_tables_n_live_tup + pg_stat_user_tables_n_dead_tup) * 100
踩坑①:网上大量教程写的 pg_replication_lag_seconds 根本不存在。正确的延迟在 pg_stat_replication 视图里,字段是 replay_lag(备库重放延迟)、flush_lag、write_lag,postgres_exporter 导出为 pg_stat_replication_replay_lag_seconds。我第一次照着某博客配规则,Prometheus 一直 no data,排查半天才发现指标名错了。
踩坑②:pg_stat_statements 不能只 CREATE EXTENSION。必须先改 postgresql.conf:
# postgresql.conf
shared_preload_libraries = 'pg_stat_statements'
pg_stat_statements.track = all
# 改完必须重启数据库进程,仅 CREATE EXTENSION 不会加载共享库
重启后 postgres_exporter 才导出 pg_stat_statements 开头的指标。我见过太多人只建扩展不重启,然后怀疑 exporter 坏了。
MySQL 黄金指标速查
| 监控目标 | 指标名 | 阈值(预警/严重) |
|---|---|---|
| 连接占用 | mysql_global_status_threads_connected / max_connections |
>80% / >90% |
| 真正执行 | mysql_global_status_threads_running |
> CPU 核数×2 预警 |
| 慢查询率 | rate(mysql_global_status_slow_queries[5m]) |
持续 >0 且增长 |
| 行锁等待 | mysql_global_status_innodb_row_lock_waits(累计) |
增量 >100/s 预警 |
| 死锁 | 无现成计数器,用 row_lock_waits 推断 | 见下文 |
| 复制延迟 | mysql_slave_status_seconds_behind_master |
>10s / >60s |
| 缓冲区命中 | mysql_global_status_innodb_buffer_pool_read_requests / reads |
<98% 预警 |
| 临时表 | mysql_global_status_created_tmp_tables 速率 |
突增看磁盘临时表 |
对应 PromQL(MySQL):
# 连接占用率
mysql_global_status_threads_connected / mysql_global_variables_max_connections * 100
# 真正执行线程(性能瓶颈看这个,不是 connected)
mysql_global_status_threads_running
# 行锁等待速率(累计计数器,算 rate)
rate(mysql_global_status_innodb_row_lock_waits[5m])
# 复制延迟
mysql_slave_status_seconds_behind_master
踩坑③:Threads_connected 和 Threads_running 别混。前者是已建连接总数(含空闲),后者是正在执行语句的连接数。连接池告警看 connected/max_connections,性能瓶颈看 running。有一次我误用 connected 做性能告警,晚上业务高峰 connected 涨到 2000 触发告警,实际 running 才 30——是连接没释放(连接池泄漏),不是数据库忙。反过来,若 running 长期接近 CPU 核数,才是真的算力吃紧。
踩坑④:MySQL 没有 deadlocks_total 这类现成的死锁计数器。判断锁压力用 mysql_global_status_innodb_row_lock_waits(行锁等待累计次数,算 rate 看增量),或用 performance_schema 的 events_waits_summary_global_by_event_name 查 wait/engine/innodb/row_lock。真要定位死锁,直接 SHOW ENGINE INNODB STATUS 看 LATEST DETECTED DEADLOCK 段,别在指标上找不存在的计数器。
四类故障决策树
这是本文的核心。每类故障我按「症状 → 决策 → 命令 → 阈值」排成决策树,值班时照着走能省一半排查时间。
决策树①:连接池耗尽(假死主因)
症状:接口大面积超时,OS CPU/内存正常
└─> 看 connected/max_connections 比例
├─ <80% → 不是连接池,查下一步
├─ 80-90% → 预警,检查是否有连接泄漏(idle 连接堆积)
└─ >90% → 严重!立即排查
├─ 决策:找出"谁占着连接不释放"
├─ 命令(PG):SELECT state, count(*) FROM pg_stat_activity GROUP BY state ORDER BY 2 DESC;
│ # 若 idle in transaction 大量堆积 → 应用事务没提交/没回滚,找业务侧
├─ 命令(MySQL):SHOW PROCESSLIST; # 看大量 Sleep 状态的连接 → 连接池没释放
├─ 阈值:idle in transaction > max_connections*0.3 视为异常
└─ 临时缓解:PG 可 pg_terminate_backend 杀掉空闲事务(谨慎,先确认业务方)
连接池耗尽的典型特征是 idle in transaction(PG)或大量 Sleep(MySQL)堆积——连接建了但一直空闲占着。这不是数据库在忙,是应用侧连接管理有 bug,比如事务里做了网络调用没及时提交。修复方向是应用代码,不是加 max_connections(加了只是把问题推迟,池子迟早再满)。
决策树②:锁与死锁
症状:某几张表查询突然极慢,CPU 不高但请求堆积
└─> 看锁等待指标
├─ PG:SELECT blocked, count(*) FROM pg_locks WHERE NOT granted GROUP BY blocked;
│ # blocked 列显示谁在等锁;也可查 pg_stat_activity 里 wait_event_type='Lock'
├─ MySQL:SHOW ENGINE INNODB STATUS; # 看 TRANSACTIONS 段的锁等待链
└─ 决策:找到"持锁方",通常是长事务
├─ 命令(PG):SELECT pid, state, now()-xact_start AS dur, query FROM pg_stat_activity WHERE state != 'idle' ORDER BY dur DESC LIMIT 10;
│ # xact_start 很早但还在跑 → 长事务持锁不放
├─ 阈值:事务持续时间 > 60s 预警,> 5min 严重
└─ 缓解:PG 用 pg_cancel_backend(pid) 取消,严重用 pg_terminate_backend(pid)
死锁和锁等待要分清:死锁是互等(A 等 B、B 等 A,数据库会自动回滚一方),锁等待是单方阻塞(A 持锁,B 一直等)。锁等待更危险——它不会自动解除,会越堆越多,直到连接池耗尽,引发连锁"假死"。MySQL 侧死锁会频繁出现在错误日志,PG 侧 pg_locks 里 granted=false 的锁就是等待链。
决策树③:复制延迟
症状:备库延迟告警,主库看起来正常
└─> 看 replay_lag(PG)/ seconds_behind_master(MySQL)
├─ <10s → 正常,不用管
├─ 10-60s → 观察,检查是否大事务/大 DDL 在跑
└─ >60s → 严重,有主备切换丢数据风险
├─ 决策:先判断是"真慢"还是"假警"
├─ 假警排查:
│ ├─ 主从时钟不同步 → 用数据库自身延迟,别自己算主从时间差
│ ├─ 长事务/大 DDL → 主库执行了 ALTER 大表,WAL/relay log 堆积
│ └─ 网络抖动 → 看 exporter 抓取是否中断过
├─ 真慢排查:SELECT * FROM pg_stat_replication; # 看 state、write/flush/replay_lag
└─ 缓解:若备库持续跟不上,考虑临时切只读分流,别硬扛
踩坑⑤:复制延迟假警是高频事故。主从时钟不同步(NTP 没配好)、主库跑长事务、网络抖动都会造成瞬时尖峰。我在告警规则里必须加 for: 5m,否则每晚业务高峰都会收到一堆"复制延迟"的假告警。另外别自己用 abs(主时间戳 - 备时间戳) 算延迟——一旦时钟漂移,这个值永远不准,直接用 replay_lag / seconds_behind_master 这类数据库自身计算的延迟。
决策树④:慢查询
症状:接口变慢但连接数正常,锁等待也不多
└─> 看慢查询指标
├─ PG:pg_stat_statements 的 mean_exec_time 排序
│ SELECT query, mean_exec_time, calls FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10;
├─ MySQL:slow_queries 速率 + performance_schema
│ SELECT * FROM sys.schema_unused_indexes; # 找出没人用的索引
└─ 决策:定位到具体 SQL
├─ 命令(PG):EXPLAIN (ANALYZE, BUFFERS) <慢SQL>; # 看 Seq Scan 和 buffer 读取
├─ 命令(MySQL):EXPLAIN ANALYZE <慢SQL>; # 8.0 支持
├─ 阈值:单条 >500ms 预警,>2s 严重;全表扫描且 rows 大 → 加索引
└─ 缓解:加索引前先用 EXPLAIN 确认,别盲目加(写入会变慢)
慢查询是"温水煮青蛙"——它不直接报警,但会慢慢吃掉连接和锁,最终演变成前两类故障。所以慢查询监控是预防性的:pg_stat_statements 里 calls 大且 mean_exec_time 高的 SQL,就是定时炸弹。
5 个真实事故复盘
以下是我在运维一线处理过的真实故障,细节经过脱敏。每个都对应上面一类决策树的落地。
事故一:连接池耗尽导致"假死"(对应决策树①)
现象:凌晨接口大面积超时,OS CPU 15% 全绿。根因:某定时任务改了事务边界,在事务里调了外部 HTTP 接口,HTTP 超时 30s 期间连接一直 idle in transaction 占着池子。300 个连接 200 个卡在事务里。指标怎么显示:pg_stat_database_numbackends 涨到 max_connections 的 96%,idle in transaction 占 200+,CPU 完全正常——这就是"假死"。修复:pg_terminate_backend 杀掉空闲事务,业务侧把 HTTP 调用移出事务。防再发:连接池告警阈值 >80% 预警、>90% 严重,且单独对 idle in transaction 计数加告警。
事故二:长事务持锁拖垮整张表(对应决策树②)
现象:某订单表查询从 10ms 涨到 3s,CPU 正常。根因:一个后台脚本 BEGIN 后做批量更新,中途抛异常没回滚,事务挂着持锁 40 分钟,所有对该表的写全部排队。指标怎么显示:pg_locks 里 granted=false 的锁堆积,pg_stat_activity 里一个 xact_start 40 分钟前的连接 state=active。修复:找到该 pid,pg_cancel_backend 取消。防再发:给长事务加告警(xact_start 超过 5 分钟即报警),并让开发把脚本改成 try/finally 保证回滚。
事故三:主从时钟不同步的复制假警(对应决策树③)
现象:复制延迟告警每小时响一次,检查备库实际数据并不落后。根因:主从两台机器 NTP 没配好,时钟漂了 3 秒,而我当时用 abs(主时间戳 - 备时间戳) 算延迟。指标怎么显示:seconds_behind_master 其实为 0,但我自算的"延迟"恒为 3s 左右,刚好卡在告警线上。修复:两台机配 NTP 同步,改成用数据库自身延迟指标。防再发:告警加 for: 5m,所有复制延迟一律用 replay_lag/seconds_behind_master,不用自算时间差。
事故四:全表扫描拖垮缓存命中率(对应决策树④)
现象:某报表接口越来越慢,缓存命中率掉到 92%。根因:一个统计 SQL 没带索引条件,每跑一次全表扫 200 万行,把 buffer pool 冲得全是无效页。指标怎么显示:pg_stat_database_blks_hit / (blks_hit+blks_read) 从 99% 掉到 92%,pg_stat_statements 里该 SQL mean_exec_time 涨到 1.8s。修复:加复合索引,命中率回到 99%。防再发:缓存命中率 <98% 告警,慢查询 TOP 榜每周 review 一次。
事故五:MySQL 行锁等待堆积成雪崩(对应决策树②)
现象:订单服务批量超时,从一条慢 SQL 开始,10 分钟内连坐全库。根因:一个批量更新没有按主键顺序,两条事务互相等待对方已加锁的行,加上 innodb_lock_wait_timeout 默认 50s,等待链越积越长。指标怎么显示:mysql_global_status_innodb_row_lock_waits 的 rate 从个位数飙升到 200+/s,Threads_running 高企但 Threads_connected 正常。修复:杀掉持锁会话,把批量更新改成按主键排序分批执行。防再发:行锁等待 rate >100/s 告警,锁等待链超过 3 层视为异常。
生产级告警规则
以下是我实际在用的告警规则,for 时窗和注释都是踩坑后的产物。
# database-alerts.yml
groups:
- name: postgresql
rules:
# 连接池占用率(PG)
- alert: PostgreSQLConnPoolHigh
expr: pg_stat_database_numbackends{datname!~"template.*"} / on() pg_settings_max_connections * 100 > 80
for: 2m
labels:
severity: warning
annotations:
summary: "PG 连接池占用 {{ $value | printf \"%.1f\" }}%"
description: "instance={{ $labels.instance }} datname={{ $labels.datname }} 连接池超过 80%,检查 idle in transaction 是否堆积"
- alert: PostgreSQLConnPoolCritical
expr: pg_stat_database_numbackends{datname!~"template.*"} / on() pg_settings_max_connections * 100 > 90
for: 1m
labels:
severity: critical
annotations:
summary: "PG 连接池耗尽 {{ $value | printf \"%.1f\" }}%"
description: "可能假死!立即查 pg_stat_activity 的 state,杀 idle in transaction"
# 复制延迟——坑:必须加 for 防假警(时钟/大事务/网络抖动)
- alert: PostgreSQLReplicationLag
expr: pg_stat_replication_replay_lag_seconds > 60
for: 5m
labels:
severity: critical
annotations:
summary: "PG 复制延迟 {{ $value | printf \"%.1f\" }}s"
description: "备库重放落后 {{ $value }}s,检查主库是否跑大事务/大 DDL,注意主从时钟同步"
# 缓存命中率低(全表扫描压力)
- alert: PostgreSQLCacheHitLow
expr: sum(rate(pg_stat_database_blks_hit[5m])) / (sum(rate(pg_stat_database_blks_hit[5m])) + sum(rate(pg_stat_database_blks_read[5m]))) * 100 < 98
for: 10m
labels:
severity: warning
annotations:
summary: "PG 缓存命中率 {{ $value | printf \"%.1f\" }}%"
description: "低于 98% 可能有全表扫描,查 pg_stat_statements 慢查询 TOP"
- name: mysql
rules:
- alert: MySQLConnPoolHigh
expr: mysql_global_status_threads_connected / mysql_global_variables_max_connections * 100 > 80
for: 2m
labels:
severity: warning
annotations:
summary: "MySQL 连接占用 {{ $value | printf \"%.1f\" }}%"
description: "instance={{ $labels.instance }} 连接超 80%,注意 Sleep 连接堆积(连接池泄漏)"
- alert: MySQLRowLockWaits
expr: rate(mysql_global_status_innodb_row_lock_waits[5m]) > 100
for: 2m
labels:
severity: warning
annotations:
summary: "MySQL 行锁等待速率 {{ $value | printf \"%.1f\" }}/s"
description: "锁压力高,查 SHOW ENGINE INNODB STATUS 的锁等待链,可能演变成雪崩"
- alert: MySQLReplicationLag
expr: mysql_slave_status_seconds_behind_master > 60
for: 5m
labels:
severity: critical
annotations:
summary: "MySQL 复制延迟 {{ $value }}s"
description: "备库落后 {{ $value }}s,检查大事务/大 DDL/网络,用数据库自身延迟防时钟假警"
坑:for 不是越大越好。我最早把复制延迟的 for 配成 30m,结果一次真故障延迟持续 25 分钟,告警没发出来——等发出来主库已经被切换了。折中下来,复制延迟这类瞬时尖峰多的用 for: 5m,连接池这类真故障的用 for: 1-2m(宁可早报不可漏报)。告警通知配置(webhook、Silence、抑制)看我写的 Alertmanager 告警规则,看板设计看 Grafana 面板。
FAQ
Q1:PostgreSQL 有没有 pg_replication_lag_seconds 这个指标?
没有。这个指标名在网上流传很广,实际查不到。正确延迟在 pg_stat_replication 视图:replay_lag(秒)是主库提交到备库重放完毕的延迟,另有 flush_lag(备库收到并落盘)和 write_lag(备库收到)。postgres_exporter 导出为 pg_stat_replication_replay_lag_seconds。用 \x SELECT * FROM pg_stat_replication; 可看全部字段。
Q2:为什么我 CREATE EXTENSION pg_stat_statements 了却查不到数据?
只建扩展不重启没用。pg_stat_statements 必须在 postgresql.conf 里配 shared_preload_libraries = 'pg_stat_statements',重启数据库进程后才加载共享库,CREATE EXTENSION 只是建视图和函数。重启后确认 SELECT count(*) FROM pg_stat_statements; 有数据,且 postgres_exporter 会导出 pg_stat_statements_* 指标。
Q3:MySQL 的 Threads_connected 和 Threads_running 有什么区别?
Threads_connected 是已建立连接总数(含空闲),Threads_running 是真正在执行语句的连接数。连接池告警看 connected/max_connections(>80% 预警 >90% 严重);性能瓶颈看 running——它接近 CPU 核数才算忙。connected 高但 running 低,通常是连接池泄漏或应用没释放连接,要查业务侧。
Q4:MySQL 有没有现成的死锁次数计数器?
没有 deadlocks_total 这类指标。用 mysql_global_status_innodb_row_lock_waits(行锁等待累计,算 rate 看增量)判断锁压力,或用 performance_schema 的 events_waits_summary_global_by_event_name 查 wait/engine/innodb/row_lock。死锁定位用 SHOW ENGINE INNODB STATUS 的 LATEST DETECTED DEADLOCK 段。
Q5:复制延迟老是瞬时报警怎么办?
告警加 for: 5m 防抖。主从时钟不同步、长事务、网络抖动都会造成瞬时尖峰,for 能滤掉。另外别用 abs(主时间戳-备时间戳) 自算延迟——时钟漂移会让它永远不准,用数据库自身的 replay_lag/seconds_behind_master。
相关文章
- Prometheus 部署 —— exporter 抓取链路的基础,scrape_config 怎么配
- PromQL 查询 —— 本文所有 PromQL 的语法基础,rate/sum/on 的用法
- Grafana 面板 —— 把黄金指标做成可视化看板
- Alertmanager 告警规则 —— 告警通知、Silence、Inhibit 的完整配置
- Linux 磁盘 IO 监控 —— 数据库磁盘瓶颈常和 IO 等待有关,配合看
- Linux 内存监控 —— buffer pool / shared_buffers 的内存调优基础