18_MySQL 智能巡检方案 —— 巡检项清单 / 一键巡检脚本 / 健康评分

18_MySQL 智能巡检方案 ------ 巡检项清单 / 一键巡检脚本 / 健康评分

系列定位 :《MySQL 数据库全栈运维实战系列》第 18 篇,与《Oracle 数据库全栈运维实战系列(VMware 版)》同构对标(Oracle 18 智能巡检)。适用版本 :MySQL 8.0(5.7 差异随文标注)。官方文档:MySQL 8.0 Reference Manual(System Variables / Status Variables / performance_schema)。


一、巡检体系全景

图 1

图 2

巡检域 核心检查项 类比 Oracle 巡检
实例状态 实例是否运行、运行时长、版本 实例状态 / 启动时间
连接 当前连接数/上限、异常断开 会话数/进程数
性能 QPS、慢查询、命中率 AWR 负载
锁与事务 锁等待、长事务、阻塞 enq 等待 / 阻塞会话
复制 IO/SQL 线程、延迟、GTID DG 状态 / lag
空间 库表大小、磁盘占用 表空间使用率
备份 最近备份是否成功/新鲜 备份巡检
参数 关键参数是否合规 参数合规检查

二、巡检项清单(检查标准与阈值)

# 巡检项 健康标准 异常判定 类比 Oracle
1 实例连通 mysql_up 正常 连不上 P0 实例 down
2 连接数使用率 < 60% max_connections > 80% P1 sessions/limit
3 慢查询速率 平稳 突增 3 倍 P2 慢 SQL
4 Buffer Pool 命中率 > 99% < 95% P2 buffer cache hit
5 行锁等待 接近 0 持续 > 0 P1 行锁等待
6 长事务 无 > 300s 存在 P1 长事务
7 从库 IO/SQL 线程 均 Yes 任一 No P0 DG apply/transport
8 主从延迟 < 10s > 60s P1 DG lag
9 最大表空间 增长正常 单库 > 磁盘 80% P1 表空间
10 备份新鲜度 24h 内有成功备份 > 48h P1 备份巡检
11 binlog 保留 按策略保留 磁盘满 P0 归档
12 参数合规 innodb_buffer_pool_size≈60~70%内存 偏小 P2 参数建议

三、一键巡检脚本(可直接复制)

脚本通过 mysql 客户端连库,逐项采集并加权打分。以下为生产可改造的骨架。

复制代码
#!/bin/bash
# mysql_inspect.sh ------ MySQL 一键巡检(解释:用法 ./mysql_inspect.sh -h 127.0.0.1 -P 3306 -u exporter -p 'xxx')
HOST=127.0.0.1; PORT=3306; USER=exporter; PASS='Exp@Pass2026'
while getopts "h:P:u:p:" opt; do
  case $opt in h)HOST=$OPTANT;; P)PORT=$OPTANT;; u)USER=$OPTANT;; p)PASS=$OPTANT;; esac
done
MYSQL="mysql -h$HOST -P$PORT -u$USER -p$PASS -N -B"
SCORE=100
echo "========== MySQL 巡检报告 $HOST:$PORT $(date) =========="

# ① 实例状态(解释:能查到版本即实例正常)
VERSION=$($MYSQL -e "SELECT @@version" 2>/dev/null)
if [ -z "$VERSION" ]; then echo "[P0] 实例无法连接"; SCORE=$((SCORE-40)); else echo "[OK] 实例版本: $VERSION"; fi

# ② 连接数使用率(解释:当前连接 / 上限)
CONN=$($MYSQL -e "SHOW GLOBAL STATUS LIKE 'Threads_connected'" | awk '{print $2}')
MAXCONN=$($MYSQL -e "SHOW VARIABLES LIKE 'max_connections'" | awk '{print $2}')
PCT=$((CONN*100/MAXCONN))
echo "[INFO] 连接数 $CONN / $MAXCONN (${PCT}%)"
if [ $PCT -gt 80 ]; then echo "[P1] 连接数超 80%"; SCORE=$((SCORE-15)); fi

# ③ 运行时长(解释:uptime 突降说明刚重启)
UPTIME=$($MYSQL -e "SHOW GLOBAL STATUS LIKE 'Uptime'" | awk '{print $2}')
echo "[INFO] 运行时长 ${UPTIME} 秒"
if [ $UPTIME -lt 3600 ]; then echo "[P2] 实例运行不足 1 小时(可能刚重启)"; SCORE=$((SCORE-5)); fi

