1. 项目概述与整体思路1.1 mysql_export是什么为什么要部署它mysql_export准确的叫法应该是mysqld_exporter是Prometheus官方维护的一个MySQL监控采集器。它的作用说白了就是把MySQL实例内部的运行状态数据比如连接数、慢查询数、缓冲池命中率、主从延迟、InnoDB读写量这些指标从数据库里捞出来转换成Prometheus能够理解的指标格式然后暴露在一个HTTP端口上等着Prometheus server来抓取。很多朋友第一次接触这个概念时容易混淆以为是它主动上报数据到监控平台其实不是。它是一个被动的采集端进程Prometheus每隔一段时间主动来拉取一次数据这就是Pull模型。你在你的监控架构里只要把mysqld_exporter当作一个“翻译器”挂上去Prometheus就能听懂MySQL在说什么了。我之所以每次都习惯先把MySQL的监控部署起来是因为数据库是几乎所有业务系统的地基。应用挂了可以重启但数据错乱、性能劣化是缓慢发生的如果等到业务方反馈“数据库很慢”再去排查往往已经慢了一两周。有了mysqld_exporter你至少能提前看到连接数是不是逼近max_connections了临时表是不是创建得太频繁了主从延迟是不是在悄悄变大。1.2 部署方案选型与架构定位环境本身不复杂通常就是一台Linux服务器比如CentOS 7.x或Ubuntu 20.04/22.04上的MySQL 5.7或8.0实例。我在部署时习惯把exporter部署在与MySQL同一台机器上或者至少要在同一个内网网段内。因为采集MySQL指标需要使用账号密码连接数据库如果网络跨公网一方面安全上有风险另一方面延迟和失败率也会让监控数据不稳定。架构上理解成一条链MySQL实例 - mysqld_exporter通过账号连接MySQL并执行SHOW GLOBAL STATUS等命令- Prometheus server通过http://ip:9104/metrics抓取指标- Grafana做可视化展示和告警。在实际落地时我把mysqld_exporter做成一个systemd服务来托管而不是用nohup直接扔后台。原因是systemd能保证进程挂了自动拉起重启服务器之后自动启动日志管理也更规范。这一点和部署一个Web服务的心态是一致的——你要的是一个稳定运行的“数据搬运工”而不是一个需要你手动照看的孤儿进程。整个部署过程不需要改MySQL的配置文件不需要重启MySQL对业务的影响几乎为零。你需要做的只是在MySQL里创建一个专用的监控账号赋予它必要的只读权限然后让exporter用这个账号去采集数据。这也是很多人喜欢它的原因部署动作小、风险低、收益立竿见影。2. 环境准备与工具选型2.1 MySQL监控账号的权限设计与创建这个步骤是整个部署过程中最容易踩坑的地方也是很多人后来发现“采集不到某些指标”的根源。mysql_export需要的监控账号不是随便给一个SELECT权限就完了它需要视你的监控需求来决定权限范围。先说最基础的一套权限适用于绝大多数场景CREATE USER mysqld_exporter127.0.0.1 IDENTIFIED BY 这里是密码 WITH MAX_USER_CONNECTIONS 3; GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO mysqld_exporter127.0.0.1; ALTER USER mysqld_exporter127.0.0.1 IDENTIFIED WITH mysql_native_password BY 这里是密码; FLUSH PRIVILEGES;这里有个特别容易被忽略的点WITH MAX_USER_CONNECTIONS 3。如果不限制这个监控账号的最大连接数在采集高峰期exporter可能会建立非常多连接直接占满数据库的连接池造成业务连接阻塞。尤其在大促或者活动期间这个限制非常关键。我实测下来3个连接足够exporter使用了因为它本身就是每隔几秒连接一次然后立即断开的工作模式。关于IDENTIFIED WITH mysql_native_password这一个设置在MySQL 8.0默认的caching_sha2_password认证插件下很多老版本的mysqld_exporter会因为认证方式不兼容而连接失败。虽然新版本exporter已经修复了这个兼容问题但为了保险起见加上这条语句也没坏处。如果你的监控需求还包括主从复制状态那REPLICATION CLIENT权限是必需的。如果不需要可以省去这个权限以减小暴露面。权限的最小化原则一定要记住只给够用的权限不要图省事直接给ALL PRIVILEGES。2.2 下载安装与版本选择mysqld_exporter的安装包可以从Prometheus官网的下载页面获取也可以从GitHub Releases页面下载。这里我给一个我在服务器上实际使用的版本和下载方式以Linux amd64架构为例cd /usr/local/src wget https://github.com/prometheus/mysqld_exporter/releases/download/v0.15.1/mysqld_exporter-0.15.1.linux-amd64.tar.gz tar -xzf mysqld_exporter-0.15.1.linux-amd64.tar.gz mv mysqld_exporter-0.15.1.linux-amd64 /usr/local/mysqld_exporter ln -s /usr/local/mysqld_exporter/mysqld_exporter /usr/local/bin/mysqld_exporter版本选择上我个人建议选择0.15.1之后的版本因为在0.15.0之前exporter的连接串配置方式有过比较大的调整老版本的配置写法在新版本下有兼容性问题。如果你用的是MySQL 8.x那么尽量选最新的稳定版本对caching_sha2_password的支持会更完善。下载完成后先手动运行一下确认可执行文件没问题/usr/local/bin/mysqld_exporter --version如果能正常输出版本号说明二进制文件可用。这一步不要跳过下载过程偶尔会遇到文件损坏的情况先跑一下能尽早发现问题。2.3 配置文件的设计新版mysqld_exporter支持通过环境变量或配置文件的方式传入数据库连接信息。我习惯使用配置文件的方式因为配置项多了之后更清晰也方便后续修改。默认情况下exporter会读取~/.my.cnf文件但我们一般不在root用户下运行服务所以会在systemd服务里显式指定配置文件路径。创建配置文件的方式如下mkdir -p /etc/mysqld_exporter vim /etc/mysqld_exporter/my.cnf文件内容[client] usermysqld_exporter password这里是密码 host127.0.0.1 port3306这里注意host不要写成MySQL实例的对外IP保持写127.0.0.1即可。因为exporter是部署在MySQL本机上的直接走回环地址能避免防火墙拦截、减少网络链路损耗。如果MySQL和exporter不在同一台机器才需要改成实际的IP地址。配置文件权限一定要设置严格因为里面保存了数据库的明文密码chmod 600 /etc/mysqld_exporter/my.cnf chown mysqld_exporter:mysqld_exporter /etc/mysqld_exporter/my.cnf如果是用root启动的exporter配置文件权限倒无所谓但我们一般不直接用root跑服务所以创建专用系统用户来运行是更稳妥的做法。这个问题在后面systemd服务里会一并处理。3. 核心配置与参数解析3.1 服务启动方式systemd托管为了让mysqld_exporter作为一个稳定的后台服务运行我会把启动动作交给systemd。创建一个systemd服务单元文件内容如下vim /etc/systemd/system/mysqld_exporter.service写入以下内容[Unit] DescriptionMySQL Prometheus Exporter Afternetwork.target [Service] Usermysqld_exporter Groupmysqld_exporter Typesimple ExecStart/usr/local/bin/mysqld_exporter --config.my-cnf/etc/mysqld_exporter/my.cnf --collect.info_schema.processlist --collect.info_schema.innodb_metrics --collect.engine_innodb_status --collect.perf_schema.eventsstatements --collect.perf_schema.file_instances --collect.perf_schema.file_events --collect.perf_schema.table_io_waits --collect.perf_schema.index_io_waits --collect.perf_schema.table_lock_waits Restartalways RestartSec5 [Install] WantedBymulti-user.target这里有几个点要展开说明一下。--config.my-cnf指定了之前创建的那份配置文件路径。如果你不指定exporter默认会找当前用户家目录下的.my.cnf这点很容易踩坑尤其是当你用systemd指定了运行用户之后它的家目录可能压根不存在或者没有这个文件。再说那串--collect.*参数。它们是用来开启额外采集项的开关。mysqld_exporter默认只会采集一部分基础指标如果你想获取更丰富的MySQL运行数据比如InnoDB引擎的具体状态、perf_schema维度的表锁等待情况就需要显式开启这些采集开关。这也是很多教程没有详细讲的为什么同样部署了exporter别人能在Grafana看板里看到一堆图表而你的看板却只有几张稀疏的图绝大多数原因就在于没有打开对应的采集开关。创建好服务文件后先创建专用的系统用户并设置权限useradd -r -s /bin/false mysqld_exporter chown -R mysqld_exporter:mysqld_exporter /usr/local/mysqld_exporter chown mysqld_exporter:mysqld_exporter /etc/mysqld_exporter/my.cnf然后启动服务并设置开机自启systemctl daemon-reload systemctl enable mysqld_exporter systemctl start mysqld_exporter systemctl status mysqld_exporter3.2 验证指标输出与关键指标解读服务启动后先用命令验证一下exporter是否正常工作curl http://127.0.0.1:9104/metrics如果输出了一大串以# HELP和# TYPE开头的指标数据说明exporter已经成功连接到MySQL并开始采集指标了。注意观察输出中是否有以mysql_up开头的指标这个指标尤其重要当它等于1的时候说明exporter到MySQL的连接是健康的如果是0说明连接失败了需要立刻排查账号权限或网络问题。在众多指标里我平时最关心的几个有mysql_up采集器与MySQL之间连接的状态1为正常0为异常。 mysql_global_status_threads_connected当前连接数配合max_connections可以判断连接池是否接近上限。 mysql_global_status_uptime数据库实例的存活时间重启会归零。 mysql_global_status_slow_queries慢查询累计次数注意是累计值需要配合rate函数看增速。 mysql_global_status_innodb_buffer_pool_read_requests和mysql_global_status_innodb_buffer_pool_reads这两个放在一起看命中率。 mysql_slave_status_seconds_behind_master如果配置了主从这个就是主从延迟的关键指标。看指标时养成一个好习惯先确认mysql_up是1再去看其他指标。如果mysql_up是0后面的所有指标都是无意义的旧数据或空数据别被表面数字骗了。4. 实操过程与核心环节实现4.1 接入Prometheus的Scrape配置mysqld_exporter部署完成后还需要把它接入Prometheus的抓取列表。这一步相对简单在Prometheus的配置文件prometheus.yml中新增一个job即可scrape_configs: - job_name: mysql static_configs: - targets: [192.168.10.20:9104] labels: instance: db-productiontargets里填的是mysqld_exporter所在机器的IP和端口。labels里的instance字段值得好好利用因为当你有多个MySQL实例时这个标签就是区分不同实例的关键。我建议给每个数据库实例起一个清晰的别名比如db-production、db-warehouse、db-replica-01比写死IP要直观得多在Grafana里做图例筛选时也会方便很多。配置改完后重载Prometheus配置curl -X POST http://localhost:9090/-/reload这里有个前提启动Prometheus时带了--web.enable-lifecycle参数这个接口才可用。如果没有带这个参数就需要重启Prometheus进程来加载配置了。线上环境用reload接口是首选因为重启会造成一小段时间的监控数据断档。去Prometheus的Targets页面确认一下新job的状态。如果显示UP说明Prometheus已经能正常抓取exporter的数据了。如果显示DOWN鼠标移上去通常能看到错误信息这会是我们排错的第一依据。4.2 配置Grafana可视化看板数据进了Prometheus之后展示环节离不开Grafana。我用的看板是Grafana官方社区里非常知名的MySQL OverviewDashboard ID是7362。这个看板通过ID导入即可不需要手动创建图表导入后你就能看到连接数、查询流量、缓冲池命中率、复制状态等核心监控图形。导入看板后需要把数据源设置为你的Prometheus数据源。这个看板的模板变量默认使用$instance和我们前面在scrape配置里设置的instance标签正好对得上。如果你没有设置这个标签下拉框里通常会显示出192.168.10.20:9104这样的原始地址虽说不影响看数据但看着不够直观。关于看板选择我再多说两句。很多朋友初次接触时喜欢抱着一大堆模板去导入从几百个仪表盘里挑花了眼最后导入三四个看板里面的图表有一半显示No data。我的建议是只需要一个核心看板就够日常使用了。先把7362用透理解每个图表背后的指标含义再按需添加自己关心的Panel。监控的核心目标是快速定位问题而不是在可视化上炫技。4.3 采集数据的配置细节与行为观察exporter默认的采集频率是由Prometheus的scrape_interval决定的。我通常设置为15秒一次这个频率既能捕捉到大部分瞬时波动又不会给MySQL带来明显的额外负载。mysqld_exporter的执行原理是周期性执行类似SHOW GLOBAL STATUS、SHOW ENGINE INNODB STATUS这样的命令这些命令本身很轻量但如果你把采集频率调成1秒一次高并发场景下还是会给数据库增加不少压力。特别是在开启了一堆--collect.perf_schema.*选项之后每轮采集涉及到的系统表查询会更多对性能的影响也会上升。所以我的组合方案是基础指标15秒拉一次perf_schema相关的扩展指标30秒或者60秒拉一次。这可以通过在Prometheus配置里给同一个job设置不同的scrape_interval来实现。如果你发现exporter进程本身占用CPU偏高优先检查一下是不是采集开关开得太多了以及采集频率是不是设得太激进。从我的经验看0.15.1版本在开启常用采集项、15秒采集间隔下CPU占用一般不会超过1%内存占用在50MB以内非常轻量。4.4 监控告警规则的补充部署监控的最后一公里是告警否则数据只是拿来画画图意义就小了一半。我通常会在Prometheus的告警规则目录里新增一个MySQL规则的片段举几个最有实用价值的告警项groups: - name: mysql-alerts rules: - alert: MySQL连接数飙升 expr: mysql_global_status_threads_connected / mysql_global_variables_max_connections 0.8 for: 5m labels: severity: warning annotations: summary: MySQL实例{{ $labels.instance }}连接数已超过80%上限 - alert: MySQL主从延迟过大 expr: mysql_slave_status_seconds_behind_master 30 for: 2m labels: severity: critical annotations: summary: {{ $labels.instance }}主从延迟已超过30秒 - alert: QPS突增 expr: rate(mysql_global_status_questions[1m]) 5000 for: 5m labels: severity: warning annotations: summary: {{ $labels.instance }}QPS超过5000QPS的判断阈值要看你的业务规模和机器规格来定5000只是一个示例值生产环境请根据自己的压测结果调整。告警规则的核心价值在于尽早发现而不是等到业务方来找你。5. 常见问题与排查技巧实录5.1 连接失败类问题我在实施这个部署方案的过程中遇到过且概率最高的就是exporter报“Access denied”或者连接超时的问题。下面把典型问题的排查思路整理成一个速查表。现象可能原因排查与修复方案日志显示Access denied for user密码错误或账号权限不足检查my.cnf中的密码确认GRANT权限是否包含PROCESS、SELECT日志显示Unknown databasemy.cnf中写了database字段exporter连接时不要指定database去掉即可日志显示Authentication plugin错误MySQL 8.0默认认证插件不兼容旧版exporter升级exporter版本或者在MySQL中为账号指定mysql_native_passwordcurl返回空内容或拒绝连接服务没启动或端口被占用检查systemd服务状态ss -ltnp确认9104端口是否在监听能查到metrics但mysql_up为0连接串虽然没报错但实际连接失败手动用mysql客户端测试账号连接检查exporter日志中的具体错误排查权限问题的一个很实用的技巧在服务器上直接使用监控账号手动连接MySQL执行一遍exporter会执行的查询。比如mysql -h 127.0.0.1 -P 3306 -umysqld_exporter -p这里是密码 -e SHOW GLOBAL STATUS; SHOW ENGINE INNODB STATUS;如果这一步能成功跑出来说明账号权限基本没问题问题大概率出在exporter配置上。如果这一步就报了权限错误那就老老实实回头重新执行一遍GRANT授权。5.2 采集指标不出现或看板数据缺失部署完成后在Grafana里看板依然一大片空白的这个问题排在第二位。主要原因通常有两个一是采集开关没打开。默认的mysqld_exporter只带基础采集项像Percona那类看板里的很多Panel依赖的是performance_schema相关的指标没有加--collect.perf_schema.*这样的启动参数这些指标就不会出现。看板为空不一定是你配置有问题很可能是采集项没开全。我的建议是先把上一节systemd服务文件里的采集参数原样复制过去至少能保证主流看板能看到图。二是instance标签不匹配。Grafana看板里通常有个$instance变量下拉框如果你在Prometheus配置里没有加labels或者加的标签名不是instance那Grafana里就找不到对应的选项。确认prometheus.yml里使用的是labels: instance: xxxx这种写法并且Grafana数据源指向的Prometheus已经重新加载过配置。5.3 主从复制指标缺失如果你监控的是从库但看板上完全没有mysql_slave_status_*系列的指标请检查监控账号是否有REPLICATION CLIENT权限。如果只有SELECT和PROCESS权限exporter是查不到SHOW SLAVE STATUS结果的自然就无法暴露主从相关的指标。另外MySQL 8.4之后主从复制相关的查询语法有变化旧版exporter可能无法在新版本上正确获取复制状态。这类兼容性问题比较隐蔽我的建议是先升级exporter到最新版本试试如果问题依旧那就去GitHub的Issues里搜一下对应版本组合是否有人遇到过同样的问题。5.4 版本升级与多实例部署注意点最后聊一个扩展性相关的问题如果你有多套MySQL实例mysqld_exporter能不能一套服务搞定答案是不建议。虽然exporter支持通过--config.my-cnf指定配置文件但一个exporter进程通常只对应一个MySQL实例多实例场景最好每套实例部署一个exporter分别用不同的端口把它暴露出来。比如实例A走9104端口实例B走9105端口scrape_configs: - job_name: mysql static_configs: - targets: [192.168.10.20:9104] labels: instance: db-production - targets: [192.168.10.21:9105] labels: instance: db-replica-01这样每个实例的指标相互独立出现问题也能快速定位。虽然有人会考虑在单机上用多配置文件的方式跑多个exporter进程但生产环境我建议一台机器一个实例的对应关系维护成本最低排错时的思路也最清晰。6. 整体部署后的心得与进一步扩展6.1 这套监控方案在业务里的实际价值在把mysqld_exporter部署完并稳定运行一个月之后我对这套监控方案的实际价值感受是非常直观的。有一次线上业务高峰期业务方反馈页面加载变慢大家都在怀疑应用代码有问题但打开Grafana一看MySQL的连接数曲线正在快速爬升慢查询数也在同步增长问题的方向一下子就从“应用层”拉回到了“数据库层”。后来定位到是一条SQL查询因为统计信息过期执行计划走了全表扫描把数据库IO打满了。如果没有监控数据这种问题通常要靠猜甚至可能要等数据库彻底卡死才能定位。mysqld_exporter的价值不在于它是多么新颖的技术而在于它把MySQL的众多关键运行数据做成了一串标准化的指标通过Prometheus和Grafana这条成熟的链路让“数据库正在经历什么”变得可以被看见。这是运维排查问题的基础能力。6.2 从基础监控到容量规划与告警优化部署完基础监控之后我建议后续进一步做这几件事第一把Grafana的告警能力真正用起来。Prometheus的Alertmanager可以配置多个通知渠道把数据库告警推送到企业内部的消息群。这样出了问题不是运维盯着大屏发现的而是告警机器人先喊出声。第二积累历史数据做容量规划。Prometheus的存储默认保留15天左右如果要看更长时间的趋势可以考虑调整--storage.tsdb.retention.time参数或者接入对象存储做长期归档。有了月度维度的连接数、QPS、磁盘IO趋势扩容决策就有数据支撑不用再凭感觉拍脑袋。第三把采集项做差异化。有的实例并发量不高采集开全了也没关系有的实例是核心交易库每多一个采集项都要评估对性能的影响。不要盲目追求指标数量够用就好。6.3 根据自己的场景做微调最后分享一个我在实际使用里反复体会到的小技巧监控模板和指标一定要和你的业务场景相配合。如果你的MySQL主要做OLTP交易那就要多关注mysql_global_status_threads_connected和mysql_global_status_innodb_row_lock_waits如果你的实例主要跑报表类的OLAP查询那mysql_global_status_slow_queries和临时表相关的指标优先级就更高。我见过很多团队部署了监控但常年只盯着看板上的流量曲线遇到真正的问题却还是无从下手。原因就在于没有提前理解每个指标的业务含义。部署exporter只是第一步真正的工作是从这些指标里读出数据库的运行状态并形成你自己的一套判断逻辑。这个过程急不得但一旦建立起来对你的运维效率会是质的提升。mysql_export这个项目说白了就是一套开箱即用的MySQL监控数据采集方案它的部署门槛不高但能带来的价值却非常稳定。如果你还在用自定义脚本定时抓取SHOW GLOBAL STATUS来监控MySQL或者干脆连监控都没有那不妨从今天这个方案开始把一个轻量、稳定、社区生态成熟的监控链路搭起来。这套东西不像业务系统那样需要频繁迭代它更像一个长期陪伴你的体检仪只要配置好了就会一直安静地替你把守着数据库的健康状况。