MySQL 性能监控实战:从零搭建 Prometheus + Grafana 监控告警体系(附排查 SOP)

📌 今日关键词:性能监控、PMM、Prometheus、Grafana、慢查询、告警、指标体系

大家好,我是数据库小学妹 👋

前面我们学习了锁机制、MVCC、慢查询诊断这些"事后分析"的技术。但你知道

"数据库目前处于什么状态?QPS 多少?Buffer Pool 命中率是什么水平吗?"

听到QPS、命中率这些词是不是很懵?所以SQL写得好是一回事,知道数据库在"跑"什么状态是另一回事。

今天把我从零学监控的经历整理出来,新手也能从零搭建。


一、为什么需要监控?

先讲一个案例:

某平台电商大促,系统突然变慢。开发找运维,运维找 DBA,DBA 说"等我连上去看看"。这一套流程走了 15 分钟,用户已经跑到竞品下单了。

如果有一套监控,慢查询超过阈值就自动告警,早在用户察觉之前就能介入。

监控能帮你做什么?

目的 具体场景
实时感知 QPS 突然掉底、连接数打满,立刻知道
故障预警 Buffer Pool 命中率下降,提前扩容
排障加速 出问题时不用"我觉得慢了",直接看指标
容量规划 过去三个月 QPS 趋势,决定什么时候扩容

数据这东西不会说谎。嘴上说"不慢"没用,监控图表才说了算


二、监控的五维指标体系

搞监控第一件事不是选工具,而是搞清楚该看什么。我把 MySQL 的核心指标分成五个维度:

🧠 维度 1:资源使用

指标 含义 告警阈值参考
CPU 使用率 MySQL 进程 CPU 占用 > 80% 持续 5 分钟
内存使用 InnoDB Buffer Pool 占用 实际使用 > 可用内存 90%
磁盘 IO 每秒读写次数 IOPS 写 IO 延迟 > 20ms
磁盘空间 数据目录可用空间 < 20%
网络吞吐 每秒收发流量 接近带宽上限

这些指标别在 MySQL 里查,用系统命令更快:

bash 复制代码
# CPU
top -p $(pgrep mysqld) -n1

# 内存
free -h

# 磁盘 IO
iostat -x 1 3

# 磁盘空间
df -h /var/lib/mysql

🧠 维度 2:连接与线程

sql 复制代码
-- 当前连接数 vs 最大连接数
SHOW VARIABLES LIKE 'max_connections';
SHOW STATUS LIKE 'Threads_connected';

-- 查看连接来源和状态
SELECT user, host, db, command, time, state
FROM information_schema.processlist
WHERE command != 'Sleep'
ORDER BY time DESC;

连接池满了最常见的问题------用户报"无法连接数据库",大概率是连接数被打满。

🧠 维度 3:查询性能

sql 复制代码
-- QPS 近似计算(两次查询间隔内的差值)
SHOW STATUS LIKE 'Questions';
SHOW STATUS LIKE 'Uptime';

-- 慢查询数量
SHOW STATUS LIKE 'Slow_queries';

-- 全表扫描次数
SHOW STATUS LIKE 'Select_scan';

关注三个关键指标:

  • QPS 突降 → 可能有锁等待
  • Slow_queries 飙升 → SQL 性能退化或缺少索引
  • Select_scan 增长 → 全表扫描增多

🧠 维度 4:InnoDB 引擎

sql 复制代码
-- Buffer Pool 命中率(核心指标!)
SHOW STATUS LIKE 'Innodb_buffer_pool_read%';
-- 公式:1 - (Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests) × 100%
-- 目标:> 99%

-- 行锁等待
SHOW STATUS LIKE 'Innodb_row_lock_waits';
SHOW STATUS LIKE 'Innodb_row_lock_time';

-- 脏页比例
SHOW STATUS LIKE 'Innodb_buffer_pool_pages%';

Buffer Pool 命中率是我最关注的指标之一。低于 98% 说明内存不够用了,该扩了。

🧠 维度 5:主从同步

sql 复制代码
SHOW SLAVE STATUS\G
-- 关注两个字段:
-- Seconds_Behind_Master(延迟)
-- Slave_IO_Running / Slave_SQL_Running(必须都是 Yes)

