综合 MySQL 指标报出异常后:从 OpenTelemetry 面板走到 Performance Schema 证据

2026-10-27 21:03:27

MySQL 指标报出异常后:从 OpenTelemetry 面板走到 Performance Schema 证据

前三篇把 MySQL 原生遥测导出到 Prometheus、按 DBA 常见问题组织指标、在 Grafana 搭了一个 “MySQL Telemetry Overview” 仪表盘,覆盖六个问题:连接是否被拒、负载是否变化、buffer pool 是否有效服务读、写路径是否有压力、事务是否在等行锁、主机是否参与问题。这一篇讲症状出现时怎么用这张面板。来源:blogs.oracle.com/mysql。

指标面板的作用是发现变化、给出时间点、缩小范围;它不会自动告诉你根因。下一步要回到 MySQL 收集证据:Performance Schema、server status、查询分析,以及平台层(CPU、磁盘、网络)。

症状到证据的对照

症状先看指标再收的证据
连接上升或被拒threads_connected、errors_max_connections_total、questions_totalmax_connections、连接与线程状态、应用连接池行为
负载上升且响应变慢questions_total、threads_running、CPU活动语句与语句摘要、慢日志
读性能变化read_requests_total、reads_total、buffer pool 命中率、磁盘读时间buffer pool 大小、执行计划与访问模式、工作集变化
写入变慢os_log_written_total、log_waits_total、os_log_pending_fsyncs、磁盘写时间redo 与提交行为、存储、写负载与事务大小
事务等待row_lock_current_waits、row_lock_waits_totaldata_lock_waits、data_locks、当前语句、事务持有者

需求上升开始排队

把 5 分钟窗口的请求速率与 threads_running、CPU 放在同一时间轴上看:

rate(questions_total[5m])

负载上升但 threads_running 和延迟都正常,说明 MySQL 还跟得上。若 threads_running 持续走高,再根据 cache、写路径、锁、主机四块面板决定往哪个方向查。

当前正在执行什么:

SELECT THREAD_ID, EVENT_ID, EVENT_NAME, TIMER_WAIT, SQL_TEXT
FROM performance_schema.events_statements_current
WHERE SQL_TEXT IS NOT NULL
ORDER BY TIMER_WAIT DESC;

看更长周期的负载变化,用 digest 汇总:

SELECT DIGEST_TEXT, COUNT_STAR,
  ROUND(SUM_TIMER_WAIT / 1000000000000, 2) AS total_latency_s,
  ROUND(AVG_TIMER_WAIT / 1000000000, 2) AS avg_latency_ms,
  SUM_ROWS_EXAMINED, QUERY_SAMPLE_TEXT
FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST_TEXT IS NOT NULL
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 10;

threads_running 高不等于配置有问题:低效 SQL、锁等待、CPU 饱和、存储延迟、需求突变都会给出同一个信号。

行锁等待:指标只说明“有人在等”

指标不会告诉你谁阻塞了谁、锁了什么、SQL 是什么。row_lock_current_waits 表示当前是否存在争用,rate(row_lock_waits_total[5m]) 表示窗口内是否发生过等待事件:

row_lock_current_waits
rate(row_lock_waits_total[5m])

任一指标上升并伴随应用延迟,要立刻抓证据,因为阻塞关系可能在排查开始前就消失了。

先拿阻塞关系:

SELECT REQUESTING_ENGINE_TRANSACTION_ID AS waiting_transaction,
  REQUESTING_THREAD_ID AS waiting_thread,
  BLOCKING_ENGINE_TRANSACTION_ID AS blocking_transaction,
  BLOCKING_THREAD_ID AS blocking_thread,
  REQUESTING_ENGINE_LOCK_ID AS waiting_lock,
  BLOCKING_ENGINE_LOCK_ID AS blocking_lock
FROM performance_schema.data_lock_waits;

再用线程 ID 取当前 SQL:

SELECT THREAD_ID, EVENT_ID, EVENT_NAME, TIMER_WAIT, SQL_TEXT
FROM performance_schema.events_statements_current
WHERE THREAD_ID IN (/* 等待方与阻塞方的 thread ID */);

把结果拼起来,判断持有会话、语句、表、索引和事务边界。补救方式取决于证据:查询设计、事务范围、并发模式、隔离级别、索引都可能相关。锁等待速率不是“改某个 server 变量”的指令。

常见错误

  • 只看一个指标就下结论。
  • 把相关当成证明。
  • 没确认工作负载或阻塞证据就改配置。
  • 没有基线,却用固定阈值判断。
  • 等症状结束了才去抓瞬时证据,此时 data_lock_waits 和 events_statements_current 往往已经空了。
复制全文 生成海报 MySQL 运维 监控

推荐文章

程序员茄子在线接单