# ④ 慢查询总数(解释:慢查询累计量,结合趋势)
SLOW=$($MYSQL -e "SHOW GLOBAL STATUS LIKE 'Slow_queries'" | awk '{print $2}')
echo "[INFO] 累计慢查询 $SLOW"

# ⑤ 行锁等待(解释:InnoDB 行锁等待次数)
LOCKWAIT=$($MYSQL -e "SHOW GLOBAL STATUS LIKE 'Innodb_row_lock_waits'" | awk '{print $2}')
echo "[INFO] 行锁等待累计 $LOCKWAIT"

# ⑥ 长事务(解释:运行 > 300 秒的事务)
LONGTRX=$($MYSQL -e "SELECT COUNT(*) FROM information_schema.innodb_trx
                     WHERE TIMESTAMPDIFF(SECOND, trx_started, NOW()) > 300")
echo "[INFO] 长事务(>300s) 数量: $LONGTRX"
if [ "$LONGTRX" -gt 0 ]; then echo "[P1] 存在长事务"; SCORE=$((SCORE-15)); fi

# ⑦ 从库复制状态(解释:仅从库有值;主库该查询返回空)
IO_RUN=$($MYSQL -e "SHOW REPLICA STATUS\G" 2>/dev/null | grep "Replica_IO_Running:" | awk '{print $2}')
SQL_RUN=$($MYSQL -e "SHOW REPLICA STATUS\G" 2>/dev/null | grep "Replica_SQL_Running:" | awk '{print $2}')
LAG=$($MYSQL -e "SHOW REPLICA STATUS\G" 2>/dev/null | grep "Seconds_Behind_Source:" | awk '{print $2}')
if [ -n "$IO_RUN" ]; then
  echo "[INFO] 从库 IO=$IO_RUN SQL=$SQL_RUN 延迟=${LAG}s"
  if [ "$IO_RUN" != "Yes" ] || [ "$SQL_RUN" != "Yes" ]; then echo "[P0] 复制线程异常"; SCORE=$((SCORE-30)); fi
  if [ "$LAG" -gt 60 ] 2>/dev/null; then echo "[P1] 主从延迟 >60s"; SCORE=$((SCORE-10)); fi
fi

# ⑧ Buffer Pool 命中率(解释:1 - 物理读/逻辑读,应 > 99%)
BP_READS=$($MYSQL -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads'" | awk '{print $2}')
BP_REQS=$($MYSQL -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read_requests'" | awk '{print $2}')
if [ "$BP_REQS" -gt 0 ] 2>/dev/null; then
  HIT=$(awk "BEGIN{printf \"%.2f\", (1 - $BP_READS/$BP_REQS)*100}")
  echo "[INFO] Buffer Pool 命中率 ${HIT}%"
  awk "BEGIN{exit !($HIT < 95)}" && { echo "[P2] Buffer 命中率 < 95%"; SCORE=$((SCORE-8)); }
fi

# ⑨ 磁盘使用率(解释:guest 视角,thin 置备需宿主复核)
DISKUSAGE=$(df -P /var/lib/mysql | awk 'NR==2{print $5}' | tr -d '%')
echo "[INFO] 数据目录磁盘使用率 ${DISKUSAGE}% (guest 视角)"
if [ "$DISKUSAGE" -gt 80 ]; then echo "[P1] 磁盘 > 80%"; SCORE=$((SCORE-12)); fi
if [ "$DISKUSAGE" -gt 90 ]; then echo "[P0] 磁盘 > 90%"; SCORE=$((SCORE-20)); fi

# ⑩ 备份新鲜度(解释:xtrabackup 最近一次成功备份时间,来自备份标记文件)
BAK_FILE=/backup/last_success
if [ -f "$BAK_FILE" ]; then
  BAK_TS=$(cat "$BAK_FILE")
  BAK_AGE=$(( $(date +%s) - BAK_TS ))
  BAK_HOURS=$(( BAK_AGE/3600 ))
  echo "[INFO] 最近一次成功备份距今 ${BAK_HOURS} 小时"
  if [ "$BAK_HOURS" -gt 48 ]; then echo "[P1] 备份超过 48h"; SCORE=$((SCORE-12)); fi
else
  echo "[P2] 未找到备份成功标记文件"; SCORE=$((SCORE-8))
fi

# ⑪ 表空间大小 Top(解释:按库统计数据目录占用)
echo "--- Top 库占用 ---"
$MYSQL -e "SELECT table_schema,
           ROUND(SUM(data_length+index_length)/1024/1024,1) AS MB
           FROM information_schema.tables
           GROUP BY table_schema ORDER BY MB DESC LIMIT 5;"

# ⑫ 评分等级(解释:按总分映射等级与处置动作)
if   [ $SCORE -ge 90 ]; then GRADE="健康(例行)"
elif [ $SCORE -ge 75 ]; then GRADE="良好(关注趋势)"
elif [ $SCORE -ge 60 ]; then GRADE="警告(定位扣分项)"
else GRADE="危险(立即介入)"; fi
[ $SCORE -lt 0 ] && SCORE=0
echo "========== 健康评分: $SCORE / 100  等级: $GRADE =========="

# 运行巡检(解释:输出报告并可邮件/Webhook 推送)
chmod +x mysql_inspect.sh
./mysql_inspect.sh -h 192.168.10.51 -P 3306 -u exporter -p 'Exp@Pass2026' > inspect_$(date +%F).log

5.7 差异 :5.7 用 SHOW SLAVE STATUS,字段为 Slave_IO_Running / Slave_SQL_Running / Seconds_Behind_Master;8.0 改为 SHOW REPLICA STATUS 与 Replica_* 命名。脚本可按 @@version 分支兼容。


四、健康评分模型

图 3

图 4

分数区间 等级 处置
90~100 健康 例行
75~89 良好 关注趋势
60~74 警告 定位扣分项
< 60 危险 立即介入

4.1 评分细则表(扣分矩阵)

检查项 触发条件 扣分 级别
实例连通 连不上 -40 P0
复制线程 IO 或 SQL 线程非 Yes -30 P0
磁盘使用率 > 90% / > 80% -20 / -12 P0/P1
连接数使用率 > 80% max_connections -15 P1
长事务 存在 > 300s 事务 -15 P1
主从延迟 > 60s -10 P1
备份新鲜度 > 48h 无成功备份 -12 P1
Buffer 命中率 < 95% -8 P2
备份标记缺失 无 last_success 文件 -8 P2
运行时长 < 1h(疑似刚重启) -5 P2

评分规则 :基础分 100,逐项累加扣分,扣到 0 为止(不出现负分)。同一项只扣一次(脚本里 if 单分支),避免重复扣分;多类隐患叠加时分数快速跌破警戒线,正好反映真实风险。


五、巡检结果落库与上报 Prometheus

图 5

巡检不能只"打印到日志",要持久化 + 可视化。两种落地方式:① 写入本地 sqlite/csv 留痕;② 通过 node_exporter 的 textfile collector 暴露成指标,进 Grafana 看板。

5.1 上报为 Prometheus 指标(textfile collector)

复制代码
# 巡检脚本末尾追加(解释:把健康评分写进 node_exporter 可读的 .prom 文件)
TEXTFILE_DIR=/var/lib/node_exporter/textfile_collector
mkdir -p $TEXTFILE_DIR
cat > $TEXTFILE_DIR/mysql_inspect.prom <<EOF
# HELP mysql_inspect_health_score MySQL 巡检健康评分 0~100
# TYPE mysql_inspect_health_score gauge
mysql_inspect_health_score{instance="$HOST:$PORT"} $SCORE
# HELP mysql_inspect_grade 巡检等级 1=健康 2=良好 3=警告 4=危险
# TYPE mysql_inspect_grade gauge
mysql_inspect_grade{instance="$HOST:$PORT"} $(case $GRADE in *例行*)echo 1;;*趋势*)echo 2;;*扣分*)echo 3;;*)echo 4;;esac)
EOF

