概述 — 本页做什么
服务 ▸ 数据库 直接连接已注册的数据库采集器(access=database),呈现实时负载与结构指标。它并不只是罗列数字,而是为每个关键指标(锁等待、缓存命中率、索引利用率、检查点、脏页)附上一个精心设计的教学式悬停浮窗,让你在看到数值的地方就能明白"这个值为什么不好/该怎么修"。
本文汇总这些浮窗所讲解的概念。完整词条以单一来源存放在实时浮窗中(resources/lang/{ko,en}/dbmon.php 的 edu 键),因此在真实场景中请把指针悬停在指标上,阅读与上下文对应的细节。
页面是监视器(现在哪里不好),浮窗是成因教学(为什么/怎么办),而实际的配置快照在 实例参数([param] · nginx / my.cnf / sysctl)里。三者结合阅读,才能从 诊断 → 证据 → 处置 一路走通。
使用场景
- 某张数据库卡片显示 Degraded 或 Down,你想弄清原因(连接饱和、高并发、查询积压、慢查询率上升)。
- 缓存命中率或索引利用率得分偏低,你想知道根因与改进手段(缓冲池大小、增加索引、覆盖索引)。
- 行锁等待突然升高,你需要缩小范围,找出是哪条查询/哪种模式造成了争用。
- 内存管理详情中的脏页/检查点波形正在悄悄逼近风险区,你想知道调优方向(扩大缓冲池/redo 日志)。
- DBA/DevOps 新人上手 — 对着真实数据学习 InnoDB 内部机制(锁、缓冲池、redo)。
页面构成
教学浮窗挂载的位置:
| 位置 | 指标 | 浮窗讲解的内容 |
|---|---|---|
卡片底部右侧 · Cache 徽章 |
缓存命中率(缓冲池) | 推导公式 + 提升它的 4 种办法 |
卡片底部右侧 · Index 徽章 |
索引利用率 | 推导公式 + 提高索引命中的 5 种办法 |
并发负载 · lock |
行锁平均等待(ms) | 锁等待上升的 7 种原因(按出现频率) |
页头/内存详情 · Checkpoint … % of redo |
检查点年龄 | redo 日志压力的含义,以及升降的读法 |
| 详情(可折叠) · 内存管理 | 脏页 · 检查点时间序列 | LWM/MAX 阈值叠加线 + 刷新事件标注 |
卡片主体本身汇总两条负载轴:
- 并发负载 — 连接饱和度(环形仪表) ·
Running(threads_running) ·Backlog(waiting) ·lock。 - 吞吐量 —
Total QPS迷你图 ·Slow rate(slow_qps) ·Slow (total)。
底部的结构分析(可折叠)显示总容量、占用最大的库、最大的表以及引擎构成(与调优概念无关,来自 information_schema)。
使用方法
- 在数据库卡片上找到有问题的指标(红/黄徽章,或明显偏高的数值)。
- 把指针悬停在该指标的标签/徽章上打开上下文浮窗 — 会显示成因、公式与处理办法。
- 展开详情,查看带有脏页/检查点波形与阈值截线的内存管理时间序列。
- 在目标数据库上应用浮窗指出的配置手段(例如
innodb_buffer_pool_size、增加索引),或与 实例参数 中的当前值相互对照。
下面是每个概念的摘要参考(以实时浮窗为准)。
行锁等待 — 7 种原因
InnoDB 为获取行锁而等待的平均时间(ms)。数值越高表示争用越严重。按出现频率排列:
| # | 原因 | 要点 |
|---|---|---|
| 1 | 事务持锁时间过长 | BEGIN … UPDATE … 之后迟迟不提交(外部 API、用户思考时间、慢查询),会让所有等待该行的事务排起长队。最常见的一种。 |
| 2 | 热点行争用 | 大量事务更新同一行(计数器、库存、汇总/上卷行、序列)→ 被串行化,等待不断堆积。 |
| 3 | 没有索引的 UPDATE/DELETE | 如果 WHERE 用不上索引,InnoDB 会锁住远超所需的行/范围 → 连不相干的事务也被阻塞。这是实践中隐藏的头号原因。 |
| 4 | 间隙锁/临键锁 | 在 REPEATABLE READ 下,范围锁还会锁住行与行之间的间隙,从而阻塞 INSERT。典型是范围 UPDATE + 并发 INSERT 的模式。 |
| 5 | 大批量 DML | 一条涉及数万行的 UPDATE/DELETE 会长时间持有大量锁。 |
| 6 | 持锁者本身很慢 | 如果持锁的查询在 I/O 或 CPU 上很慢,它就会把锁握得更久 — 慢查询率上升与锁等待上升往往同步发生。 |
| 7 | 外键检查 | 更新引用外键的表会对父行加共享锁,进一步拉长等待。 |
在本页面上,第 3 项(没有索引的 UPDATE)是锁等待飙升背后隐藏的头号推手。请把
SHOW ENGINE INNODB STATUS的 TRANSACTIONS 段落与 索引利用率 得分结合起来看。
缓存命中率(InnoDB 缓冲池)
当大多数读取由内存(缓冲池)而非磁盘提供时,该值就会很高。
hit ratio = 1 − Δinnodb_buffer_pool_reads / Δinnodb_buffer_pool_read_requests
| 评级 | 阈值 |
|---|---|
| 优秀 | ≥ 99.5% |
| 良好 | ≥ 98% |
| 一般 | ≥ 90% |
如何提升(摘要):调大 innodb_buffer_pool_size(经验值为内存的 50–75%) · 减少全表扫描以免污染缓冲池 · 缩小工作集(避免取用不到的列、拆分大 BLOB、归档) · 用 innodb_buffer_pool_instances 降低争用,并在重启时转储/重载缓冲池。
索引利用率
通过索引定位到行的读取,与一路扫描到下一行的读取之间的比例。
index usage = Δhandler_read_key / (Δhandler_read_key + Δhandler_read_rnd_next)
| 评级 | 阈值 |
|---|---|
| 优秀 | ≥ 90% |
| 良好 | ≥ 70% |
| 一般 | ≥ 40% |
如何提升(摘要):用 EXPLAIN 找出全表扫描(type=ALL)与文件排序,然后给 WHERE/JOIN/ORDER BY 涉及的列建索引 · 建复合索引时把选择性最高的列放在最前(最左前缀原则) · 不要在列上使用函数或类型转换而让索引失效(WHERE DATE(col)=… → 改用范围条件) · 使用覆盖索引 · 删除重复/未被使用的索引。
检查点年龄(redo 日志压力)
redo 日志在最后一次检查点之后前进了多少(字节)= 尚未刷入数据文件的变更量,也是崩溃时 InnoDB 需要重放的工作量。页头的 % of redo 表示距离刷新风暴悬崖还有多远。
| 状态 | % of redo | 含义 |
|---|---|---|
| 安全 | < 50% | 变更能被及时刷盘 |
| 关注 | 50 – 75% | 写入速度超过刷盘速度;强制刷新正在逼近 |
| 风险 | ≥ 75% | 接近异步/同步刷新阈值 — 强制刷新可能带来延迟/I/O 风暴 |
读法:上升=写入 > 刷盘(redo 正在填满) · 下降=刷盘已追上(健康) · 锯齿形=积累 ↔ 刷盘,属于正常节奏。接近 75% 时,可以考虑扩大缓冲池或 innodb_log_file_size。
脏页刷新(内存管理)
缓冲池中已被修改、但尚未写入磁盘的页。合适的取值取决于服务器自身的刷新阈值(innodb_max_dirty_pages_pct = MAX,innodb_max_dirty_pages_pct_lwm = LWM)。专家的共识是:脏页应当在 LWM 之下波动。
| 状态 | 条件 | 含义 |
|---|---|---|
| 健康(good) | 在阈值以下波动(健康的锯齿形) | 刷新期间数据库没有受苦 |
| 注意(warn) | 高于低水位线(进入预刷新区) | 关注写入压力与检查点滞后 |
| 危险(crit) | 已达到 MAX 阈值 | 激进刷新 → 延迟尖峰/I/O 风暴(扩大缓冲池/redo 日志) |
内存管理时间序列会把 LWM/MAX 截线叠加在脏页曲线之上,并标出淘汰/刷新事件。右侧指标还会显示 Pending writes 和 Row-lock avg。
数据来源
这些教学概念所引用的真实计数器与存储:
| 概念 | 来源计数器/状态 | 备注 |
|---|---|---|
| 锁等待 | SHOW GLOBAL STATUS · information_schema.processlist |
计算积压量;需要 PROCESS 权限 |
| 缓存命中率 | Innodb_buffer_pool_reads / _read_requests |
两次采样之间的差值 |
| 索引利用率 | Handler_read_key / Handler_read_rnd_next |
两次采样之间的差值 |
| 检查点 · 脏页 | InnoDB 状态(检查点年龄 · 脏页 · 待处理) | 内存管理时间序列 |
| QPS · 慢查询 | Questions · Slow_queries(累计) |
由差值推导出 QPS /慢查询率 |
- 时间序列保存在
infr_db_metric(迁移 000681)。App\Services\Database\DbCollectorService直接连接已注册的数据库,读取SHOW GLOBAL STATUS+@@max_connections+ processlist,并以与上一次采样的差值计算派生指标。 - 采集通过
infr:collect-db命令执行(默认每分钟调度一次,单次执行后退出)。进入页面时若最后一次采样已过期,ensureFresh()会立即补采一次。 - 页面轮询间隔:30 秒。为避免连接泄漏,采集器在
finally中调用DB::purge,并设置了 PDO 超时。
卡片状态(degraded)阈值(OpsPolicy::dbThresholds() 的默认值 — 可在 运维策略 中调整):
| 条件 | 默认阈值 | 原因标签 |
|---|---|---|
连接饱和 conn_pct ≥ |
80% | 连接饱和 |
threads_running ≥ |
40 | 高并发 |
waiting(积压) ≥ |
5 | 查询积压 |
slow_qps ≥ |
1/s | 慢查询率 |
访问权限
- 查看(页面与浮窗):demo(级别 1)及以上。浮窗是纯粹的教学内容 — 没有额外的权限门槛或审计。
- 调整数据库状态阈值:在 运维策略 中管理 — 管理员(级别 5/10 ·
infr.level:N)。 - 登记/编辑数据库采集器:采集器 管理员(级别 5/10)。口令以加密方式(Crypt)保存在采集器中,或通过
cred_ref = env:PREFIX复用.env中的一组凭据(绝不硬编码)。
故障排查与常见问题
Q. Backlog 显示"own connections only"。
统计服务器范围内积压的查询,需要数据库账号具备 PROCESS 权限。没有该权限时,只会统计你自己的连接。请参见 sql/infr_db_monitor_grant.sql(建议使用专用的监控账号)。
Q. 缓存/索引得分为空(N/A)。 派生指标是以两次采样之间的差值计算的。如果采集器刚刚启动,或计数器被重置(重启过),第一次采样就得不出分数 — 等下一个周期即可。
Q. 卡片显示 stale(没有近期采样)。
在 economy 模式下,没有控制台用户在线时会跳过采集。进入页面时 ensureFresh(45s) 会立即补采一次,但如果调度器积压,卡片可能短暂降级为 pending。若需要常态采集,请在 运维策略 中把数据库采集模式设为 always。
Q. 如何翻译/编辑浮窗文案?
教学词条集中在一个地方:resources/lang/{ko,en}/dbmon.php 的 edu 键(单一来源)。其他语言会回退到 en。
Q. 我该如何真正定位某次锁等待的成因?
在目标数据库上查看 SHOW ENGINE INNODB STATUS(TRANSACTIONS · LATEST DETECTED DEADLOCK)以及 information_schema.INNODB_TRX / data_locks,再与上面的 7 种原因表相互对照。
相关条目
- 服务 ▸ 数据库 — 这些概念出现的实时负载与结构页面
- Redis 调优概念 — 会话 (Redis) 对应的教学浮窗:内存容量、命中率、碎片率
- 数据库采集器 — 面向已注册数据库的直连采集流水线
- 运维策略 — 调整数据库状态阈值与采集模式
- 实例参数 — 真实调优取值的快照(my.cnf 等),也是 AI 调优的依据
