尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
MySQL数据库监测指标体系搭建:采集、阈值与文档化实践
简介数据库监控是保障线上服务稳定性的基础能力但很多团队的监控体系只停留在截图和临时查询。真正有效的监控需要一套可采集、可对比、可告警的数字指标体系并且每个指标的定义、阈值和负责人要长期有效。以MySQL为例监控指标通常分为吞吐、连接、缓存与复制三个维度QPS/线程数反映承载压力连接使用率是故障第一现场InnoDB buffer pool命中率和复制延迟则需要结合磁盘状态综合判断。通过mysqld_exporter将状态变量转为Prometheus时间序列搭配最小权限账号和textfile collector补充自定义指标再基于7天基线数据用quantile_over_time计算p95阈值才能避免告警轰炸。最终把指标名、采集来源、单位、阈值和副作用沉淀为可校验的文档并用脚本同步校验Prometheus中的指标是否存在确保监控体系可持续演进。围绕指标设计、采集落地和配置校验提供一套可直接抄用的命令和配置帮助团队快速搭建可靠的MySQL数据库监测体系。1. 数据库监测指标不是一张截图把数据库监测指标写成一份文档听上去是运维里最简单的事实际上大多数团队交出来的只有监控截图和一句看 Grafana 吧。等真正出故障QPS、连接数、复制延迟散落在不同系统没人说得清哪条指标该告警、阈值是谁定的。数据库监测指标真正要做的事是把数据库还健康吗翻译成一组可采集、可对比、可告警的数字并且让这些数字的定义、口径和负责人长期有效。下面以 MySQL 为例从指标分类、采集落地、阈值设计到文档化校验把整条链路拆开讲命令和配置都可以直接抄。2. 数据库监测指标的三个维度吞吐、连接、缓存与复制2.1 吞吐类指标看趋势别看绝对值QPS 和 TPS 是业务方问得最多的两个数。这两个数本身不构成告警依据真正有用的是变化趋势。PromQL 里一般这样算rate(mysql_global_status_queries[1m])mysql_global_status_queries 是累计值rate 把它变成每秒速率。这个指标适合看曲线有没有明显抬升或下跌——QPS 突然减半比突然翻倍更值得警觉因为常见原因是连接被堵住请求根本进不来。比 QPS 更值得盯的是 threads_running即当前正在执行的线程数。它反映数据库此刻真实的工作压力。CPU 核数为 N 的实例threads_running 持续超过 2N基本可以判断 SQL 已经进入执行层排队。开发同学常问的数据库是不是慢了用这个指标回答最直接。2.2 连接类指标故障第一现场数据库故障最先体现出来的往往不是 CPU而是连接异常。threads_connected 接近 max_connections 时新请求直接报 Too many connections应用侧表现为连接池报错。这里有个经典坑MySQL 的 max_connections 默认只有 151而应用连接池可能按 200 甚至更高去配两边从配置上就没对齐过。连接指标的正确打开方式是看比值mysql_global_status_threads_connected / on (instance) mysql_global_variables_max_connections除了当前连接数还要看 Connection_errors_max_connections 和 Aborted_connects 这两个累计值。前者只要大于 0说明已经发生过连接拒绝后者持续增长通常是密码错误、连接被防火墙掐断或者客户端异常断开这类问题看平均值没用必须看斜率。2.3 缓存、存储与复制延迟要从根上拆InnoDB buffer pool 命中率是 MySQL 最老的监控指标之一但命中率 99% 只说明热数据在内存不能说明磁盘没有压力。要把 innodb_buffer_pool_reads从磁盘读页的累计值单独拉出来配合 node_exporter 的磁盘 await 一起看。命中率高同时 await 高通常是刷新脏页或双写造成的命中率掉到 95% 以下才需要怀疑 buffer pool 容量本身。复制延迟用 seconds_behind_master 就能看但这个指标有个著名的坑SQL 线程空闲时它不更新主从之间网络断了反而可能显示 0。看从库健康度不能只看这一个数还要看 Slave_IO_Running 和 Slave_SQL_Running 两个线程状态以及主从的 GTID 集合差。监控指标里把这三样都采上比只盯一个秒数可靠得多。下面是生产环境常驻的 8 条核心指标推荐作为指标字典的第一版清单指标名exporter 输出含义单位参考阈值mysql_global_status_queries累计查询数次无看趋势mysql_global_status_threads_running执行中的线程数线程数CPU 核数 × 2mysql_global_status_threads_connected已建立连接数连接数max_connections × 80%mysql_global_status_slow_queries慢查询累计值次基线 p95mysql_global_status_aborted_connects中断连接累计值次持续增长即告警mysql_global_variables_max_connections最大连接数连接数只作分母mysql_global_status_innodb_buffer_pool_reads从磁盘读页累计值页持续增长需关注mysql_slave_status_seconds_behind_master复制落后秒数秒 30 告警这 8 条覆盖了吞吐、连接、存储、复制四个平面每条都有明确的采集来源和对应的处置动作。先跑通这 8 条再往细处扩展比一开始就接十几个 exporter 要好维护得多。3. 用 mysqld_exporter 把数据库监测指标采成时间序列3.1 最小的采集拓扑数据库监测指标落地最常用的是三件套Prometheus 负责抓取和计算告警mysqld_exporter 负责把 SHOW GLOBAL STATUS 这类只读命令转成指标node_exporter 补上 CPU、内存、磁盘。之所以这样拆是为了排错时能直接区分是数据库本身的问题还是主机资源的问题。碰到慢查询先看 node_exporter 的磁盘 await 有没有抬头再看 threads_running 和慢查询数两步就能把问题定位到层。3.2 先建一个最小权限的采集账号mysqld_exporter 不要用 root 连库。常见做法是单独建一个只读账号CREATE USER exporter127.0.0.1 IDENTIFIED BY readonly_pass WITH MAX_USER_CONNECTIONS 3; GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO exporter127.0.0.1;PROCESS 权限用于读取 processlist 和线程状态REPLICATION CLIENT 用于读取主从状态SELECT 用于查询各类状态表。WITH MAX_USER_CONNECTIONS 3 是防止监控账号连接失控把监控自己变成故障源。授权之后不用 FLUSH PRIVILEGESGRANT 语句本身会即时生效。3.3 用 my.cnf 启动 exporter避免密码进进程参数启动参数里直接写 -p 密码会在 ps 输出里暴露不建议这么做。常见做法是准备一个 my.cnf[client] userexporter passwordreadonly_pass host127.0.0.1 port3306然后启动./mysqld_exporter \ --config.my-cnf/etc/mysqld_exporter/.my.cnf \ --collect.info_schema.processlist \ --collect.slave_status \ --web.listen-address0.0.0.0:9104几个参数说明--collect.info_schema.processlist 会查询 information_schema.processlist让 active 线程数更精确但这个查询本身在高并发下锁开销变大低配实例可以去掉--collect.slave_status 只有从库需要开--web.listen-address 如果 Prometheus 不在同一台机器要同步调整防火墙放行。my.cnf 建议属主改成 root:mysqld_exporter权限 640防止其他账号读走密码。提示mysqld_exporter 的 --collect.info_schema.processlist 在连接数上千的实例上会放大锁开销低配实例建议先关掉观察一周再决定要不要开。3.4 exporter 采不到的指标用 textfile collector 补mysqld_exporter 只管 MySQL 自身的状态量业务相关指标比如当前活跃事务数执行超过 5 秒的实时 SQL 条数它不会给你。常见做法是写一个 cron 脚本把结果输出到 node_exporter 的 textfile 目录#!/usr/bin/env bash # /usr/local/bin/mysql_custom_metrics.sh OUT_DIR/var/lib/node_exporter/textfile OUT_FILE$OUT_DIR/mysql_custom.prom TMP_FILE$OUT_FILE.$$ MYSQL(mysql --defaults-extra-file/etc/mysql/metrics.cnf -N -B) active_tx$(${MYSQL[]} -e SELECT COUNT(*) FROM information_schema.innodb_trx 2/dev/null) long_running$(${MYSQL[]} -e SELECT COUNT(*) FROM information_schema.processlist WHERE INFO IS NOT NULL AND TIME 5 2/dev/null) { echo mysql_active_transactions $active_tx echo mysql_long_running_queries $long_running } $TMP_FILE mv $TMP_FILE $OUT_FILE配套 cron 每 60 秒执行一次* * * * * /usr/local/bin/mysql_custom_metrics.sh这个脚本有几个细节值得说明。一是先写临时文件再 mv避免 Prometheus 抓到写了一半的 .prom 文件二是用 --defaults-extra-file 代替命令行传密码ps 里看不到凭据三是指标名统一用 mysql_ 前缀划分命名空间。information_schema.innodb_trx 在长事务多的时候查询本身有开销采集间隔不要低于 60 秒业务高峰期如果发现监控账号占用连接优先降这个频率而不是删指标。3.5 抓取间隔和实例数量的取舍Prometheus 的 scrape_interval 常规设 15 秒就够覆盖告警场景。不要为了实时设成 5 秒——每次抓取 mysqld_exporter 都要执行一批 SHOW 命令5 秒间隔等于给数据库加了一路持续的只读负载。多实例情况下我一般一台实例对应一个 exporter 进程用不同端口区分靠单个 exporter 频繁切换 DSN 的做法会增加连接建立和状态刷新的开销得不偿失。4. 阈值设计数据库监测指标从有数到会用4.1 先跑基线再定阈值监控采上来第一周不要急着配告警。先让数据积累 7 天用分位数算基线quantile_over_time(0.95, mysql_global_status_threads_running[7d])quantile_over_time 把 7 天内的 threads_running 按 95 分位收敛成一个值代表绝大多数时间线程数不超过多少。用 p95 而不是平均值或最大值是因为平均值会被空闲时段拉低最大值会被一次性毛刺拉高。更细致的做法是按星期几分段周一的流量形态和周末凌晨完全不一样共用一套阈值必然误报或漏报。4.2 告警规则怎么写才不吵阈值定好之后写成 Prometheus 规则文件。下面是一组可以改改就用的规则groups: - name: mysql_health rules: - alert: MySQLConnectionRatioHigh expr: | mysql_global_status_threads_connected / on (instance) mysql_global_variables_max_connections 0.8 for: 3m labels: severity: warning annotations: summary: MySQL 连接使用率超过 80% description: {{ $labels.instance }} 连接使用率 {{ $value | humanizePercentage }} - alert: MySQLThreadsRunningHigh expr: mysql_global_status_threads_running 60 for: 5m labels: severity: critical annotations: summary: MySQL 活跃线程持续高位 description: {{ $labels.instance }} threads_running{{ $value }}请检查慢查询与锁等待这条规则的三个要点expr 里的 / on (instance) 是显式指定按实例标签做除法因为连接数和最大连接数两个指标的标签集合不一定一致for: 3m 或 5m 表示持续这么久才触发用来过滤秒级毛刺annotations 里务必带 {{ $labels.instance }} 和 {{ $value }}否则收到告警还要自己查是哪台机器。MySQLThreadsRunningHigh 的 60 只是初始值拿到 7 天基线后改成基线 p95 的 1.5 倍更合理。4.3 组合条件、级别和收敛单一指标的告警往往不可靠。复制延迟高但数据库整体很闲和复制延迟高同时线程数打满是两个完全不同的故障等级处置优先级也不一样。用 AND 把条件组合起来expr: | mysql_slave_status_seconds_behind_master 30 AND ON (instance) mysql_global_status_threads_running 30两个条件同时满足才触发 critical比单指标告警更有决策价值。告警收敛交给 Alertmanagergroup_wait 设 30s、group_interval 设 5m、repeat_interval 设 4h能有效避免一次抖动刷屏。注意恢复通知是 Prometheus 在条件不再满足时自动发出的如果不想凌晨被恢复通知吵醒在 Alertmanager 路由里按时间过滤即可。下表是生产环境常用的初始阈值配合基线数据再微调指标阈值持续时长级别连接使用率 80%3mwarning连接使用率 90%3mcriticalthreads_running基线 p95 × 1.55mwarning复制延迟 30s1mcritical慢查询数基线 p95 × 1.510mwarningbuffer pool 命中率 99%15mwarning磁盘使用率 85%10mcritical注意告警阈值不要照抄任何一篇文章先用自己环境的 7 天数据算基线。buffer pool 命中率这条在低配实例上尤其明显内存紧张时命中率常在 97% 上下波动直接套 99% 会天天误报。5. 把数据库监测指标沉淀成一份可校验的文档5.1 指标字典的六个必填字段回到标题里那个数据库监测指标的文档。一份能长期用的指标文档不该是截图集锦而是一张字段完整的指标字典。我一般每个指标至少写六列指标名、采集来源、单位、计算方法、阈值与级别、负责人。指标名必须和 exporter 输出严格一致PromQL 表达式直接写进去接手的人不用再去 Grafana 面板里翻表达式。5.2 用脚本校验文档和生产环境一致exporter 升级、MySQL 大版本变更都会让指标名静默失效。文档写得再漂亮指标不存在就没有意义。常见做法是跑一个校验脚本用文档里的指标名和 Prometheus 的元数据做差集#!/usr/bin/env python3 import requests prometheus http://127.0.0.1:9090 dict_file mysql_metrics_dict.csv with open(dict_file, encodingutf-8) as f: doc_metrics [r.split(,)[0].strip() for r in f if r.strip()] names requests.get(f{prometheus}/api/v1/label/__name__/values, timeout5).json()[data] missing [m for m in doc_metrics if m not in set(names)] print(缺失指标:, missing if missing else 无)这个接口一次请求返回全量指标名脚本跑完 5 秒内能告诉你有多少条文档指标在 Prometheus 里不存在。配合 cron 每周执行一次exporter 升级时就不会把失效指标带进告警链路。5.3 把采集副作用写进文档指标字典里最容易被忽略、排错时最值钱的一列是采集副作用。information_schema.innodb_trx 的 COUNT(*) 在长事务多的时候会加剧元数据锁竞争processlist 查询在连接数高位时会放大锁开销textfile 脚本里那条超过 5 秒的 SQL 统计也一样。把这些副作用写成一句备注附在对应指标后面下一任维护者调节采集频率就有据可依不用重新踩一遍坑。本文还有配套的精品资源点击获取
RELATED

