数据库性能监控与诊断

系统讲解数据库性能监控体系:MySQL Performance Schema / Sys Schema、慢查询分析 pt-query-digest、InnoDB Metrics、锁诊断、连接池监控与 PMM/VictoriaMetrics 可视化方案。

数据库是系统核心组件,其性能直接影响用户体验。建立完善的监控与诊断体系,是 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:
-- ...

死锁解决:

  1. 调整事务顺序(按固定顺序访问资源)
  2. 缩短事务时长
  3. 降低隔离级别
  4. 重试逻辑:ON DUPLICATE KEY UPDATE 或应用层重试

5. InnoDB 内部状态诊断

# InnoDB 完整状态
SHOW ENGINE INNODB STATUS\G

# 关键段分析

关键监控项:

段落内容健康指标
SEMAPHORES信号量争用rw-shared spins < 1000/s
TRANSACTIONS活跃事务、锁信息长事务 < 60s
FILE I/OIO 线程状态pending_reads/pending_writes 低
INSERT BUFFER AND ADAPTIVE HASH INDEXChange Buffer/AHIhash searches/s 高比例
LOGRedo Log 状态Log sequence 增长平稳
BUFFER POOL AND MEMORYBuffer Pool 使用hit rate > 95%
INDIVIDUAL BUFFER POOL INFO多实例 Buffer PoolFree 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、死锁  │
└─────────────────────────────────────────────┘

监控的最高境界是防患于未然:通过基线建立,在性能劣化变为故障前发现并处理。建立完善的监控与告警机制,将数据库故障从"被动救火"转变为"主动预防"。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「数据库」更多文章

  1. 备份恢复与高可用方案
  2. NewSQL 选型对比
  3. Redis 高级实战