# Grafana 看板直接展示巡检评分(解释:低于 75 自动标红)
mysql_inspect_health_score
# 配套告警:评分跌破 75 触发(解释:与第19篇 Alertmanager 衔接)
#   mysql_inspect_health_score < 75  for: 1m  -> severity P1

5.2 巡检结果落库(csv 留痕,便于回溯趋势)

复制代码
# 巡检输出追加一行到 csv(解释:字段=时间,实例,评分,等级,关键隐患数)
echo "$(date '+%F %T'),$HOST:$PORT,$SCORE,\"$GRADE\"" >> /var/log/mysql_inspect/history.csv

VMware 注意事项 :textfile collector 的 .prom 目录要和 node_exporter 的 --collector.textfile.directory 参数指向一致;巡检脚本与 node_exporter 跑在同一虚机,注意文件属主权限(node_exporter 进程要能读该目录)。
VMware 注意事项:巡检脚本若跑在虚机内,注意 ① 巡检用只读账号,避免误操作写库;② 长事务、锁等待查询会短暂加元数据锁,建议低峰执行;③ 磁盘类巡检(df)需在虚机宿主视角评估,thin 置备的虚机磁盘实际增长可能滞后于 guest 内显示,巡检报告应注明"guest 视角"。


六、定时巡检(与第 19 篇衔接)

