6.7.2 关键性能指标与瓶颈识别

本节聚焦MySQL性能指标体系与瓶颈识别方法,建立“指标—症状—根因—验证”的闭环,并提供可执行的观测、排错与练习示例。

一、原理草图:从指标到根因的识别链路

文章图片

二、关键性能指标(KPI)体系与含义
- 吞吐指标:QPS、TPS、Com_select/insert/update/delete、Com_commit/rollback
用途:衡量业务负载强度与读写结构。
- 响应指标:P50/P95/P99、慢查询比例、平均查询时间
用途:衡量用户体验与尾延迟。
- 并发指标:Threads_connected、Threads_running、Max_used_connections
用途:评估连接压力与排队情况。
- 锁与事务指标:InnoDB_row_lock_time、Innodb_deadlocks、锁等待次数
用途:识别热点资源与长事务。
- 缓存与内存指标:Buffer Pool命中率、临时表落盘比例
用途:判断内存是否成为瓶颈。
- IO指标:磁盘IOPS、读写延迟、Innodb_log_waits
用途:判断IO瓶颈与日志写入压力。
- 复制指标:Seconds_Behind_Master、Relay_Log_Space
用途:识别复制延迟与回放堆积。

三、常用观测数据来源与安装准备
- MySQL内置:SHOW GLOBAL STATUSSHOW ENGINE INNODB STATUS
- 性能视图:performance_schemasys
- 系统侧:vmstatiostatsartop/htop
- 日志侧:慢查询日志、错误日志、审计日志

安装与启用示例(sys库与性能视图)

# 1) 确认performance_schema已启用(MySQL 5.7+默认开启)
mysql -uroot -p -e "SHOW VARIABLES LIKE 'performance_schema';"

# 2) 安装sys库(如果未安装)
mysql -uroot -p < /usr/share/mysql/sys.sql

# 3) 验证sys库
mysql -uroot -p -e "SHOW DATABASES LIKE 'sys';"

命令解释:
- performance_schema:用于采集SQL、锁、IO等细粒度指标
- sys库:提供友好的视图与诊断查询

四、关键命令与示例(含解释与预期效果)

1)系统层观测:CPU/内存/IO

# CPU与上下文切换
vmstat 1 5
# 解释:us/sy高表示CPU繁忙;cs高表示上下文切换频繁

# IO延迟与利用率
iostat -x 1 5
# 解释:await高表示IO延迟高;%util接近100说明磁盘繁忙

2)MySQL层状态变量

-- 连接与并发
SHOW GLOBAL STATUS LIKE 'Threads%';

-- 事务与锁
SHOW GLOBAL STATUS LIKE 'Innodb_row_lock%';
SHOW GLOBAL STATUS LIKE 'Innodb_deadlocks';

-- 缓冲池命中率计算
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';

命令解释:
- Threads_running高且持续,表示并发压力或锁等待
- Innodb_buffer_pool_reads增多,表示缓存命中率下降

3)热点SQL与慢查询

-- sys库查看Top SQL(总耗时)
SELECT * FROM sys.statement_analysis
ORDER BY total_latency DESC LIMIT 5;

-- 启用慢查询日志(示例配置)
-- /etc/my.cnf
[mysqld]
slow_query_log=ON
long_query_time=1
slow_query_log_file=/var/log/mysql/slow.log

预期效果:
- sys.statement_analysis能快速定位高成本语句
- 慢日志用于还原SQL特征与执行时间分布

4)锁等待定位

-- sys库查看锁等待
SELECT * FROM sys.innodb_lock_waits;

-- 结合进程列表
SHOW FULL PROCESSLIST;

排错思路:
- 若锁等待集中在同一表或索引,优先排查长事务与热点更新

五、瓶颈识别示例(带验证步骤)

示例1:QPS增长但响应变慢(疑似IO瓶颈)

# 观察IO延迟
iostat -x 1 3

# 观察MySQL IO等待
mysql -uroot -p -e "SHOW GLOBAL STATUS LIKE 'Innodb_log_waits';"

判断逻辑:
- await高、%util接近100,且Innodb_log_waits增长,说明IO成为瓶颈
验证方法:
- 临时提升innodb_flush_log_at_trx_commit到2(仅用于验证)

SET GLOBAL innodb_flush_log_at_trx_commit=2;

预期效果:事务等待下降、P95延迟下降(注意持久性风险,仅测试)

示例2:Threads_running持续升高(疑似锁争用)

SHOW GLOBAL STATUS LIKE 'Threads_running';
SELECT * FROM sys.innodb_lock_waits;

验证方法:
- 对疑似热点表执行EXPLAIN与执行计划分析

EXPLAIN SELECT * FROM orders WHERE user_id=1001 FOR UPDATE;

预期效果:
- 若未命中索引或范围扫描大,锁持有时间延长

六、故障排查清单(可执行步骤)
1. 确认异常:与基线对比,确认波动幅度
2. 系统层排查vmstat + iostat确认CPU/IO瓶颈
3. MySQL层排查SHOW GLOBAL STATUS确认连接/锁/缓存
4. SQL层排查sys.statement_analysis与慢日志定位Top SQL
5. 验证与复现:临时参数调整或隔离压测确认根因

七、实操练习
1. 采集并计算Buffer Pool命中率
- 公式:1 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests

SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';
  1. 找出总耗时最高的Top 3 SQL
SELECT * FROM sys.statement_analysis
ORDER BY total_latency DESC LIMIT 3;
  1. 模拟锁等待并定位
-- 会话1
BEGIN;
UPDATE t_order SET status='PAID' WHERE id=1;

-- 会话2
UPDATE t_order SET status='CANCEL' WHERE id=1;

预期效果:会话2阻塞,sys.innodb_lock_waits出现记录

八、实践建议
- 建立基线与阈值告警,避免事后排障
- 指标分层与SQL层结合分析,避免“头痛医头”
- 优先处理高影响、高频问题,再优化长尾问题