相关推荐

MySQL启动报错Can‘t create test file?排查思路与修复实操

MySQL启动报错Can‘t create test file?排查思路与修复实操

上周给一台测试机装 MySQL 8.0,初始化一切顺利,结果卡在了服务启动这一步。Windows 服务管理器弹了个很笼统的提示——本地计算机上的 MySQL 服务启动后停止,没有任何其他有效信息。去翻数据目录下的错误日志,追到最后线索就剩一行…

📅 2026/9/18 0:34:15
MySQL ALTER VIEW 安全变更实战指南

MySQL ALTER VIEW 安全变更实战指南

1. 项目概述:ALTER VIEW 不是“改个名字”那么简单在 MySQL 数据库日常维护和开发中,“修改视图”这个动作,表面看只是执行一条ALTER VIEW语句,仿佛和ALTER TABLE一样,属于基础 DDL 操作。但实际踩过坑的人才知道——它…

📅 2026/9/18 0:34:15
SQL Server 2019彻底卸载:注册表、服务与实例残留清理指南

SQL Server 2019彻底卸载:注册表、服务与实例残留清理指南

1. 先搞清楚SQL Server 2019到底装了些什么很多人卸载SQL Server 2019失败,问题从第一步就埋下了:把它当成一个普通软件,以为点一下“卸载”就完事。实际上SQL Server 2019是一整套组件家族,控制面板里可能同时躺着七八个甚至十几…

