原生mysqld_exporter无法监控备份状态,因其仅采集mysql内部指标,不感知外部备份脚本的退出码、日志或标记文件;必须通过在备份脚本末尾写入原子化标记文件,并扩展mysqld_exporter新增backup_status collector来暴露mysql_backup_last_success_seconds_ago等自定义指标,再结合时效性与状态双维度编写告警规则。

直接回答:不能靠原生 mysqld_exporter 监控备份状态,必须自行扩展或改写采集器 —— 因为备份成功与否不体现在 MySQL 内部状态里,而是由外部脚本(如 xtrabackup)的退出码、日志文件或标记文件决定。
为什么原生 mysqld_exporter 无法监控备份
原生 mysqld_exporter 只连接 MySQL 实例,执行 SHOW STATUS、SHOW VARIABLES、SELECT 系统表等 SQL 查询。它完全不感知外部备份进程是否存在、是否成功、是否超时。即使 xtrabackup 执行失败卡死,MySQL 实例本身仍可能返回 mysql_up{job="mysql"} == 1,造成严重误判。
常见错误现象包括:
- 告警规则只盯
mysql_up或mysql_global_status_uptime,但备份失败了却收不到通知 - 用
node_exporter监控备份目录 mtime,但无法区分“备份启动中”和“备份成功完成” - 把
xtrabackup日志塞进 Loki 后再做关键词匹配,延迟高、告警链路长、且无法直接关联 Prometheus 告警路由
如何让 Prometheus 知道备份是否成功
核心思路是:用一个轻量级程序(可复用 mysqld_exporter 框架)定期检查备份结果,并暴露为自定义指标。推荐在原有 exporter 上增加 collector,而非另起服务。
实操要点:
- 备份脚本末尾必须写一个标记文件,例如
/var/lib/mysql-backup/last_success,内容为 Unix 时间戳;失败时不更新或写/var/lib/mysql-backup/last_failed - 新增的 Go collector(如
backup_status.go)读取该文件,计算距今秒数,输出mysql_backup_last_success_seconds_ago和mysql_backup_status{state="success"} 1 - 指标名必须带
mysql_前缀、使用namespace保持一致性,否则 Grafana 面板和告警规则无法复用原生态 MySQL 监控体系 - 避免在 collector 中调用
exec.Command运行xtrabackup --version等命令 —— 抓取周期内多次 fork 子进程易引发资源抖动
告警规则怎么写才可靠
不能只判断“有没有成功记录”,要结合时效性与状态双维度。例如:
groups:
- name: mysql-backup-alerts
rules:
- alert: MySQLBackupStale
expr: mysql_backup_last_success_seconds_ago > 86400
for: 10m
labels:
severity: warning
annotations:
summary: "MySQL 备份已超过 24 小时未成功"
- alert: MySQLBackupFailed
expr: mysql_backup_status{state="failed"} == 1
for: 2m
labels:
severity: critical
annotations:
summary: "MySQL 最近一次备份明确失败"
注意点:
-
for: 2m是必须的 —— 避免因 collector 抓取间隙导致瞬时抖动触发误告 - 不要用
absent(mysql_backup_status{state="success"})做“缺失即失败”的逻辑,因为 exporter 启动失败或配置错误时也会触发,无法区分真失败和采集断连 - 如果备份任务跨多实例(主+从),需确保每个实例的标记文件路径独立,且
mysqld_exporter启动时通过--web.listen-address绑定不同端口,或用relabel_configs注入 instance 标签
最易被忽略的一点:标记文件的写入必须是原子操作。不要 echo $(date +%s) > last_success,而要用 echo $(date +%s) > last_success.tmp && mv last_success.tmp last_success —— 否则 Prometheus 抓取时可能读到空文件或截断内容,导致 mysql_backup_last_success_seconds_ago 变成 0,误判为“刚刚成功”。