三、三层工具选型

🟢 新手级:PMM(Percona Monitoring and Management)

PMM 是 Percona 开源的监控平台,基于 Prometheus + Grafana,开箱即用。

安装(docker 一把梭):

bash 复制代码
# 拉取 PMM Server
docker run -d -p 80:80 -p 443:443 \
  --name pmm-server \
  percona/pmm-server:2

# 在 MySQL 机器上安装 PMM Client
yum install pmm2-client
# 或
apt-get install pmm2-client

# 注册客户端到服务端
pmm-admin config --server-insecure-tls --server-url=https://admin:admin@<pmm-server-ip>

然后刷浏览器打开 PMM 面板,你会看到一个详细的仪表盘------QPS、连接数、Buffer Pool 命中率、慢查询趋势,全在里面。

🌐 进阶级:搭建你自己的 Grafana 面板

PMM 好用,但如果你已经有 Prometheus 体系,自己搭一套更灵活。

架构:

复制代码
MySQL → mysqld_exporter → Prometheus → Grafana

步骤 1:安装 mysqld_exporter

bash 复制代码
# 创建监控用户
CREATE USER 'exporter'@'%' IDENTIFIED BY 'password';
GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'%';

# 安装运行
wget https://github.com/prometheus/mysqld_exporter/releases/latest
./mysqld_exporter --mysqld.username=exporter --mysqld.password=password

步骤 2:Prometheus 配置

yaml 复制代码
# prometheus.yml
- job_name: 'mysql'
  static_configs:
    - targets: ['your-mysql-host:9104']

步骤 3:Grafana 仪表盘

Grafana 有现成的 MySQL 仪表盘模板:

  • Dashboard ID: 7362(MySQL Overview)
  • Dashboard ID: 9623(MySQL InnoDB Metrics)

导入就能用,不用从零画图。

🔧 兜底级:纯 SQL 脚本

不是所有环境都能装监控工具。开发环境、内网测试库有时候只能自己跑 SQL 看:

sql 复制代码
-- 一键快照脚本(适合做定时任务)
SELECT NOW() AS snapshot_time;

SELECT '--- QPS ---' AS indicator;
SELECT ROUND(QUESTIONS / UPTIME, 2) CURRENT_QPS,
  ROUND(QUESTIONS / UPTIME, 2) AVG_QPS
FROM (
  SELECT VARIABLE_VALUE AS QUESTIONS FROM performance_schema.global_status WHERE VARIABLE_NAME='Questions'
) q,
(
  SELECT VARIABLE_VALUE AS UPTIME FROM performance_schema.global_status WHERE VARIABLE_NAME='Uptime'
) u;

SELECT '--- Buffer Pool 命中率 ---' AS indicator;
SELECT
  CONCAT(ROUND((1 - reads / requests) * 100, 2), '%') AS buffer_hit_rate
FROM (
  SELECT
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_reads') AS reads,
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_read_requests') AS requests
) t;

SELECT '--- 连接数 ---' AS indicator;
SELECT
  (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='Threads_connected') AS current,
  (SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME='max_connections') AS max;

放到 crontab 里每 5 分钟跑一次,输出到文件,自己整理看趋势。


四、告警规则怎么设?

有监控没告警,等于闭着眼睛开车。生产环境最必要的几条告警:

告警项 条件 级别
连接数过多 当前连接 > 最大连接 × 0.8 P1(紧急)
慢查询骤增 5 分钟内慢查询 > 50 P2(重要)
Buffer Pool 命中率下降 < 95% 持续 10 分钟 P2(重要)
磁盘空间不足 < 10% 可用 P1(紧急)
主从延迟 > 10 秒持续 5 分钟 P2(重要)
QPS 突降 下降 > 50% 持续 3 分钟 P1(紧急)

告警通知渠道

  • P1 → 短信 + 电话 + IM 群通知
  • P2 → IM 群通知 + 邮件

别把所有告警都设成 P1,不然会被"狼来了"效应淹没。


五、监控实战 checklist

