SHOW BINARY LOGS 不能直接反映异常频率,因为它仅显示 binlog 文件列表及大小等静态结果,无法体现单位时间内的事件写入节奏;真正需监控的是 Binlog_bytes_written 增量速率(B/s),结合 Com_commit/Com_rollback 计算平均每事务写入量,并排除备份、重启等因素干扰,才能识别高频小事务等异常行为。

为什么 SHOW BINARY LOGS 不能直接反映异常频率
很多人一上来就用 SHOW BINARY LOGS 查日志列表,再算文件数量或大小变化,但这只能看到“结果”,没法判断“是否异常”。比如业务低峰期每小时生成 1 个 mysql-bin.000001,高峰期每 5 分钟一个,这本身合理;但如果某次主库写入几乎为 0,却每分钟都在滚动新 binlog 文件,那大概率是 binlog_cache_size 过小或事务频繁提交导致的无效刷盘——这才是要监控的“异常频率”。
真正该盯的是单位时间内的 binlog 事件写入节奏,而不是文件名或磁盘占用。
-
SHOW MASTER STATUS返回的File和Position是当前写入点,配合定时采集可算出增量字节数/秒 - 更关键的是
SHOW GLOBAL STATUS LIKE 'Binlog_bytes_written',它统计的是实际写入 binlog 的字节数(不含 header、checksum 等开销),比文件系统层面的ls -l更准 - 注意:该状态变量在 MySQL 8.0.30+ 才稳定支持,旧版本需退而求其次用
Binlog_cache_use/Binlog_cache_disk_use组合推断缓存压力
用 shell 脚本抓取并计算 binlog 写入速率
别依赖单次采样。至少间隔 10 秒采两次 Binlog_bytes_written,再除以时间差,才能得到真实速率(单位:B/s)。脚本里必须加错误兜底——比如 MySQL 连接失败、权限不足(需要 PROCESS 权限)、状态变量不存在(老版本返回空)。
#!/bin/bash
USER="monitor"
PASS="xxx"
HOST="127.0.0.1"
PORT="3306"
<p>get_bytes() {
mysql -u"$USER" -p"$PASS" -h"$HOST" -P"$PORT" -Nse \
"SHOW GLOBAL STATUS LIKE 'Binlog_bytes_written'" 2>/dev/null | awk '{print $2}'
}</p><p>b1=$(get_bytes)
sleep 10
b2=$(get_bytes)</p><p>if [[ -z "$b1" || -z "$b2" ]]; then
echo "ERROR: failed to fetch Binlog_bytes_written"
exit 1
fi</p><p>rate=$(( (b2 - b1) / 10 ))
echo "Binlog write rate: ${rate} B/s"- 务必用
-Nse参数:-N 去掉列名,-s 禁用表格格式,-e 直接执行语句,避免解析干扰 - 不要用
awk '/Binlog_bytes_written/ {print $2}'这种模糊匹配——MySQL 有可能返回多行(如开启 GTID 后附带Binlog_bytes_written_by_gtid) - 如果 rate 持续 > 5MB/s 且无对应业务高峰,就要查
INFORMATION_SCHEMA.INNODB_TRX是否有长事务或未提交小事务刷盘
如何区分“高频小事务”和“正常大写入”
光看字节速率会误判。比如批量导入 1GB 数据,Binlog_bytes_written 短时飙升到 20MB/s 是正常的;但如果是 1000 个 UPDATE t SET x=x+1 WHERE id=123 在 1 秒内执行完,同样产生 2MB binlog,就属于危险信号——它暴露了应用层没合并更新、或 ORM 自动生成低效 SQL。
- 结合
SHOW GLOBAL STATUS LIKE 'Com_commit'和Com_rollback,算出平均每事务写入量:Binlog_bytes_written / (Com_commit + Com_rollback) - 若该值长期 Com_commit > 1000/s,基本可判定为高频小事务
- 检查
innodb_flush_log_at_trx_commit=1是否被意外改成 2 或 0——这会让 binlog 写入看似“变快”,实则牺牲持久性
告警阈值设多少才不误报
没有通用数值。阈值必须基于你自己的基线。先跑 3 天脚本,每 5 分钟采一次,用 awk 统计 P95 和标准差:
awk '{sum+=$1; n++} END {print "avg:", sum/n, "p95:", int(n*0.95)+1}' rates.log然后把告警线设为 avg + 3 * std_dev。硬套“超过 1MB/s 就告警”在 OLAP 场景下每天吵 20 次,在 IoT 设备上报场景下可能一周都收不到一次。
- 务必排除备份工具影响:
mysqldump --single-transaction或mydumper会触发大量 binlog 写入,这类流量应通过PROCESSLIST中的User字段过滤掉 - 监控脚本自身不能成为压力源:避免用
SELECT SLEEP(1)占用连接,也不要每秒轮询——10 秒间隔对 binlog 频率监控已足够敏感 - MySQL 重启后
Binlog_bytes_written归零,脚本需识别该情况并跳过本次计算,否则会出现负速率
真正难的不是采集,而是把“字节速率”翻译成“业务行为是否失控”。这需要你清楚自己数据库的典型事务模式,而不是 blindly trust any threshold.


















