简介:面向运维与云计算工程师的一套普罗米修斯(Prometheus)监控MySQL详细文档,系统梳理了从环境准备到报警通知的完整链路。内容首先讲解如何在Linux环境下的MySQL中创建专用监控账号并授予SELECT、PROCESS、SUPER等必要权限;随后介绍mysql_exporter二进制包的下载、解压、.my.cnf连接配置,以及通过systemd实现服务托管与开机自启;再说明Prometheus添加监控目标的两种方式,即静态配置和服务发现,并针对容器场景给出Docker服务发现的接入说明;最后讲解Alertmanager处理告警的配置方法。所有步骤均基于实际实验环境编写,包含具体命令、参数和验证方法,有助于读者快速部署一套可用的MySQL监控系统。资源为单个Word文档,压缩包大小约6MB,已有1275人学习使用。对于需要掌握Prometheus监控数据库的运维和云计算人员,是一份性价比很高的参考资料。
1. Prometheus监控MySQL:从一条慢查询到告警通知,中间隔着三层配置
很多团队把Prometheus监控MySQL当成“装个exporter就完事”的活,实际落地时才发现:采集起来了,看板上的指标读不懂、告警要么不响要么天天误报。这套方案的本质是三条链路的协作——mysqld_exporter把MySQL的status变量和performance_schema数据转成Prometheus指标格式,Prometheus负责定时拉取、存储并计算告警规则,最后由看板工具和告警通道把状态可视化、把异常推出去。
适合正在选型或者已经装了但没跑通的运维和开发阅读。下文按数据链路、部署步骤、告警规则、避坑细节的顺序展开,每个命令都标注参数含义和常见误区,照着走完一遍,至少能把基础监控、告警和排查路径完整搭起来。
2. 先理解数据链路:mysqld_exporter的采集原理与指标口径
很多人配置时直接照抄网上的命令,一遇到指标对不上就懵了。这一章先把链路拆开讲清楚:数据从哪里来、指标名怎么读、类型为什么重要。搞懂这三件事,后面配置告警和排查问题才有依据。
2.1 为什么是mysqld_exporter而不是自研脚本或其它采集器
Prometheus采用主动拉取模型,监控目标必须暴露一个符合文本格式的/metrics HTTP端点。mysqld_exporter就是为MySQL准备这个端点的标准组件。它周期性连接MySQL,执行一组预设查询,把结果转换成带标签的指标,再以Prometheus认识的文本格式暴露出去。
自研脚本的问题在于:指标类型要自己维护,counter还是gauge直接决定告警表达式怎么写;标签体系要自己设计,采集失败要自己处理重试和超时;Prometheus重启后还要考虑指标是否出现断层。mysqld_exporter把这些都封装好了,而且使用官方维护的驱动实现连接,协议和数据类型转换上省掉很多麻烦。
另一个常见选型是pushgateway加定时脚本。这个组合临时补救可以,长期会有致命问题:目标挂了,Prometheus仍然能从pushgateway读到旧数据,mysql_up不会变成0,存活性告警形同虚设。拉取模式下exporter停止响应后,Prometheus会自动标记target为DOWN,数据链路才完整。这也是我在选型时坚持用exporter直连的原因。
要不要上更重型的数据库管理平台?小规模实例或单一业务集群没必要,额外的基础设施维护成本比监控本身还高。mysqld_exporter加Prometheus,两个组件就能覆盖绝大多数MySQL集群的监控需求。
2.2 指标从哪里来:状态变量、系统表与命名规则
mysqld_exporter的数据来源分两路。第一路是SHOW GLOBAL STATUS和SHOW GLOBAL VARIABLES,负责全局运行状态和配置参数,比如当前连接数、最大连接数、运行时长、慢查询累计计数。第二路是information_schema和performance_schema里的表,提供更细粒度的进程列表、表锁、语句统计和InnoDB状态。
指标命名上有明显区分:mysql_global_status_开头的来自状态变量,mysql_global_variables_开头的来自配置变量,mysql_info_schema_和mysql_perf_schema_开头的来自对应的系统表。看到指标名就能反推数据源,排查问题时路径清楚很多。
| collector | 数据来源 | 典型指标 | 所需权限 |
|---|---|---|---|
| 全局状态(默认) | SHOW GLOBAL STATUS | mysql_global_status_threads_connected | SELECT |
| 全局变量(默认) | SHOW GLOBAL VARIABLES | mysql_global_variables_max_connections | SELECT |
| slave_status | SHOW SLAVE STATUS | mysql_slave_status_slave_io_running | REPLICATION CLIENT |
| processlist | information_schema.processlist | mysql_info_schema_processlist_* | PROCESS |
| eventsstatements | performance_schema 语句汇总表 | mysql_perf_schema_events_statements_* | SELECT |
这张表后面配置账号权限时也会用到。基本规则是:开了哪些collector,账号就补哪些权限。权限宁少勿多,避免监控账号成为安全隐患。
2.3 counter、gauge与指标基数:决定告警写法和存储成本
从使用角度讲,理解数据来源的直接好处是分清指标类型。threads_connected是gauge,反映当前瞬时值,告警用比值加for子句就能过滤抖动。慢查询累计值slow_queries是counter,必须用rate()计算速率才有意义;直接对原始值设阈值,这个数会随着运行时间越滚越大,超过阈值后永远不恢复,等于废掉这个告警。
在/metrics端点里能直接看到指标类型:每类指标前面有# TYPE声明,counter类型通常会额外出现_total结尾的序列。写告警表达式之前先看一眼TYPE,能避免把counter当gauge用、把gauge当counter算速率这类错误。
还要留意指标基数。processlist和eventsstatements这类collector会产生带pid、digest、schema等标签的序列,业务越复杂,序列数量越多。高基数指标直接推高Prometheus存储和内存消耗。新环境上我会先跑一次exporter,启动日志会列出全部可用collector及开关状态,再按实例规模决定开哪些。这一步花两分钟,后面排查指标缺失或存储增长时能省半小时。
3. 从零部署:监控账号、exporter启动参数与Prometheus抓取配置
上一章讲清楚了原理,这一章给出可直接照做的步骤。部署顺序建议自底向上:先在MySQL侧准备账号,再启动exporter,然后配置Prometheus抓取,最后验证。
3.1 MySQL侧先准备最小权限监控账号
MySQL端先建一个专用监控账号,权限遵循最小化原则。常见做法是只授予SELECT、PROCESS、REPLICATION CLIENT三个权限,分别对应基础查询、进程列表采集、复制状态采集。不要拿root或业务账号做监控,职责分离能避免权限过大,也能防止业务账号密码轮换时监控跟着断掉。
CREATE USER 'exporter'@'127.0.0.1' IDENTIFIED BY '这里填一个复杂密码'; GRANT SELECT, PROCESS, REPLICATION CLIENT ON *.* TO 'exporter'@'127.0.0.1';host部分按实际来源地址设置。exporter和应用同机时用127.0.0.1最安全;exporter独立部署时改成对应IP,网络层再限制来源。GRANT之后多数情况不需要FLUSH PRIVILEGES,但我习惯顺手执行一次,避免个别环境账号缓存导致权限不生效。
再补一个细节:给监控账号加上最大连接数限制。写法是在CREATE USER语句末尾加WITH MAX_USER_CONNECTIONS 3。监控账号如果出现连接泄漏反复重连,可能瞬间占用大量连接栈,加上这个限制能防止它把连接数打满。
3.2 下载并启动mysqld_exporter:凭据传递与启动参数
二进制下载解压后直接就能跑。凭据传递有两种常见做法:一是配置文件.my.cnf,二是环境变量DATA_SOURCE_NAME。密码里有特殊字符时配置文件更省心,不需要考虑转义。
先写配置文件:
[client] user=exporter password=这里填密码 host=127.0.0.1 port=3306再启动:
./mysqld_exporter \ --config.my-cnf=/etc/mysqld_exporter/.my.cnf \ --web.listen-address=0.0.0.0:9104 \ --collect.info_schema.processlist \ --collect.perf_schema.eventsstatements \ --collect.binlog_size参数说明:--config.my-cnf指定凭据文件路径;--web.listen-address是exporter监听地址,9104是默认端口,只给本机Prometheus用就绑127.0.0.1;--collect.info_schema.processlist开启进程列表采集,看活跃连接数用;--collect.perf_schema.eventsstatements开启语句统计,慢查询分析依赖它;--collect.binlog_size采集二进制日志大小,预估磁盘容量用。
不想写配置文件的场景,用环境变量也行:
export DATA_SOURCE_NAME='exporter:密码@tcp(127.0.0.1:3306)/' ./mysqld_exporter --web.listen-address=127.0.0.1:9104生产环境建议用systemd托管,重启自愈和日志管理都方便:
[Unit] Description=Prometheus MySQL Exporter After=network.target [Service] Type=simple User=exporter Group=exporter ExecStart=/usr/local/bin/mysqld_exporter --config.my-cnf=/etc/mysqld_exporter/.my.cnf --web.listen-address=0.0.0.0:9104 Restart=always [Install] WantedBy=multi-user.target启动后看日志,没有Access denied或连接失败的报错,就说明MySQL连接正常。先curl一下确认指标能返回,再做Prometheus侧配置。
3.3 Prometheus抓取配置:job与scrape_interval怎么设
prometheus.yml里加一个job:
scrape_configs: - job_name: 'mysql' static_configs: - targets: ['127.0.0.1:9104'] scrape_interval: 15sjob_name用于分组,一个MySQL实例集群可以拆成多个job区分环境,比如mysql-prod、mysql-dev。targets填exporter的地址和端口。scrape_interval默认15s,也是我推荐的起步值:MySQL的指标变化粒度大多在秒级甚至分钟级,15s足够捕捉连接数爬升和慢查询趋势。后续要做更细粒度的性能分析,再单独下调到5s,同时评估Prometheus自身负载和存储增长。
如果MySQL实例很多,targets可以用文件或服务发现动态维护,避免每次扩容都改配置文件。小规模部署用static_configs完全够用,不必提前引入复杂机制。
3.4 验证采集是否真的成功:三个必须检查的点
第一个检查点是exporter的HTTP端点,确认返回文本里有mysql_up且值为1。第二个是Prometheus的Targets页面,mysql job状态显示UP。第三个是在Prometheus查询框里执行mysql_global_status_uptime,能看到持续增长的数值才算真正跑通。
curl -s http://127.0.0.1:9104/metrics | grep -E '^mysql_up|^mysql_global_status_uptime'mysql_up等于1表示exporter到MySQL的连接正常;uptime持续增长说明数据是活的,不是静态缓存。三个检查点按顺序跑,能快速定位是exporter问题还是Prometheus配置问题。常见情况是exporter正常但Prometheus里查不到数据,这种基本是targets地址写错或抓取间隔期间服务重启过。
4. 告警规则:连接数、慢查询、复制状态怎么量化成触发条件
监控的最终产出是告警。这一章给出我常用的五类告警表达式,以及规则文件里for、labels、annotations三个字段的调优方法。
4.1 核心指标组:优先配哪些告警
告警不是越多越好,配了不响是浪费,天天误报则会被业务方无视。按故障影响面排序,我的底线是五个场景。
| 故障场景 | 推荐表达式 | 告警级别 |
|---|---|---|
| 实例不可达 | mysql_up == 0 | critical |
| 连接数水位过高 | mysql_global_status_threads_connected / mysql_global_variables_max_connections * 100 > 80 | warning |
| 慢查询速率突增 | rate(mysql_global_status_slow_queries[5m]) > 5 | warning |
| 复制线程中断 | mysql_slave_status_slave_io_running != 1 or mysql_slave_status_slave_sql_running != 1 | critical |
| 主从延迟过大 | mysql_slave_status_seconds_behind_master > 30 | warning |
连接数按比例算而不是绝对值,因为不同实例的max_connections差异很大,绝对值阈值没法通用。慢查询速率基线需要观察一周正常业务后确定,表格里的5只是起步值。复制相关的几个指标要求实例本身已经配置了主从,没有主从关系的实例不要套这条规则。
还有两个容易被忽略的指标:mysql_global_status_aborted_connects反映连接被拒绝的次数,突增说明连接数接近上限或账号权限有问题;mysql_global_status_threads_running反映当前正在执行语句的线程数,是判断实例真实压力的关键。
4.2 规则文件写法与参数调优:for、labels、annotations怎么设
规则文件用YAML组织,一组规则的完整写法如下:
groups: - name: mysql_alerts rules: - alert: MySQLConnectionHigh expr: mysql_global_status_threads_connected / mysql_global_variables_max_connections * 100 > 80 for: 10m labels: severity: warning annotations: summary: "MySQL连接数超过80%" description: "实例 {{ $labels.instance }} 当前连接占比 {{ $value | humanizePercentage }}" - alert: MySQLReplicationBroken expr: (mysql_slave_status_slave_io_running == 0 or mysql_slave_status_slave_sql_running == 0) and mysql_up == 1 for: 1m labels: severity: critical annotations: summary: "MySQL主从复制中断" description: "实例 {{ $labels.instance }} 的复制线程已停止,请立即检查"for子句是防抖动的关键。连接数偶发冲高很快就会回落,for 10m能过滤掉大部分噪音;复制中断需要快速处理,for 1m比较合适。labels里的severity用于告警路由分组,annotations里的模板变量会在通知内容里渲染出具体实例和数值。最后那个and mysql_up == 1条件很重要:实例本身宕机时不叠加复制中断告警,减少告警风暴。
规则写完后复制到Prometheus的rules目录,在配置文件里用rule_files声明,然后reload。Prometheus的reload是热生效,不用重启进程,但每次改动前建议先做语法校验,校验方法在最后一章给出。
5. 避坑指南:Prometheus监控MySQL最容易翻车的五个细节
这一章每条都按现象、原因、解决三步展开,都是我实际部署时碰到过或帮别人排查过的类型。前四条和MySQL相关,最后一条其实是Prometheus自身的坑,但监控MySQL时最容易暴露。
5.1 现象:采集超时,exporter内存居高不下
现象:配置了很多collector之后,Prometheus抓取经常超时,exporter进程内存持续上涨。
原因:performance_schema的语句统计和表统计在大实例上扫描量很大,特别是events_statements_summary_by_digest这类汇总表,累积数据多时每次采集都要做聚合,CPU和内存开销成倍增加。
解决:只保留必要的collector。我的基准配置是全局状态、slave_status、processlist三个,语句统计按需开启。已经开启高消耗collector的实例,定期清理汇总表数据:
TRUNCATE TABLE performance_schema.events_statements_summary_by_digest;清理账号需要对应权限。另外要清楚,清理后慢查询统计基线会重置,告警规则里的rate()在清理后短暂跳到零,这是正常现象,不用慌。
5.2 现象:连接数告警频繁误报,业务方开始无视告警
现象:连接数告警一天响好几次,排查时发现实例没有异常,DBA和业务都被告警吵到疲于应对。
原因:直接用threads_connected绝对值设阈值,忽视了实例规格差异;大量sleep连接被连接池占着,看起来连接数很高但实际压力不大。
解决:改成比例告警,表达式用threads_connected除以max_connections,阈值设在80%;for至少拉到10分钟;同时看threads_running辅助判断真实压力。threads_running才是当前正在执行语句的线程数,两个指标配合才能区分“连接池占位”和“真的打满”。
5.3 现象:exporter在容器里连不上MySQL
现象:exporter日志报Access denied或dial tcp连接失败,但本机直接连MySQL是通的。
原因:容器里用127.0.0.1访问的是容器自己的网络栈,不是宿主机;MySQL账号的host限制也可能不匹配。
解决:容器用--network host模式启动exporter,让网络栈和宿主机一致;或者把.my.cnf里的host改成宿主机局域网IP。账号授权也要对应修改,host写成%或指定来源IP。这个坑很隐蔽,因为本机测试是通的,换到容器里就报错,排查时不熟悉容器网络的容易卡很久。
5.4 现象:主从复制监控时好时坏,切换后告警状态不对
现象:复制中断告警有时能触发有时不能;主从切换后旧实例还挂着告警。
原因:REPLICATION CLIENT权限没给全;多源复制场景下不同channel的复制状态都暴露在同一组指标里,没按channel_name标签区分;切换后exporter连接的还是旧实例,采集到的还是老状态。
解决:确认监控账号有REPLICATION CLIENT权限;多源复制按channel_name拆分告警或聚合判断;主从切换后重启exporter或调整target配置,让采集指向新的主从拓扑。切换这类动作应该纳入变更流程,不能指望exporter自己发现拓扑变化。
5.5 现象:Prometheus数据盘被写爆
现象:TSDB目录增长很快,磁盘使用率告警,有时Prometheus直接因内存不足退出。
原因:默认保留时间15天,很多人没配存储上限;高基数指标比如进程列表和语句统计会生成大量时间序列,每个pid或每个digest都是一条序列,存储和内存消耗随着业务增长持续攀升。
解决:启动参数加上--storage.tsdb.retention.time=7d和--storage.tsdb.retention.size=20GB,两个参数配合使用,先到哪个算哪个。同时在抓取配置里用metric_relabel_configs过滤掉不需要的标签,能显著降低基数。定期看Prometheus的TSDB head series数量,如果持续上涨就要检查是否有新的高基数指标被纳入。
6. 把监控做成体系:看板组织方式与规则自检习惯
6.1 看板怎么组织:按使用视角分组而不是按指标罗列
看板我习惯分成四层。总览页放实例存活、连接数水位、活跃线程数这类全局指标;性能页放慢查询速率、InnoDB读写、缓冲池命中率;复制页单独用从库视角,只放复制线程状态和延迟;容量页放binlog大小、磁盘占用和表数量增长。按视角分组比按指标罗列好在:排障时能顺着页面从上往下定位,而不是在一堆图表里找指标。
6.2 用promtool做规则自检:上线前必跑的命令
改完规则文件不要直接reload,先用promtool做语法检查:
promtool check rules /etc/prometheus/rules/mysql.yml没有输出错误再执行规则测试。准备一个测试文件,把历史故障的指标值写进去,验证告警能否按预期触发。这一步能拦住大部分表达式写错、标签引用错误、阈值设反的低级问题。
rule_files: - /etc/prometheus/rules/mysql.yml evaluation_interval: 1m tests: - interval: 1m input_series: - series: 'mysql_global_status_threads_connected{instance="127.0.0.1:9104"}' values: '100+0x20' - series: 'mysql_global_variables_max_connections{instance="127.0.0.1:9104"}' values: '100+0x20' alert_rule_test: - eval_time: 5m alertname: MySQLConnectionHigh测试文件里构造两组输入序列,一组连接数恒为100,一组最大连接数恒为100,连接占比100%超过80%阈值,缓冲5分钟后告警应该处于Pending状态。promtool test rules的完整语法在不同版本略有差异,以本机promtool test rules --help输出为准。
我自己的习惯是每次改动规则都在配置文件注释里记录时间和原因,比如“连接数告警从80%调到85%,原因是业务大促时连接池水位正常偏高”。三个月后回看这些注释,能避免把同一个阈值来回调。规则测试、注释记录、定期看板和指标基线,这套习惯比任何单点配置都重要。希望帮到你。
本文还有配套的精品资源,点击获取