这是我学监控的计划,按这个顺序来对新手友好:

Phase 1:先看(第 1 周)

bash 复制代码
# 每天跑一遍,感受数据库的"脉搏"
SHOW STATUS;
SHOW ENGINE INNODB STATUS\G
SHOW PROCESSLIST;

不用监控工具,每天手动跑几次这些命令,感受一下 QPS、连接数、慢查询的变化。先建立"手感"

Phase 2:再看(第 2-3 周)

  • 安装 PMM,导入默认仪表盘
  • 学会看 QPS 趋势图、慢查询列表
  • 每天看一眼 Buffer Pool 命中率

Phase 3:会报警(第 4 周)

  • 配置连接数告警(P1)
  • 配置慢查询告警(P2)
  • 确认告警通道畅通

Phase 4:能排障(持续)

  • 梳理常见性能问题的监控排查路径
  • 把排查经验写成 SOP

六、我的排查 SOP:三步定位法

当告警响起,按这三步来:

第一步:全局扫一眼

复制代码
QPS ↓ 50% → 继续 ↓
连接数 ↑ 300% → 连接池打满 → 可能是慢查询导致连接堆积
慢查询 ↑ 10x → 确认!有慢查询 → 进入第二步

第二步:定位慢查询元凶

sql 复制代码
-- 查当前正在跑的慢 SQL
SELECT 
    trx_mysql_thread_id AS thread_id,
    trx_query AS current_sql,
    TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS running_seconds
FROM information_schema.innodb_trx
WHERE trx_state = 'RUNNING'
ORDER BY running_seconds DESC;

-- 或者从慢查询日志查历史
-- 先确认慢查询日志是否开启
SHOW VARIABLES LIKE 'slow_query_log';

-- 分析最近 50 条慢查询
mysqldumpslow -t 50 /var/lib/mysql/slow.log

第三步:分析慢查询

用 EXPLAIN 看执行计划(这个我们之前的文章详细讲过),定位是全表扫描还是索引没走对。

这套流程在大促值班时用过一次:凌晨 2 点 QPS 掉底告警,顺着三步走,3 分钟定位到一个缓存过期导致的 full join,扩容后恢复正常。


七、今日学习心得

  1. 监控不是装完工具就完事,指标体系设计比工具重要
  2. 五个维度(资源/连接/查询/引擎/主从)覆盖 90% 的性能问题
  3. PMM 适合新手快速上手,Prometheus + Grafana 适合有基础的自己定制
  4. 告警要分级,别把 P2 的事设成 P1
  5. 先建立手感,再上工具------顺序很重要

👋 我是 数据库小学妹 一个用设计师思维学数据库的转行人。我们一起,用监控让数据库问题早发现、早解决!💕


本文示例基于 MySQL 8.0 + InnoDB。不同环境配置可能有差异,请结合实际调整。

相关推荐
阿坤带你走近大数据2 小时前
mysql从5.7升级到8.0后ONLY_FULL_GROUP_BY是升级后应用报错的第一大原因
数据库·mysql
devilnumber3 小时前
MySQL 部门表:树结构 (自关联) vs 非树结构 (扁平化 / 冗余字段)
数据库·mysql
User_芊芊君子3 小时前
一条命令搞定 mysql_exporter 部署,Shell 脚本把重复配置这件事自动化了
android·mysql·自动化
fengxin_rou3 小时前
【MySQL 三大日志深度解析】:redo log、undo log、binlog 作用与两阶段提交原理
数据库·mysql·日志·redo log
电商API_180079052474 小时前
反向海淘是什么?现状如何?未来趋势如何?
数据库·人工智能·笔记·性能优化·数据挖掘·网络爬虫
唐青枫4 小时前
别让 NULL 拖垮结果:MySQL COALESCE 空值兜底实战详解
sql·mysql
wand codemonkey5 小时前
SpringbootWeb【入门】+MySQL【安装】+【DataDrip安装 】+【连接MySQL】
java·mysql·mybatis
廿一夏13 小时前
MySql存储引擎与索引
数据库·sql·mysql
敲个大西瓜16 小时前
Java项目常用数据归档方式
mysql