图 6

复制代码
# crontab 每天 08:00 跑一次巡检并归档(解释:定时触发,报告推送见第19篇)
0 8 * * * /opt/scripts/mysql_inspect.sh -h192.168.10.51 -uexporter -p'Exp@Pass2026' \
  >> /var/log/mysql_inspect/$(date +\%F).log 2>&1

七、要点速记

  1. 巡检八域:实例/连接/性能/锁事务/复制/空间/备份/参数。
  2. 一键脚本 :用只读账号连库,逐条 SHOW GLOBAL STATUS + information_schema 采集。
  3. 健康评分:P0 扣 30~40、P1 扣 10~15、P2 扣 5,区间分级处置。
  4. 重点盯长事务与复制线程:这两类是生产最常见的隐患源。
  5. 定时化:cron 每日巡检,报告推送接第 19 篇 Webhook/告警。

八、踩坑记录(实测汇总)

# 坑 现象 解决
1 巡检用高权限账号 误操作写库 只读账号 exporter
2 锁/长事务查询高峰跑 短暂元数据锁 低峰执行
3 5.7/8.0 字段名混用 脚本取不到复制值 按版本分支 SHOW SLAVE/REPLICA
4 uptime 突降误判 判为重启 结合错误日志确认是否真重启
5 thin 置备磁盘 guest 内空间显示滞后 巡检注明 guest 视角,宿主侧复核
6 连接数只看当前值 漏掉瞬时峰值 配合 Prometheus 历史曲线
7 长事务阈值过大 漏报 按业务设 300s 内
8 备份巡检只查存在 备份可不可恢复未知 定期恢复演练(第07篇)
9 报告没人看 巡检流于形式 评分 <75 自动升级(第19篇)
10 脚本硬编码密码 泄露 用配置文件/环境变量

九、参考资料(官方正式文档)

主题 官方链接
MySQL 8.0 Reference Manual https://dev.mysql.com/doc/refman/8.0/en/
Server Status Variables https://dev.mysql.com/doc/refman/8.0/en/server-status-variables.html
information_schema InnoDB Trx https://dev.mysql.com/doc/refman/8.0/en/information-schema-innodb-trx-table.html
Replication 状态视图 https://dev.mysql.com/doc/refman/8.0/en/replication-monitoring.html
performance_schema https://dev.mysql.com/doc/refman/8.0/en/performance-schema.html

本文章属于《MySQL 数据库全栈运维实战系列》监控与巡检篇。欢迎收藏、交流。

相关推荐
java_logo7 分钟前
Docker 部署 Liquibase:轻松搭建数据库变更管理
数据库·docker·容器·数据库管理·liquibase·轩辕镜像·数据库变更
凤凰院凶涛QAQ2 小时前
《MySQL内核拆解:从SQL到InnoDB》(四) : 联合查询 & 视图
数据库·sql·mysql
码农小河662 小时前
基于SSM+JSP的高校专业信息管理系统【附源码+数据库】
java·开发语言·数据库
张小姐的猫2 小时前
【MySQL】访问 & 数据流动原理
android·数据库·mysql·adb·1024程序员节
天远API4 小时前
零信任架构实战:基于天远运营商三要素详版V即时版构建自动化消费电子大促电商平台高价值权益秒杀与优惠券防羊毛高并发实名核验网关
运维·人工智能·架构·自动化
Android系统攻城狮5 小时前
Linux FFmpeg深度解析之avcodec_default_get_encode_buffer调用流程与实战(二十八)
linux·运维·服务器·ffmpeg·车载音视频·ffmpeg音视频
乐维_lwops6 小时前
案例解读:大型综合性科创产业园运维监控落地实践
运维·网络·人工智能·安全·it监控·国产运维智能体
这个DBA有点耶6 小时前
信创场景下数据同步软件怎么选?对比开源CDC与原生闭环工具的结构性差异
数据库·mysql·架构