数据库是系统核心组件,其性能直接影响用户体验。建立完善的监控与诊断体系,是 DBA 和 SRE 的核心能力。本文系统讲解 MySQL 性能监控的完整工具链与实践方法。
1. 监控指标体系
1.1 黄金指标(Google SRE 方法论)
| 指标类型 | 具体指标 | 说明 |
|---|---|---|
| 流量 | QPS/TPS、连接数、Threads_connected | 系统负载 |
| 延迟 | 查询耗时 P50/P95/P99、慢查询率 | 响应速度 |
| 错误 | 错误查询数、死锁数、锁等待超时 | 失败比例 |
| 饱和度 | CPU、内存、磁盘 IO、Buffer Pool 命中率 | 资源瓶颈 |
1.2 关键公式
QPS = Queries / Uptime
TPS = (Com_commit + Com_rollback) / Uptime
Buffer Pool 命中率 = 1 - (Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests)
值 > 95% 为健康
慢查询占比 = Slow_queries / Queries × 100%
应 < 1%,否则需要优化
2. Performance Schema
MySQL 5.5+ 内置的性能监控框架,低开销采集运行时数据。
2.1 启用配置
[mysqld]
performance_schema = ON
performance-schema-instrument='wait/lock/%=ON'
performance-schema-instrument='stage/%=ON'
performance-schema-instrument='statement/%=ON'
2.2 核心查询
-- 查看最消耗资源的 SQL(按总执行时间排序)
SELECT
DIGEST_TEXT as query,
COUNT_STAR as exec_count,
SUM_TIMER_WAIT/1e12 as total_latency_sec,
AVG_TIMER_WAIT/1e12 as avg_latency_sec,
MAX_TIMER_WAIT/1e12 as max_latency_sec,
SUM_LOCK_TIME/1e12 as total_lock_time_sec,
SUM_ROWS_SENT,
SUM_ROWS_EXAMINED,
FIRST_SEEN, LAST_SEEN
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 10;
-- 查看表级别的 IO 统计
SELECT
OBJECT_SCHEMA,
OBJECT_NAME,
COUNT_READ, SUM_NUMBER_OF_BYTES_READ,
COUNT_WRITE, SUM_NUMBER_OF_BYTES_WRITE,
COUNT_FETCH, SUM_TIMER_FETCH/1e12
FROM performance_schema.table_io_waits_summary_by_table
ORDER BY SUM_TIMER_WAIT DESC;
-- 查看从未使用过的索引
SELECT
OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE INDEX_NAME IS NOT NULL
AND COUNT_STAR = 0;
2.3 Sys Schema(Performance Schema 视图封装)
-- 查看全表扫描的 SQL
SELECT * FROM sys.statements_with_full_table_scans
ORDER BY rows_examined DESC;
-- 查看最慢的 SQL(75 percentile)
SELECT * FROM sys.statements_with_runtimes_in_95th_percentile;
-- 查看锁等待
SELECT * FROM sys.innodb_lock_waits\G
-- 查看冗余索引
SELECT * FROM sys.schema_redundant_indexes;
-- 查看表统计
SELECT * FROM sys.schema_table_statistics
WHERE table_schema = 'mydb' ORDER BY total_latency DESC;
3. 慢查询日志分析
3.1 配置慢查询日志
slow_query_log = 1
slow_query_log_file = /var/lib/mysql/slow.log
long_query_time = 1 # 超过1秒记录
log_queries_not_using_indexes = 1 # 记录未走索引的查询
log_slow_admin_statements = 1
log_slow_slave_statements = 1
log_throttle_queries_not_using_indexes = 10 # 每分钟最多记录10条无索引查询
3.2 pt-query-digest 深度分析
# 基础分析
pt-query-digest /var/lib/mysql/slow.log > slow_report.txt
# 过滤特定数据库
pt-query-digest --filter '$event->{db} && $event->{db} eq "mydb"' slow.log
# 按时间段分析
pt-query-digest --since '2024-01-01 00:00:00' --until '2024-01-02 00:00:00' slow.log
# 输出到库里(方便查询历史)
pt-query-digest --review h=localhost,D=percona,t=query_review \
--history h=localhost,D=percona,t=query_history slow.log
3.3 pt-query-digest 报告关键信息
Profile
Rank Query ID Response time Calls R/Call V/M Item
==== ================== ============= ===== ====== ===== ====
1 0x1234... 1500s 45.0% 5000 0.3000 0.01 SELECT users
2 0x5678... 800s 24.0% 2000 0.4000 0.02 UPDATE orders
解读:
- Response time: 该指纹 SQL 的总耗时及占比
- Calls: 执行次数
- R/Call: 单次平均耗时
- V/M: 方差均值比,越高表示执行时间越不稳定
4. 锁与死锁诊断
4.1 查看当前锁
-- InnoDB 当前事务与锁
SELECT
r.trx_id waiting_trx_id,
r.trx_mysql_thread_id waiting_thread,
r.trx_query waiting_query,
b.trx_id blocking_trx_id,
b.trx_mysql_thread_id blocking_thread,
b.trx_query blocking_query
FROM information_schema.innodb_lock_waits w
JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;
-- 查看锁明细
SELECT * FROM performance_schema.data_locks
WHERE OBJECT_NAME = 'my_table';
4.2 死锁分析
-- 查看最近死锁日志
SHOW ENGINE INNODB STATUS\G
-- ------------------------
-- LATEST DETECTED DEADLOCK
-- ------------------------
-- *** (1) TRANSACTION:
-- TRANSACTION 12345, ACTIVE 10 sec starting index read
-- mysql tables in use 1, locked 1
-- LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
-- MySQL thread id 100, OS thread handle 12345, query id 500 localhost 127.0.0.1 app
-- SELECT * FROM accounts WHERE id = 1 FOR UPDATE
-- *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
-- RECORD LOCKS space id 58 page no 3 n bits 72 index PRIMARY of table `db`.`accounts`
-- *** (2) TRANSACTION:
-- ...
死锁解决:
- 调整事务顺序(按固定顺序访问资源)
- 缩短事务时长
- 降低隔离级别
- 重试逻辑:
ON DUPLICATE KEY UPDATE或应用层重试
5. InnoDB 内部状态诊断
# InnoDB 完整状态
SHOW ENGINE INNODB STATUS\G
# 关键段分析
关键监控项:
| 段落 | 内容 | 健康指标 |
|---|---|---|
| SEMAPHORES | 信号量争用 | rw-shared spins < 1000/s |
| TRANSACTIONS | 活跃事务、锁信息 | 长事务 < 60s |
| FILE I/O | IO 线程状态 | pending_reads/pending_writes 低 |
| INSERT BUFFER AND ADAPTIVE HASH INDEX | Change Buffer/AHI | hash searches/s 高比例 |
| LOG | Redo Log 状态 | Log sequence 增长平稳 |
| BUFFER POOL AND MEMORY | Buffer Pool 使用 | hit rate > 95% |
| INDIVIDUAL BUFFER POOL INFO | 多实例 Buffer Pool | Free buffers 充足 |
6. 可视化监控方案
6.1 PMM(Percona Monitoring and Management)
# Docker 部署
docker pull percona/pmm-server:2
docker run -d \
-p 443:443 \
-v /srv/pmm-data:/srv \
--name pmm-server \
--restart always \
percona/pmm-server:2
# 客户端注册
pmm-admin config --server-insecure-tls --server-url=https://admin:admin@pmm-server:443
pmm-admin add mysql --username=pmm --password=pmm --query-source=perfschema
PMM 关键 Dashboard:
- MySQL Overview: QPS、线程、连接、Buffer Pool
- InnoDB Metrics: 事务、锁、redo log、Adaptive Hash
- Query Analytics: Top Queries、Query Details
- Compare: 多实例对比
6.2 Prometheus + Grafana(自建)
# mysqld_exporter 配置
scrape_configs:
- job_name: 'mysql'
static_configs:
- targets: ['mysql-exporter:9104']
params:
collect[]:
- global_status
- perf_schema.tablelocks
- perf_schema.file_events
- binlog
- info_schema.innodb_metrics
Grafana Dashboard 推荐:
- MySQL Overview (ID: 7362)
- MySQL InnoDB Metrics (ID: 11323)
7. 自动化告警规则
# Prometheus alert rules
groups:
- name: mysql-alerts
rules:
- alert: MySQLHighQPS
expr: rate(mysql_global_status_queries[1m]) > 10000
for: 5m
labels:
severity: warning
annotations:
summary: "MySQL QPS 过高"
- alert: MySQLSlowQueries
expr: rate(mysql_global_status_slow_queries[5m]) > 1
for: 5m
labels:
severity: warning
- alert: MySQLConnectionsHigh
expr: mysql_global_status_threads_connected / mysql_global_variables_max_connections > 0.8
for: 5m
labels:
severity: critical
- alert: MySQLReplicationLag
expr: mysql_slave_lag_seconds > 60
for: 5m
labels:
severity: critical
- alert: MySQLDeadlock
expr: increase(mysql_global_status_innodb_deadlocks[5m]) > 0
labels:
severity: warning
8. 日常巡检清单
| 检查项 | 方法 | 频率 |
|---|---|---|
| 慢查询分析 | pt-query-digest | 每日 |
| 死锁检查 | SHOW ENGINE INNODB STATUS | 每日 |
| 长事务监控 | information_schema.INNODB_TRX | 实时 |
| 索引使用 | schema_unused_indexes | 每周 |
| 表空间增长 | information_schema.tables | 每日 |
| 连接池使用率 | Threads_connected / max_connections | 实时 |
| Buffer Pool 命中率 | Innodb_buffer_pool_read_requests | 实时 |
| 复制延迟 | Seconds_Behind_Master | 实时 |
9. 总结
数据库性能监控的三层体系:
┌─────────────────────────────────────────────┐
│ 可视化层:PMM / Grafana Dashboard │
│ 趋势图、Top N、告警通知 │
├─────────────────────────────────────────────┤
│ 分析层:pt-query-digest / Performance Schema│
│ 慢查询、执行计划、锁等待、未使用索引 │
├─────────────────────────────────────────────┤
│ 基础层:SHOW [GLOBAL] STATUS / INNODB STATUS│
│ QPS、连接数、Buffer Pool、Redo Log、死锁 │
└─────────────────────────────────────────────┘
监控的最高境界是防患于未然:通过基线建立,在性能劣化变为故障前发现并处理。建立完善的监控与告警机制,将数据库故障从"被动救火"转变为"主动预防"。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。