4. 源端监控实战(MySQL Binlog)

好,咱们进入实战环节。CDC 链路的第一站,就是 MySQL 的 Binlog。你想想看,如果源头的数据都抓不准、抓不全,后面整个链路就是空中楼阁。所以源端监控,我把它放在全链路监控的第一位。

这一章,我们聚焦四个核心指标:Binlog 生成速率、磁盘空间、主从延迟、解析异常。这四个点,是我在几十套生产环境里踩坑踩出来的。每一个都出过事故,每一个都有血的教训。

核心观点:源端监控不是看 Binlog 有没有,而是看 Binlog 生成得「快不快」、磁盘「够不够」、主从「同步是否及时」、解析「有没有报错」。缺一个,事故就在路上。

源端监控四大核心维度 MySQL Binlog 监控 ① Binlog 生成速率 ② 磁盘空间监控 ③ 主从延迟监控 ④ 解析异常监控 监控目标: • 生成速率:MB/s 或 events/s • 磁盘空间:使用率 > 80% 预警 • 主从延迟:Seconds_Behind_Master • 解析异常:错误日志 + 重试次数

4.1 Binlog 生成速率监控

Binlog 生成速率,说白了就是 MySQL 每秒往磁盘上写了多少 Binlog。这个指标直接反映了数据库的写入压力。我见过一个案例,业务高峰期 Binlog 生成速率飙到 200MB/s,结果下游 Canal 消费不过来,Binlog 文件堆积,磁盘直接打满。

怎么监控?我一般用两种方式:

  1. 文件系统级: 通过 stat 或 du 定时采集 Binlog 文件大小变化。
  2. MySQL 内部: 通过 SHOW MASTER STATUS 的 File 和 Position 字段计算。

下面是我常用的监控脚本片段:

#!/bin/bash
# Binlog 生成速率监控脚本
# 每 60 秒采集一次

BINLOG_DIR="/var/lib/mysql"
INTERVAL=60

while true; do
  # 获取当前 Binlog 文件大小
  CURRENT_FILE=$(mysql -e "SHOW MASTER STATUS\G" | grep "File" | awk '{print $2}')
  CURRENT_SIZE=$(stat -c%s "$BINLOG_DIR/$CURRENT_FILE")
  
  sleep $INTERVAL
  
  # 再次获取
  NEW_SIZE=$(stat -c%s "$BINLOG_DIR/$CURRENT_FILE")
  
  # 计算速率(字节/秒)
  RATE=$(( (NEW_SIZE - CURRENT_SIZE) / INTERVAL ))
  
  echo "$(date '+%Y-%m-%d %H:%M:%S') | Binlog: $CURRENT_FILE | Rate: $RATE bytes/s"
  
  # 告警阈值:超过 50MB/s 触发
  if [ $RATE -gt $((50 * 1024 * 1024)) ]; then
    echo "WARNING: Binlog 生成速率过高!当前: $RATE bytes/s"
    # 这里可以接入告警系统
  fi
done

我的经验: 速率阈值要动态调整。白天业务高峰期 50MB/s 可能正常,凌晨 2 点 10MB/s 就算异常。我习惯按「基线 + 3σ」的方式设定动态阈值,而不是固定值。

4.2 Binlog 磁盘空间监控

这个监控点,说白了就是看磁盘会不会被 Binlog 撑爆。MySQL 的 Binlog 默认不会自动删除,除非你设置了 expire_logs_days 或 binlog_expire_logs_seconds。但即使设置了,如果生成速率突然暴增,磁盘还是可能被打满。

我记得有一次,某电商大促期间,Binlog 生成速率是平时的 10 倍。虽然设置了 7 天过期,但磁盘还是 3 天就满了。结果 MySQL 直接 Hang 住,因为写不了 Binlog 了。嗯,那次事故让我养成了一个习惯:磁盘使用率超过 80% 就要预警,超过 90% 必须立即处理。

监控命令很简单:

# 查看 Binlog 目录磁盘使用率
df -h /var/lib/mysql

# 查看 Binlog 文件列表及大小
ls -lh /var/lib/mysql/mysql-bin.*

# 查看 Binlog 过期设置
mysql -e "SHOW VARIABLES LIKE 'expire_logs_days';"
mysql -e "SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';"

我建议的监控指标如下:

