如何设计数据库可观测性、事故排查与运行证据链
不要先堆监控指标;先解释“用户说数据库慢,CPU 却不高”
这一页只解决一个问题: 数据库事故现场怎样证明慢在哪里。可观测性不是 dashboard 越多越好,而是能把业务症状、SQL 指纹、等待事件、锁链、连接池、复制延迟、IO / WAL 和近期变更连成证据链。
周一 9:30,用户反馈“本月账单打不开”。应用 CPU 40%,数据库 CPU 45%。如果只看机器指标,团队会误以为数据库没事;但用户确实慢了。
| 现象 | 错误反应 | 先拆什么 |
| 用户说慢 | 先重启服务 | 影响接口、租户、时间段 |
| CPU 不高 | 认为数据库没问题 | 锁等待、连接等待、IO、WAL、复制延迟 |
| P99 高,平均值正常 | 认为影响不大 | 尾延迟集中在哪类 SQL 或租户 |
| 问题 | 需要的证据 |
| 谁受影响 | 接口、租户、用户规模、错误率、P95 / P99 |
| 哪类 SQL 在慢 | SQL fingerprint、调用入口、扫描行数、返回行数 |
| 慢在执行还是等待 | wait event、lock wait、connection wait、IO wait |
| 谁阻塞谁 | blocking session、事务年龄、锁对象 |
| 读的是主库还是从库 | db_role、replica lag、commit_lsn、连接目标 |
| 最近发生了什么变化 | 发布、DDL、导入、备份、归档、回填任务 |
db_trace_sample
- route
- tenant_id
- db_role
- db_instance
- sql_fingerprint
- plan_hash
- scanned_rows
- returned_rows
- wait_event
- lock_wait_ms
- connection_wait_ms
- replica_lag_ms
- release_version
吸收点: 没有 SQL 指纹和业务入口,慢查询日志只是一堆噪音;没有等待事件,所有慢都会被误修成索引问题。
| 边界 | 现象 | 设计动作 |
| 连接池满 | 请求等连接 | 先看连接持有时间、慢 SQL、长事务,不直接扩池 |
| 锁等待 | SQL 看起来慢 | 找 blocker、事务年龄、锁对象和 safe kill 边界 |
| 从库延迟 | 刚写后读不到 | 记录 commit_lsn 和 replica replay 位点 |
| IO / WAL 等待 | CPU 不高但提交慢 | 看日志刷盘、checkpoint、备份和导出任务 |
关键边界: “数据库慢”不是原因,是症状。先分类等待,再决定止血动作。
| 演练 | 通过标准 |
| 长事务锁住预算行 | 能看到 blocker、被影响接口和安全 kill 边界 |
| 连接泄漏 | 能区分连接等待和 SQL 执行慢 |
| 删除索引造成计划回归 | plan hash、扫描行数和 SQL fingerprint 异常可见 |
| 从库延迟 10 秒 | 写后读能识别新鲜度不足 |
| 备份和导出压热库 | 能把慢提交归因到 IO / WAL 等待 |
| 切主后连接池仍连旧实例 | 能从 db_instance 和 topology 证据定位 |
总结: 数据库可观测性不是指标大全。它只问:谁受影响,哪类 SQL,慢在执行还是等待,谁阻塞谁,读写去了哪里,最近什么变了。证据链能回答这些,事故才不会靠猜。