📅 2026/9/18 0:34:15
MORE NEWS

更多资讯

📰

从RTE到iRTE,实时终于有了体感

声网iRTE2026实时智能大会将近,已经开始报名。连续关注RTE2024和RTE2025后,我对这场大会最直观的感受是:它不只把技术热词搬上台,而是把行业变化,拆成开发者和产品人看得见的下一步。RTE2024是第十届大会,站…

📰

MySQL重装初始化失败?从错误日志与data目录残留排查

你有没有遇到过这种情况:新装软件一切正常,但当你因为换版本、改配置、清理环境而把 MySQL 卸载再重装时,安装向导却卡在最后一步,直接弹出一个红色错误:Database initialization failed。我当时看到这个报错&#xff…

📰

出国看病病历翻译怎么做?材料清单、各国要求与避坑要点一文讲清

近年来,越来越多的家庭选择出国就医,从肿瘤、心血管等重症治疗,到辅助生殖、口腔种植等消费型医疗项目,跨境就医的需求持续增长。但在实际操作中,很多人把精力都放在选医院、办签证上,却忽略了一个关键环节…

📰

InfiniBand交换机实战解析:从架构原理到部署运维

InfiniBand网络交换机这东西,很多人第一次接触是在机房或者公司新采购的高性能计算集群里。一台台设备通过粗铜缆或者光纤连到一台看起来“平平无奇”的盒子上,标签上印着Mellanox或NVIDIA的Logo,型号里带着IB两个字母,这就是Infi…

📰

Windows下Node.js多版本管理:手动安装与nvm-windows切换实战

同时维护几个前端项目的人,大概率都碰过 nodejs 版本不一致的麻烦:老后台依赖旧版 Node,新项目又要求新版 Node,手动改环境变量改到怀疑人生。这时候要么同时安装多个 nodejs 版本并按需切换,要么直接用 nvm 做版本管理…

📰

IDEA右键新建Java Class选项消失?排查顺序与解决方案

IDEA右键新建时没有Java Class选项?别急着重装,先按这个排查顺序来用IDEA做Java开发,最让人措手不及的往往不是代码报错,而是工具本身突然“闹脾气”。前两天就有个同事在群里发截图问:在目录上右键想新建一个Java Cla…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