你有没有遇到过这种场景:生产环境的MySQL突然卡得怀疑人生,业务响应慢得像蜗牛爬,运维团队急得团团转。你第一时间想到的肯定是“看慢查询日志”,于是登录服务器,打开 /var/log/mysql/slow.log,结果发现……里面空空如也,或者只有几条无关痛痒的查询。
这时候你就懵了:明明感觉数据库扛不住了,CPU飚到了90%,内存也快爆了,连接数更是蹭蹭往上涨,但慢查询日志里却抓不到“凶手”。这就像警察抓小偷,现场证据确凿,但监控录像里就是没拍到嫌疑人。
别急,这种“盲飞”的状态在运维工作中太常见了。今天我就带你把这层窗户纸捅破,用一套完整的实时监控方案——Percona PMM + Zabbix + Grafana,把MySQL的健康状况摸得清清楚楚。我们不搞那些虚头巴脑的理论,直接上干货,五步搞定从监控到排查再到优化的全流程。
第一步:为什么慢查询日志“失灵”了?
在深入工具之前,我们得先搞清楚,为什么有时候慢查询日志抓不到问题。很多初学者甚至有一定经验的运维都会踩这个坑。
慢查询日志的生效是有前提条件的。首先,你得确保 slow_query_log 是开启的。你可以登录MySQL,执行 SHOW VARIABLES LIKE 'slow_query_log'; 看看状态。如果显示 OFF,那你当然看不到任何慢查询记录。开启也很简单,SET GLOBAL slow_query_log = ON; 就行,但这个改动重启后会失效,所以最好在配置文件 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf 里永久配置:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
这里有个关键参数 long_query_time,它决定了哪些查询会被记录到慢查询日志里。默认值是10秒,这意味着只有执行时间超过10秒的查询才会被记录。如果你的问题查询大部分都在1秒到10秒之间,那它们就会被漏掉。这时候你需要适当降低这个值,比如设为0.5秒甚至0.1秒,但要注意,设得太低会导致日志量爆炸,影响性能。
但即使你设了 long_query_time = 0.1,还是可能抓不到问题。为什么?因为有些查询确实执行很快,比如0.5秒就完成了,但它们占用了大量的CPU或锁资源,导致其他查询排队等待。这种情况下,慢查询日志里记录的是这0.5秒的查询,但真正的问题在于它引发了大量的锁等待,而这些锁等待信息并不会出现在慢查询日志里。
还有一个常见情况是,查询被缓存了。MySQL的查询缓存(虽然MySQL 8.0已经移除了)或者连接池的缓存,会让相同的查询直接返回结果,不经过真正的执行引擎。这时候,你看到的执行时间很短,但实际上底层可能发生了复杂的锁竞争或资源争抢。
所以,当我们说“慢查询日志抓不到问题”时,通常指的是:问题不是单一的“慢SQL”,而是由CPU飙升、内存不足、连接数爆满、锁等待等多种因素交织而成的性能瓶颈。单一维度的监控自然看不到全貌。
第二步:搭建Percona PMM——MySQL的“贴身保镖”
Percona Monitoring and Management(PMM)是由Percona公司开发的一套开源监控解决方案,专门为数据库监控设计,特别是MySQL。它比Zabbix更专业,比Grafana更集成,是目前MySQL监控的最佳实践之一。
2.1 部署PMM Server
PMM Server本身可以通过Docker快速部署。假设你已经安装了Docker,执行以下命令:
docker run -d \
--name pmm-server \
-v /opt/pmm-data:/srv \
-p 443:443 \
--restart always \
percona/pmm-server:2
部署完成后,访问 https://<your-server-ip>,默认账号是 admin,密码也是 admin(首次登录会要求修改密码)。
2.2 安装PMM Client
在MySQL服务器上安装PMM Client,用于采集数据并发送到Server:
# CentOS/RHEL
yum install -y https://www.percona.com/redir/downloads/percona-monitoring-and-release/RPM/redhat/7/x86_64/percona-release-1.0-11.noarch.rpm
yum install -y pmm2-client
# Ubuntu/Debian
apt install -y https://www.percona.com/redir/downloads/percona-monitoring-and-release/deb/pool/percona-r/percona-release/percona-release_1.0-11.all.deb
apt install -y pmm2-client
安装完成后,配置Client指向Server:
pmm-admin config --server-insecure-tls --server-url=https://admin:password@<your-server-ip>
2.3 添加MySQL服务监控
pmm-admin add mysql --user=root --password=your_password --port=3306
这一步很关键。PMM Client会自动采集MySQL的QPS、TPS、连接数、CPU使用率、内存使用、InnoDB Buffer Pool命中率、慢查询数量等几十项指标,并发送到PMM Server。
2.4 查看PMM Dashboard
登录PMM Web界面,在 MySQL Overview 页面,你可以看到一个全景式的Dashboard,包括:
- MySQL Top SQL:按执行次数、总时间、锁定时间等维度排序的SQL。
- MySQL Connections:活跃连接、空闲连接、最大连接数等。
- MySQL CPU:CPU使用率的详细分解。
- MySQL Memory:内存使用情况。
- MySQL Queries:QPS、TPS趋势。
- MySQL Locks:锁等待情况。
特别是 MySQL Top SQL 页面,它不仅仅记录慢查询,而是统计所有查询的执行情况,包括那些执行时间不长但执行频率极高的查询。这就是为什么它能抓到“慢查询日志抓不到”的问题——因为它看的是全局,而不是单一的超时阈值。
第三步:Zabbix的深度挖掘——系统层面的“放大镜”
虽然PMM在数据库层面做得非常出色,但它对操作系统层面的监控相对较弱。比如,当CPU飙升时,是MySQL进程本身在干活,还是某个其他进程(比如备份任务、日志轮转)在抢占CPU?MySQL的内存是否已经被OS层压缩或换出?这些细节PMM不一定能直接告诉你。
这时,Zabbix就派上用场了。Zabbix是一个通用的IT基础设施监控工具,它可以采集MySQL服务器所在主机的所有系统指标。
3.1 Zabbix Agent安装
在MySQL服务器上安装Zabbix Agent:
# CentOS/RHEL
rpm -Uvh https://repo.zabbix.com/zabbix/6.0/rhel/7/x86_64/zabbix-release-6.0-2.el7.noarch.rpm
yum install -y zabbix-agent
# Ubuntu/Debian
wget https://repo.zabbix.com/zabbix/6.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_6.0-2+ubuntu20.04_all.deb
dpkg -i zabbix-release_6.0-2+ubuntu20.04_all.deb
apt update
apt install -y zabbix-agent
编辑配置文件 /etc/zabbix/zabbix_agentd.conf,设置Server地址:
Server=<your-zabbix-server-ip>
ServerActive=<your-zabbix-server-ip>
Hostname=<your-mysql-server-hostname>
重启Agent:
systemctl restart zabbix-agent
systemctl enable zabbix-agent
3.2 配置MySQL项监控
Zabbix默认不包含MySQL的深层监控,需要额外配置。可以通过 UserParameter 自定义监控项,或者使用Percona提供的Zabbix模板。Percona为Zabbix提供了专门的MySQL监控模板,可以在PMM Server上导出,也可以从GitHub获取。
一个简单的自定义监控项示例,用于监控MySQL的连接数:
UserParameter=mysql.connections,/usr/bin/mysql -u<user> -p<password> -e "SHOW STATUS LIKE 'Threads_connected';" | awk '{print $2}'
但更推荐使用Percona的模板,它已经包含了数百个MySQL相关的监控项,包括:
mysql.status[Connections]:总连接数mysql.status[Threads_connected]:当前连接数mysql.status[Threads_running]:活跃线程数mysql.status[Innodb_buffer_pool_pages_free]:Buffer Pool空闲页数mysql.status[Innodb_row_lock_time]:行锁等待时间mysql.status[Innodb_row_lock_waits]:行锁等待次数
3.3 主机与模板关联
在Zabbix Web界面,找到你的MySQL主机,点击 Templates,链接并导入 Percona MySQL Server 模板。之后,Zabbix会自动开始采集各项指标,并在 Latest Data 中查看。
第四步:Grafana的统一视图——让数据“说话”
Zabbix和PMM各自有各自的Dashboard,但这样会导致信息割裂:你看PMM时看不到CPU历史,看Zabbix时又看不到MySQL的详细SQL统计。这时候,Grafana就是那个“粘合剂”,它可以从多个数据源(包括PMM的Prometheus后端和Zabbix)拉取数据,在一个统一的Dashboard中展示。
4.1 安装Grafana
# CentOS/RHEL
yum install -y grafana
# Ubuntu/Debian
apt install -y apt-transport-https
wget -q -O - https://packages.grafana.com/gpg.key | apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" > /etc/apt/sources.list.d/grafana.list
apt update
apt install -y grafana
systemctl start grafana-server
systemctl enable grafana-server
4.2 添加数据源
登录Grafana后,依次添加以下数据源:
- Prometheus:PMM Server默认使用Prometheus作为后端,地址通常是
http://<pmm-server-ip>:9090。 - Zabbix:如果要用Zabbix的数据,需要安装Zabbix插件,并配置Zabbix API地址和账号。
4.3 导入MySQL Dashboard
Grafana官方和Percona都提供了现成的MySQL Dashboard,可以直接导入使用。比如,Percona的MySQL Dashboard ID是 893,在Grafana的 Dashboard -> Import 中,输入ID即可。
导入后,你会看到一个包含多个面板的Dashboard,包括:
- CPU Usage:MySQL进程的CPU使用率,以及系统整体CPU使用率。
- Memory Usage:MySQL使用的内存,以及OS层面的内存情况。
- Connection Count:连接数趋势,以及当前连接数的分布。
- Query Stats:QPS、TPS、慢查询数量。
- Lock Waits:锁等待时间和次数。
- InnoDB Buffer Pool:命中率、脏页比例等。
4.4 自定义报警规则
Grafana支持设置报警规则,当某个指标超过阈值时,发送通知到钉钉、企业微信、Slack或邮件。例如,当 mysql.threads_connected 超过最大连接数的80%时,触发告警。
在Grafana中,编辑Dashboard中的面板,点击 Alert 标签,添加条件:
Condition: B > 80%
For: 5m
No data or error: OK
这样,当连接数持续5分钟超过80%时,就会发送告警。
第五步:从监控到排查——5步锁定性能瓶颈
好了,监控体系已经搭建完毕,数据也在源源不断地流入。但当问题真正发生的时候,你该怎么从海量数据中快速定位问题呢?下面我分享一个实战案例,带你走完这五步排查流程。
场景描述
某天下午,业务部门反馈系统变慢,数据库连接超时。你登录服务器,发现:
- CPU使用率95%以上
- 连接数接近1000(最大连接数1000)
- 慢查询日志几乎为空
- 内存使用率80%左右
第1步:看PMM Top SQL,找出“隐形杀手”
打开PMM的 MySQL Top SQL 页面,按 Total Time 排序。你会发现,排在前面的并不是那些执行时间很长的查询,而是一些执行时间只有0.2秒,但执行频率极高的查询,每分钟执行上千次。
这些查询的共同特点是:都在同一张表上执行 UPDATE 操作,并且没有使用索引。虽然每次执行很快,但由于频率极高,它们累积占用了大量的CPU时间,并且引发了频繁的锁竞争。
第2步:看Zabbix CPU监控,确认瓶颈来源
切换到Zabbix,查看CPU使用率的历史趋势。你会发现,CPU使用率在问题发生前半小时就开始缓慢上升,而且主要是用户态CPU(us)占用高,说明是MySQL进程本身在大量计算,而不是I/O等待(wa)或中断(irq)。
进一步查看MySQL进程的CPU热图,发现热点集中在某个SQL执行计划上。
第3步:看Grafana连接数面板,发现连接池耗尽
在Grafana中,连接数面板显示,活跃连接数在问题发生前就已经达到了900以上,而且大部分连接都处于 Sleep 状态,只有少数几个是 Query 状态。这说明应用层没有正确释放连接,或者连接池配置不合理,导致连接被大量占用。
第4步:查看锁等待信息,找到锁根源
在PMM的 MySQL Locks 面板,或者通过执行 SHOW ENGINE INNODB STATUS\G,可以看到当前的锁等待情况。你会发现,有大量线程在等待同一个表的行锁,而这个锁正是由第1步中找出的那个高频UPDATE查询持有的。
第5步:优化SQL与连接配置,解决问题
基于以上分析,我们采取了以下措施:
- 优化SQL:给UPDATE语句涉及的字段添加索引,减少锁的范围。同时,将大事务拆分为小事务,减少锁持有时间。
- 调整连接池配置:在应用层,调整连接池的最大连接数为200,最小空闲连接数为20,避免连接数无限增长。
- 调整MySQL参数:将
max_connections从1000调整为300,wait_timeout从28800秒调整为300秒,及时释放空闲连接。
优化后,重新观察监控数据:CPU使用率下降到30%以下,连接数稳定在150左右,慢查询日志中开始出现那些被优化的SQL,但执行时间已经缩短到毫秒级,业务响应速度恢复正常。
结语:监控不是目的,可观测性才是
这套方案的核心思想,不是简单地“部署几个工具”,而是建立一个可观测性体系。监控(Monitoring)告诉你“发生了什么”,而可观测性(Observability)让你理解“为什么发生”。
Percona PMM提供了数据库层面的深度洞察,Zabbix覆盖了操作系统层面的基础指标,Grafana则将这些数据整合成一个统一的视图。三者互补,缺一不可。
当然,工具只是手段,真正的价值在于运维人员的分析能力和经验。当看到CPU飙升时,你能否迅速联想到锁竞争?当连接数爆满时,你能否判断是连接泄漏还是正常业务高峰?这些都需要在实践中不断积累。
希望这篇长文能帮你建立起一套完整的MySQL性能排查思路。记住,下次再遇到“慢查询日志抓不到问题”的情况时,别慌,打开你的监控大屏,让数据告诉你真相。
