先聊点实在的。做后端和运维这几年,我最大的感受是:MySQL服务挂掉之前往往不是毫无征兆,而是给了你很多机会,只是你没看到。慢查询在堆积、连接数在爬升、Buffer Pool命中率在下降,这些信号藏在SHOW GLOBAL STATUS的一堆数字里,可真等你手动去查的时候,要么是问题已经爆发,要么是根本无从下手。所以我一直强调,监控系统不是“上线了就行”,而是要把数据提前、完整、自动地采集出来,并在异常时告诉你“问题正在发生”。而Prometheus+Grafana这套组合,正好是用最少的成本把这件事做扎实的方案。这篇文章不是文档复读机,而是基于我实际搭过的环境,完整走一遍从采集到可视化再到告警的流程,把那些文档里没明说但你又必须知道的细节全掰开。
先说清楚这篇内容能帮你解决什么问题:一、装好一套能自动采集MySQL运行指标的监控体系;二、让关键指标以图表形式在Grafana上直观呈现;三、为重要指标配上告警,让系统主动找人而不是人找系统。适合谁看?后端开发、DBA、运维,以及那些正在从“手动查问题”往“平台化监控”过渡的团队。如果你是刚接触Prometheus的初学者,这篇也能当一份能照着敲的落地指南。
1. 监控架构设计:为什么是Prometheus+Grafana+MySQL这套组合
1.1 三件套的分工与价值
很多朋友一上来就闷头装环境,结果装完不知道哪个组件干什么。先把架构捋清楚,后面才不会糊涂。
这套体系由三个角色组成:
- Prometheus:负责定时拉取(Pull)监控数据,存在自己的时序数据库里,并且作为告警规则的判定引擎。整个体系的核心调度者。
- mysqld_exporter:一个用Go写的采集器进程,负责连接MySQL实例,把状态变量、InnoDB内部计数器、复制状态等转换成Prometheus能识别的指标格式。
- Grafana:负责数据可视化和展示,通过PromQL(Prometheus查询语言)去Prometheus里查数据,渲染成折线图、仪表盘、热力图等。
打个比方:mysqld_exporter是“传感器”,装在MySQL这栋房子各处,不断采集温度、湿度、电压;Prometheus是“数据中心”,定时把传感器的读数抄走并归档;Grafana是“监控大屏”,把归档的数据画成曲线图给值班人员看。
选择这套组合,核心原因是它形成了一个完整的闭环。采集层、存储层、展示层、告警层完全解耦,每一层都有成熟生态和社区积累。对比传统的Nagios或Zabbix,Prometheus在时序数据处理能力、云端原生支持、告警规则灵活度上优势明显;对比直接用MySQL自带的performance_schema或sys库查询,它能让你在实例故障时依然保留历史数据用于回溯,这是“被动的查”和“主动的看”之间的本质区别。
1.2 数据流转路径详解
了解数据流,排查问题时才能快速定位到底是哪一环断了。
MySQL实例 (3306端口) ↓ mysqld_exporter 通过MySQL协议连接,执行统计SQL mysqld_exporter (9104端口, /metrics) ↓ HTTP GET 拉取指标 Prometheus (9090端口, /api/v1/query) ↓ PromQL查询后返回时序数据 Grafana (3000端口) ↓ 可视化 + Alertmanager告警分发 告警通知整个链路里,最容易被忽略的是mysqld_exporter的执行方式。它不是被动等MySQL推送数据,而是Prometheus按设定的间隔(默认15秒)来HTTP GET它的/metrics接口,mysqld_exporter再当场去MySQL执行查询,然后把结果以文本格式曝光。这意味着:
- 如果Prometheus挂了,exporter还能继续工作,只是数据没人收,MySQL本身不受影响。
- 如果
mysqld_exporter连不上MySQL,它的/metrics接口依然存在,只是返回的数据里有错误标记或空指标,Grafana里会出现断线缺口,但面板本身依然能打开。 - Prometheus拉取间隔越短,数据点越密,告警响应越快,但MySQL和exporter的负担也越大。生产环境建议15秒到30秒,别为了“实时”把采集间隔压到1秒,尤其是高并发实例,频繁执行统计查询本身就有开销。
2. 环境准备:从零装好Prometheus、mysqld_exporter和Grafana
2.1 部署前想清楚的几件事
在动手装之前,有四个基础问题需要先确认,否则后面容易返工:
第一个是环境身份。我这边演示用的是Linux(CentOS 7以上的发行版基本通用),系统里已经装好了MySQL 8.0实例(本机或可网络可达的远端实例均可)。Prometheus和Grafana都支持Windows和macOS,但生产环境强烈建议放在Linux服务器上,稳定性和资源占用更有保障。
第二个是版本兼容。Prometheus、Grafana、mysqld_exporter各自按自己的节奏发版,没有严格绑定关系,但建议优先选择当前的主线稳定版本。特别提醒:mysqld_exporter的v0.15.0及以上版本对指标命名做了一次调整,很多老教程里的指标名在新版本里已经查不到了,所以下载时留意版本号。
第三个是端口规划。各组件默认端口如下,生产环境最好提前规划好防火墙放行策略:
| 组件 | 默认端口 | 说明 |
|---|---|---|
| Prometheus | 9090 | Web UI 与数据查询接口 |
| mysqld_exporter | 9104 | 指标暴露接口 |
| Grafana | 3000 | Web UI |
| MySQL | 3306 | 数据库服务端口 |
第四个是资源预估。这套组合非常轻量:一个中等规模MySQL实例,exporter内存占用通常不到100MB;Prometheus单节点可以支撑每秒数万指标点;Grafana本身消耗极低。所以即使是2核4G的小机器,也足够支撑几十个实例的监控场景。
2.2 安装Prometheus(二进制方式)
最推荐的方式是直接从官网下载二进制包,不依赖包管理器和编译工具,干净可控。
# 下载并解压,以下版本号以实际为准 wget https://github.com/prometheus/prometheus/releases/download/v2.45.0/prometheus-2.45.0.linux-amd64.tar.gz tar xvf prometheus-2.45.0.linux-amd64.tar.gz mv prometheus-2.45.0.linux-amd64 /usr/local/prometheus解压后目录里有两个关键文件:prometheus(主程序)和prometheus.yml(配置文件)。先用默认配置把服务跑起来试试:
/usr/local/prometheus/prometheus --config.file=/usr/local/prometheus/prometheus.yml启动后浏览器访问http://服务器IP:9090,能看到Prometheus自带的基础Web界面就是成功的。那些TSDB维护、告警规则的调整,后续通过改yml文件实现。
实际部署时建议用systemd管理进程,这样开机自启、崩溃重启都不用操心。创建/etc/systemd/system/prometheus.service:
[Unit] Description=Prometheus After=network.target [Service] User=root ExecStart=/usr/local/prometheus/prometheus --config.file=/usr/local/prometheus/prometheus.yml --storage.tsdb.path=/usr/local/prometheus/data Restart=on-failure [Install] WantedBy=multi-user.target然后依次执行:
systemctl daemon-reload systemctl enable prometheus systemctl start prometheus用systemd管理的好处是日志统一走journalctl -u prometheus查看,排查问题比直接前台跑方便太多。
2.3 安装与配置mysqld_exporter
mysqld_exporter本体安装方式和Prometheus一致,下载解压后就是一个可执行文件。关键在于它与MySQL的连接配置。
exporter需要连上MySQL实例去采集统计信息,所以要给它创建一个专用账号。安全起见,权限遵循最小化原则,不要给root或全部权限:
CREATE USER 'exporter'@'localhost' IDENTIFIED BY '你的强密码'; GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost'; FLUSH PRIVILEGES;三个权限的解释:
PROCESS:读取进程列表和状态变量,采集线程数、连接数等核心指标。REPLICATION CLIENT:读取主从复制状态,采集复制延迟、IO/SQL线程状态。SELECT:查询表和系统库,采集数据表状态、实时TPS/QPS等信息。
如果MySQL启用了performance_schema,新版本exporter还能采集更多深层次指标,但基础监控用这三项权限就够了。
exporter连接MySQL的凭据有两种配置方式。我推荐用.my.cnf文件,好处是权限可以限制到文件级别:
[client] user=exporter password=你的强密码启动exporter时指定配置文件路径:
#!/bin/bash export DATA_SOURCE_NAME='exporter:你的强密码@tcp(127.0.0.1:3306)/' /usr/local/mysqld_exporter/mysqld_exporter \ --config.my-cnf=/usr/local/mysqld_exporter/.my.cnf \ --web.listen-address=:9104DATA_SOURCE_NAME环境变量是传给exporter的MySQL连接串,其中的@tcp(127.0.0.1:3306)就是MySQL地址和端口,如果MySQL在另一台机器上,改成对应的IP。--web.listen-address是exporter的指标暴露端口,默认9104。注意该端口不要和Prometheus主端口9090混淆。
启动后验证一下:
curl http://127.0.0.1:9104/metrics | head -n 20能看到大量mysql_开头的指标输出,说明exporter和MySQL之间的链路已经打通。
2.4 把exporter接入Prometheus采集任务
在prometheus.yml的scrape_configs区块追加一个job配置,让Prometheus知道该去哪里拉数据:
scrape_configs: - job_name: 'mysql' static_configs: - targets: ['127.0.0.1:9104'] labels: instance: 'mysql-01'这里我加了instance: 'mysql-01'这个标签,方便在有多个MySQL实例时区分是哪个库的数据。如果监控多套MySQL,只要在targets下面继续追加地址,并给每个target配上不同的instance标签即可。
配置改完,需要重启Prometheus才能生效。由于Prometheus是热加载设计,也可以直接向接口发送请求完成重载:
curl -X POST http://127.0.0.1:9090/-/reload这种方式不用重启服务,对线上环境更友好。
进入Prometheus Web界面,在Status→Targets页面里,能看到mysql这个job处于UP状态,说明采集链路已通。如果显示DOWN,按下面排查顺序检查:exporter进程是否存活、9104端口是否监听、防火墙是否放行、Prometheus配置文件里targets地址是否正确。
2.5 安装Grafana并配置数据源
Grafana安装方式取决于系统。以Debian/Ubuntu为例:
sudo apt-get install -y software-properties-common sudo add-apt-repository "deb https://packages.grafana.com/oss/deb stable main" sudo apt-get install grafana sudo systemctl enable grafana-server sudo systemctl start grafana-serverCentOS/RHEL则使用yum源,这里不展开贴命令,官网文档写得很清楚。装好后浏览器访问http://服务器IP:3000,首次登录默认账号密码是admin/admin,登录后强制让你改密码。这个默认密码一定要首登改掉,否则等于把监控系统大门敞开。
进入Grafana后的第一步不是建面板,而是先添加Prometheus数据源。路径是Configuration→Data Sources→Add data source→ 选择Prometheus,在HTTP地址栏填http://127.0.0.1:9090,点击Save & Test,看到绿色提示就表示数据源连接成功。数据源是整个Grafana的地基,没有连接成功之前,后面所有面板都是空的。
3. 核心监控指标解读:先知道看什么,再谈怎么做面板
3.1 连接数与线程状态:MySQL的“门卫”
MySQL的并发能力首先体现在连接数上。如果连接数打满,新来的请求只能排队甚至直接报错Too many connections,这是生产事故最常见的触发点。
有两个指标必须盯住:
mysql_global_status_threads_connected:当前活跃连接数。相当于此刻有多少人正挤在门口。mysql_global_variables_max_connections:允许的最大连接数。相当于门卫最多能放多少人进来。
判断是否“拥挤”,不能只看绝对值,要看已用连接数占最大连接数的百分比。我见过一个业务,max_connections配了2000,平时稳定在800左右,看着没压力,可一旦流量高峰叠加慢SQL,连接数半小时就能冲到1900,然后雪崩式报错。所以建议监控已用百分比,阈值设在70%告警、85%直接报警。
线程状态是另一个隐藏信号。mysql_global_status_threads_running表示当前正在执行的线程数,注意这不是连接数,而是实际在处理请求的线程。这个值如果持续走高,说明CPU在过载运转,通常伴随大量慢查询。两个指标一起看,才能区分“连接满了但业务还好”和“连接满了真的跑不动了”。
3.2 查询性能与慢查询:MySQL的“效率表”
你可以在Prometheus里观察mysql_global_status_questions这个指标,它记录了服务器执行的语句总数(包含命令、DML、DDL,但不包含存储过程内部的语句)。对这个值做rate趋势计算,得到的就是QPS——每秒查询数,这是评估数据库负载最直接的指标之一。
值得注意的是,QPS增高不一定是坏事,可能是业务量在上涨。真正危险的是:QPS增长的同时,mysql_global_status_slow_queries也在快速增加。这表示负载里有一批“吃力不讨好”的查询在拖后腿,而慢查询往往是压垮InnoDB的元凶。
配置慢查询日志、使用performance_schema定位锁等待,那是另一个话题。这里要强调的是,监控先把慢查询的数量趋势放出来,当一个时间段内慢查询数量突增,往往意味着上线了新的低效SQL,或者某个表的统计信息过期导致执行计划走了全表扫描。有了趋势图,这种问题是能第一时间暴露的。
3.3 InnoDB存储引擎指标:MySQL的“心脏”
现代MySQL默认引擎是InnoDB,它的性能直接决定了数据库整体表现。以下三个指标是我的必配项。
Buffer Pool命中率。mysql_global_status_innodb_buffer_pool_read_requests是InnoDB向Buffer Pool发起的读请求次数,innodb_buffer_pool_reads是真正落到磁盘的读取次数。命中率可以按公式计算:
(1 - rate(mysql_global_status_innodb_buffer_pool_reads[5m])) / rate(mysql_global_status_innodb_buffer_pool_read_requests[5m])这个值正常应维持在99%以上。如果跌到95%以下,说明Buffer Pool太小或数据量增长太快,缓存已经撑不住了,这时候与其加机器CPU,不如先考虑调大innodb_buffer_pool_size或优化查询减少全表扫描。
日志写等待。mysql_global_status_innodb_log_waits表示日志缓冲等待写入的次数。如果这个值在不断增长,说明磁盘写入速度跟不上InnoDB日志刷新频率。检查磁盘IO是否饱和、是否存在其他进程抢占IO资源,比盲目调整innodb_log_buffer_size更有效。
行锁等待。mysql_global_status_innodb_row_lock_waits反映行锁冲突次数,持续增长意味着多个事务在争抢同一批行。配合事务隔离级别和业务逻辑来看,能发现不少并发写冲突的问题。
3.4 主从复制状态:数据库的“安全网”
如果你用了主从复制(一主一从或一主多从),复制状态必须纳入监控。mysqld_exporter会通过REPLICATION CLIENT权限读取复制状态,产生两类关键指标:
mysql_slave_status_slave_io_running:IO线程是否在从主库拉取binlog,值是1表示正常,0表示中断。mysql_slave_status_slave_sql_running:SQL线程是否在应用binlog,值是1表示正常,0表示中断。mysql_slave_status_seconds_behind_master:从库落后主库的秒数。
复制中断的后果不用多说,主从数据不一致、读流量打到从库拿不到最新数据。而延迟过高则意味着从库的查询可能读到较旧的数据,需要业务侧提前兜底。
给复制状态配告警时,有个细节容易漏:如果从库因为SQL线程出错(比如主键冲突)而停止,slave_io_running可能还是1,单看IO线程会误判为正常。所以建议同时监测两个线程状态和一个延迟值,三者任一异常都触发告警,不要只盯一个。
3.5 额外补充:磁盘空间与表数量
再说一个容易被忽略的视角。MySQL的数据文件放在磁盘上,磁盘满了,再高性能的MySQL也会瘫痪——写不了binlog、写不了数据刷盘、事务提交直接失败。如果你的exporter所在机器和MySQL在同一台机器上,建议用node_exporter直接把系统磁盘使用率纳入监控;如果MySQL在云上用云盘,可以在云监控层面配磁盘告警。总之,磁盘空间属于“不用预测,必须提前告警”的指标。
表数量也是一个值得留意的参数。information_schema.tables里的表数量过多会拖慢DDL和SHOW TABLES操作,但exporter基础指标不会直接暴露这个值,需要自己写一条自定义SQL用textfile collector方式采集,这点在后面的扩展部分再说。
4. Grafana可视化面板:把指标变成一眼看懂的大屏
4.1 面板方案选型:导入模板还是自己画
Grafana最大的优势之一就是社区模板资源丰富。登录Grafana后,在Dashboards→Import页面,输入社区面板ID(比如经典的MySQL监控模板7362),点击Load,再选一下Prometheus数据源,几秒钟就能获得一套完整的MySQL监控面板。这套面板把连接数、查询量、慢查询、InnoDB的关键指标都做了分类展示,对于大多数团队来说,是性价比最高的方案。
但社区模板有几个要接受的问题:指标名可能和你的exporter版本对不上(尤其是新版改名之后),部分面板的图表布局、阈值并不符合你业务的关注重点,而且模板里往往塞了十几个panel,很多你用不上。
我的建议是:先用社区模板跑起来,观察一周,找到你们真正关心的指标,然后自己动手画一两个定制面板。比如你们是电商业务,高峰期关注订单相关SQL的慢查询,那个面板就值得单画;如果是支付业务,连接数趋势和InnoDB日志等待就是重点关注项。
4.2 手动创建核心Dashboard的方法
我以创建一个“MySQL概览”面板为例,演示在Grafana里如何从一个空面板建起。
在Grafana左侧菜单点+→Dashboard→Add new panel,进入图表编辑界面。以一个常见的QPS趋势图为例:
查询语句:
rate(mysql_global_status_questions[5m])配置项说明:
- Legend:写成
QPS,图例上就能显示这个名称。 - Unit:选择合适的单位,这类指标可以用
ops(operations per second)。 - Interval:建议选
auto或跟随面板全局设置,Power用户可以在面板设置里统一调整最小间隔为15s,防止图表点太密导致浏览器卡顿。 - Threshold:在面板设置的Thresholds里可以给关键面板加一个背景色区域(比如超过某个QPS就变红),不过QPS高不一定是坏事,需要结合你的业务来定。
保存后,回到Dashboard拖拽布局,把多个图表组合成一个完整面板。Graph类型面板在Grafana里是主力的时序图类型;如果指标适合做分布统计(比如锁等待时间分布),可以试试Heatmap或Histogram类型。
4.3 给图表加标签和时间范围控制
多个MySQL实例的数据汇入同一个Prometheus时,图表里可以用instance标签做筛选:
rate(mysql_global_status_questions{instance="mysql-01"}[5m])这样即使监控了5套MySQL,面板上也能分别画线并对比。如果实例间负载差异太大,多条线会挤在一起,可以在面板的Legend里设置{{instance}},然后在Graph工具提示里打开All values,鼠标悬停即可单实例查看。
时间范围控制也是实用技巧。Grafana右上方有Last 6 hours、Last 30 days等预设,但不同场景要看不同粒度。排查线上问题用最近1小时的数据;观察慢SQL增长趋势用最近7天;评估容量用最近30天。面板右上角的Fast ranges可以自定义快捷区间,建议把常用区间设为1h、6h、24h、7d。
5. 告警规则配置:让监控从“可视”走向“主动”
5.1 告警体系的两层设计
有了图表只能解决“事后看”的问题,真正生产级监控必须做到“事中通知”。Prometheus的告警分成两层:
第一层是告警规则。在Prometheus配置文件中定义规则,Prometheus周期性对规则表达式做查询计算(rule_files加载规则文件),当某个指标条件持续满足设定的时间(for参数),规则被触发,状态变为Firing。
第二层是Alertmanager。Prometheus将触发的告警发送给Alertmanager,由它做去重、分组、静默、路由等管理,再通过邮件、Webhook等渠道通知到人。
所以完整链路是:Prometheus判定异常→发送给Alertmanager→Alertmanager分发给指定渠道→负责人在手机或邮件上收到通知。
5.2 常用MySQL告警规则解析
在prometheus.yml同级目录创建规则文件mysql_alerts.yml,然后在主配置里加载:
rule_files: - "mysql_alerts.yml"规则文件的基本结构如下:
groups: - name: mysql_alerts rules: - alert: MySQLConnectionsHigh expr: mysql_global_status_threads_connected / mysql_global_variables_max_connections > 0.85 for: 5m labels: severity: critical annotations: summary: "MySQL连接数过高" description: "实例 {{ $labels.instance }} 的连接数已达 {{ $value | humanizePercentage }}"这条规则的含义一目了然:连接数占总连接数的85%以上,并且持续5分钟,则触发MySQLConnectionsHigh告警。for: 5m的意义在于过滤瞬时抖动,比如某次应用重试风暴导致连接数瞬间冲高,但几十秒后恢复,这类波动不应该立刻报警试人,持续5分钟以上才说明是真实风险。
第二类必配的规则是慢查询突增,表达式可以写:
- alert: MySQLSlowQueriesSurge expr: increase(mysql_global_status_slow_queries[5m]) > 100 for: 3m labels: severity: warning annotations: summary: "MySQL慢查询突增" description: "实例 {{ $labels.instance }} 最近5分钟慢查询数增加超过100"这个告警适合有固定慢查询基线的业务,如果你们的慢查询平时就很多,需要把100调大,或者用rate的5分钟变化率来比较相对增长。
第三类是高危告警:复制中断或延迟过大。
- alert: MySQLReplicationStopped expr: mysql_slave_status_slave_io_running == 0 or mysql_slave_status_slave_sql_running == 0 for: 1m labels: severity: critical annotations: summary: "MySQL复制中断" description: "实例 {{ $labels.instance }} 复制线程断开,请立即检查从库状态"以上三类规则实际上已经覆盖了大多数中小型MySQL集群的核心风险点。配置完后,重启Prometheus加载新规则,在Alerts页面能看到规则列表,处于INACTIVE状态说明规则正常生效,当前无告警。
5.3 Alertmanager与通知渠道配置
Alertmanager本身也是一个独立组件,下载安装后编写配置文件alertmanager.yml:
route: group_by: ['instance'] group_wait: 30s group_interval: 5m repeat_interval: 2h receiver: 'webhook' receivers: - name: 'webhook' webhook_configs: - url: 'http://你的通知服务地址/alert'group_by表示按实例分组;group_wait是同一组内的告警聚合等待时间;repeat_interval控制相同告警多久重新发送一次,防止持续轰炸。Webhook是通用的通知方式,企业内部通信用它的接口就行。
启动Alertmanager后,在Prometheus主配置里追加指向它的地址:
alerting: alertmanagers: - static_configs: - targets: ['127.0.0.1:9093']弹出一个告警去测试,从触发到收到通知,实际链路需要经过Prometheus → Alertmanager → Webhook服务 → 终端App,每一跳的延迟都可能导致通知滞后。我当时踩过一个坑:告警规则和入参变量值写错了,导致告警一直处于Pending状态,结果凌晨数据库真的挂了,所有图表都白了,但告警一条都没发出来。这笔教训告诉我,告警规则配置好之后一定要做两个实验:一、故意把阈值调低,制造一次真实触发的告警,验证链路通不通;二、恢复阈值,确认告警能正常恢复和关闭。
6. 常见问题与排查技巧实录
6.1 问题速查表
这套方案跑起来之后,我遇到过不少“小问题”,单看官方文档往往要查半天,这里把高频问题整理成一张速查表:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| Targets里mysql为DOWN | exporter没启动或端口不通 | 检查curl http://IP:9104/metrics是否返回指标数据 |
| 指标一直是空的 | 数据源连接失败或不匹配 | Grafana里点数据源的“Test”按钮,确认连接和权限 |
| 图表出现断线缺口 | 网络抖动或exporter被系统OOM了 | 查看Prometheus日志、journalctl -u prometheus |
| 面板某些指标找不到 | 新版exporter改过指标名称 | 在Prometheus的查询页输入指标名看是否存在 |
| 连接数告警频繁误报 | 阈值设置不合理 | 观察正常流量基线2周后再定阈值 |
| 复制状态指标全部是0 | 账号缺少REPLICATION CLIENT权限 | 重新执行GRANT并FLUSH PRIVILEGES |
| 打开Grafana显示空白 | 数据源或面板权限被改 | 检查数据源是否在最近被重置过 |
第一重要的还是权限问题。很多时候exporter连不上MySQL,或者即使连上了也拿不到复制状态,基本都是授权语句不完整导致。我自己第一次搭的时候,只给了SELECT权限,线程数和慢查询倒是正常了,复制状态指标全是0,折腾了大半天才反应过来是复制权限没给。
6.2 踩坑记录与避坑建议
版本坑:指标的“户口本”变更
mysqld_exporter在v0.15.0之后对指标命名方案做过一轮统一调整。很多旧版指标名(比如mysql_global_status_threads_connected)在新版依然能用,但部分指标加了后缀或变了前缀。我建议别死记指标名,学会在curl /metrics输出里用grep来找你想监控的指标,这是最靠谱的方法:
curl http://127.0.0.1:9104/metrics | grep -i "threads_connected"看到指标名还在,再去写PromQL,就不会出现“表达式写了半天结果查询为空”的尴尬。
时间坑:时区不一致导致图表错位
服务器时区设置为UTC、浏览器访问Grafana用的却是北京时间,会导致图表横轴时间错位8小时。Grafana里可以在面板小时范围调整时区,但最稳妥的是在部署时统一系统时区。Prometheus的处理方式是把所有时间戳统一转成UTC存储,展示层再做时区转换,所以系统时区不一致对数据链路影响不大,但会给人排查问题时造成额外的心智负担。
采集频率坑:过度采集适得其反
MySQL的mysql_global_status_*指标是实时计算出来的,频繁被读取本身会增加数据库的统计开销。尤其是开启了performance_schema后,大量内部计数器更新会额外消耗CPU。对绝大多数业务,15到30秒的采集间隔足够满足监控需求,没必要为了“看起来实时”把采集压到3秒以内。
数据保留坑:只盯着磁盘忘了数据生命周期
TSDB的数据会按--storage.tsdb.retention.time参数决定保留时长,默认是15天。如果你的监控数据需要长期归档(比如容量规划、季度趋势分析),建议在部署时就把保留时长设成30天或60天,或者配置远程存储来做长期归档。否则到期后历史数据自动删除,到时候想查半年前的某次故障点,图表里什么都不会留下。
告警轰炸坑:没有配置分级和静默
告警不是越多越好,更不是越响越好。我记得刚搭建完这套监控时,某次数据库运维操作需要重启MySQL实例,结果所有关联的告警全部触发,手机通知持续轰炸了十来分钟。后来想想,这种情况在告警系统里是应该提前处理的:要么在计划维护期间给规则加一个静默时间段,要么在Alertmanager里配置一条基于时间段的静默规则。生产环境强烈建议整理好“告警分级”和“维护窗口”,否则运维人员很快会对告警脱敏,真的出事反而没人看了。
6.3 文本采集器:采集exporter不提供的定制指标
如果你有自身业务定制指标的需求,可以用textfile collector功能,它允许自定义脚本以文本文件格式暴露指标。mysqld_exporter支持在启动参数里加--collect.textfile.directory,指定一个目录,exporter会定时读取目录内的.prom文件,把里面的指标合并曝光到/metrics。
比如我想采集MySQL里数据表的总数,写一个小脚本定期执行并生成文件:
#!/bin/bash TABLE_COUNT=$(mysql -u exporter -p你的密码 -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='your_db';") echo "mysql_custom_table_count $TABLE_COUNT" > /var/lib/prometheus/textfile/table_count.prom配合cron定时执行,这个指标就会被exporter一并暴露,再通过Prometheus抓取、Grafana展示。扩展能力很灵活,但注意脚本执行频率和内容格式,文件描述符泄漏、脚本卡死会导致exporter在读取时不稳定,保证脚本的幂等性和执行时间可控是关键。
7. 实操心得与后续扩展
经过几个月的实际运行,这套Prometheus+Grafana+MySQL监控体系最大的价值不在于花了多少精力搭建,而在于它把“看数据库状态”这件事从被动变成了主动。以前值班时,收到用户反馈“系统变慢了”,第一反应是登服务器执行SHOW PROCESSLIST,看到一堆长事务,然后再慢慢定位。现在可以直接打开Grafana面板,从连接数、慢查询、InnoDB缓冲区命中率几个图表里快速缩小问题范围,甚至能提前在业务方感知之前发现隐患。
我这里最后分享两个运维中特别实用的小技巧。
一是在告警恢复通知上做文章。Alertmanager默认会在告警恢复后不额外通知,但实际运维中恢复通知同样重要。开启方式是在route节点下配置group_wait和repeat_interval的同时,在receivers里加入webhook_configs,并在告警规则里通过annotations区分Firing和Resolved状态,可以让接收方明确知道问题在扩大还是在收敛。这个细节很多教程都不提,但值班体验差距巨大。
二是对告警阈值做动态调整。静态阈值在业务流量波动的时段容易误报,表达式中可以使用PromQL的max_over_time做时间窗口内走势参考,或者配合changes()函数感知指标的变化率,我会在大促前手动把阈值调高20%,结束后再恢复正常,这套灵活度是Zabbix那样固定阈值系统比不了的。
如果你完成这套基础建设后发现还有更多需求,可以往这几个方向继续延伸:用node_exporter监控MySQL所在宿主机的CPU/内存/磁盘/网络;用cAdvisor监控部署了多个MySQL容器的资源争抢;为多个MySQL实例加上统一标签并配上总览视图;如果数据量到了一定规模,为Prometheus引入远程存储或联邦集群做横向扩展。监控建设没有终点,但先把MySQL这台发动机的“仪表盘”装好,比什么都重要。