指标 正常范围 预警阈值 告警阈值
磁盘使用率 < 60% 80% 90%
Binlog 文件数 < 50 个 100 个 200 个
最大 Binlog 文件大小 < 1GB 2GB 5GB
Binlog 过期时间 7 天 < 3 天 < 1 天

注意: 不要等到磁盘满了再处理。一旦 MySQL 因为写不了 Binlog 而 Hang 住,恢复起来非常麻烦。我曾经遇到过需要手动清理 Binlog 文件,然后重启 MySQL 的情况,那个过程简直是噩梦。

4.3 主从延迟监控

主从延迟,是 CDC 同步中最常见的坑。你想想看,如果主库写入了数据,但从库还没同步过来,CDC 工具(比如 Canal)连接的是从库,那它读到的 Binlog 就是滞后的。数据延迟就这么产生了。

监控主从延迟,最直接的方式就是看 Seconds_Behind_Master。但这个指标有个问题:它只反映 SQL 线程的延迟,不反映 IO 线程的延迟。也就是说,如果从库的 IO 线程已经落后了,但 SQL 线程还在拼命追,这个值可能显示为 0。

所以我一般会同时监控三个指标:

  1. Seconds_Behind_Master: 传统延迟指标,单位秒。
  2. Master_Log_File 和 Relay_Master_Log_File: 对比这两个文件是否一致,判断 IO 线程是否落后。
  3. Read_Master_Log_Pos 和 Exec_Master_Log_Pos: 对比这两个位置,判断 SQL 线程是否落后。
mysql -e "SHOW SLAVE STATUS\G" | grep -E "Seconds_Behind_Master|Master_Log_File|Relay_Master_Log_File|Read_Master_Log_Pos|Exec_Master_Log_Pos"

输出示例:

             Master_Log_File: mysql-bin.000123
         Relay_Master_Log_File: mysql-bin.000123
          Read_Master_Log_Pos: 456789012
          Exec_Master_Log_Pos: 456789012
        Seconds_Behind_Master: 0

如果 Master_Log_File 和 Relay_Master_Log_File 不一致,说明 IO 线程落后了。如果 Read_Master_Log_Pos 和 Exec_Master_Log_Pos 不一致,说明 SQL 线程落后了。

避坑指南: 我曾经遇到过一个案例,Seconds_Behind_Master 显示为 0,但数据就是延迟了 10 分钟。后来发现是因为从库的 IO 线程卡住了,但 SQL 线程已经把 Relay Log 消费完了,所以显示为 0。从那以后,我坚持同时监控文件位置,而不是只看秒数。

4.4 Binlog 解析异常监控

这个监控点,是 CDC 工具特有的。Binlog 本身是二进制格式,需要解析成可读的事件。如果解析过程中出现异常,比如 Binlog 文件损坏、格式不兼容、或者 MySQL 版本升级导致的事件格式变化,CDC 工具就会报错。

我常用的监控方式有两种:

  • 工具日志监控: 比如 Canal 的 canal.log,Debezium 的 connector.log。定期扫描日志中的 ERROR 和 WARN 级别日志。
  • 心跳检测: 在源库创建一个心跳表,每隔几秒更新一条记录。CDC 工具如果能正常解析这条记录,说明链路正常。如果超过一定时间没收到心跳,说明解析可能出了问题。

下面是一个简单的日志监控脚本:

#!/bin/bash
# Binlog 解析异常监控脚本
LOG_FILE="/opt/canal/logs/canal.log"
KEYWORDS=("ERROR" "parse failed" "binlog checksum" "unknown event")

tail -f $LOG_FILE | while read line; do
  for keyword in "${KEYWORDS[@]}"; do
    if echo "$line" | grep -qi "$keyword"; then
      echo "$(date) | 发现解析异常: $line"
      # 触发告警
      curl -X POST http://alert-server/api/v1/alert \
        -d "source=canal&message=$line"
    fi
  done
done

重要提醒: Binlog 解析异常一旦发生,通常意味着数据丢失或数据错乱。不要只依赖日志监控,一定要配合心跳检测。我见过一个案例,Canal 日志一直正常,但实际已经停止解析新数据了,因为 Binlog 文件被意外 rotate 了。心跳检测能第一时间发现这种「静默故障」。

4.5 小结

源端监控,说白了就是盯住 Binlog 的「量」和「质」。量是生成速率和磁盘空间,质是主从同步和解析正确性。这四个监控点,缺一不可。