2. MySQL Binlog 基础:三种格式、开启配置与 mysqlbinlog 工具

聊到 CDC,Binlog 是绕不开的起点。我经常跟团队里的新人说,搞懂 Binlog,实时数据这条路你就走通了一半。说白了,Binlog 就是 MySQL 的“操作日记”,记录了所有数据变更。今天咱们就把它的格式、配置和工具讲透。

2.1 Binlog 的三种格式:STATEMENT、ROW、MIXED

Binlog 有三种记录格式。选哪种,直接影响你的 CDC 方案能不能跑得稳。我见过不少项目因为格式选错,后期踩了大坑。

2.1.1 STATEMENT 格式

这种格式只记录 SQL 语句本身。比如你执行了 UPDATE users SET age=age+1 WHERE id>100,Binlog 里就记下这条 SQL。

优点:日志量小,一条 SQL 可能影响一万行,但只记一条记录。

缺点:某些场景下数据不一致。比如用了 NOW()、UUID() 这类函数,主从重放时结果可能不同。

我记得有一次排查线上问题,发现主从数据对不上。查了半天,罪魁祸首就是 STATEMENT 格式下用了 LIMIT 子句的 UPDATE。主库和从库的数据排序不一样,更新结果就偏了。嗯,从那以后我对 STATEMENT 格式就格外小心。

2.1.2 ROW 格式

ROW 格式记录的是每一行数据的变化细节。还是刚才那个 UPDATE,它会记下每一行修改前和修改后的完整数据。

我个人强烈推荐:生产环境用 ROW 格式。CDC 场景下,ROW 格式能精确捕获每一行变更,不会丢失上下文。Debezium、Canal 这些工具都依赖 ROW 格式。

缺点也很明显——日志量大。一次批量更新 10 万行,Binlog 文件会暴涨。我曾经在一个日活千万的系统上,因为没预估好 ROW 格式的日志量,磁盘差点写爆。你想想看,那场面多刺激。

2.1.3 MIXED 格式

MIXED 是前两种的混合体。MySQL 自己判断:安全的 SQL 用 STATEMENT 记,不安全的(比如带函数、子查询的)自动切到 ROW。

听起来很智能对吧?但我在实际项目中很少用。为什么?因为不可控。你没法精确预判 MySQL 什么时候切格式,CDC 消费端处理起来很麻烦。说白了,MIXED 适合“通用场景”,不适合“CDC 专用场景”。

对比维度 STATEMENT ROW MIXED
日志量 小 大 中等
数据一致性 可能不一致 完全一致 基本一致
CDC 适用性 不推荐 强烈推荐 不推荐
典型场景 简单主从复制 数据同步、审计、CDC 通用复制

2.2 Binlog 的开启与配置

Binlog 默认是关闭的。你需要手动开启。我建议你在安装 MySQL 时就配好,别等到需要 CDC 了再回头改。

2.2.1 基础配置

编辑 MySQL 配置文件 my.cnf(Linux)或 my.ini(Windows),在 [mysqld] 段下添加:

[mysqld]
# 开启 Binlog
log-bin=mysql-bin
# 设置格式为 ROW
binlog-format=ROW
# 每个 Binlog 文件最大 1GB
max_binlog_size=1G
# 保留 7 天的 Binlog
expire_logs_days=7
# 要记录的数据库(可选)
binlog-do-db=your_database
# 忽略的数据库(可选)
binlog-ignore-db=mysql

我曾经踩过的坑:expire_logs_days 设得太短,导致 CDC 消费端还没读完,Binlog 就被清理了。建议根据你的消费速度,至少保留 3-7 天。如果数据量大,可以配合 binlog_expire_logs_seconds 做更精细的控制。

2.2.2 验证配置是否生效

重启 MySQL 后,执行以下命令检查:

-- 查看 Binlog 是否开启
SHOW VARIABLES LIKE 'log_bin';

-- 查看当前 Binlog 格式
SHOW VARIABLES LIKE 'binlog_format';

-- 查看所有 Binlog 文件列表
SHOW BINARY LOGS;

如果 log_bin 显示 ON,binlog_format 显示 ROW,恭喜你,配置成功了。

2.2.3 在线切换 Binlog 格式

有些场景下,你可能需要临时切换格式。比如做一次大表归档,想减少日志量。MySQL 支持在线切换:

-- 当前会话级别切换
SET SESSION binlog_format = STATEMENT;

-- 全局级别切换(需要 SUPER 权限)
SET GLOBAL binlog_format = MIXED;

但注意,全局切换后,新的连接才会生效。已经存在的连接不受影响。我一般只在排查问题时用会话级别切换,生产环境从不乱动全局配置。

2.3 mysqlbinlog 工具的使用

mysqlbinlog 是 MySQL 自带的 Binlog 解析工具。虽然现在很多 CDC 框架都封装了解析逻辑,但掌握这个工具,能帮你快速定位问题。

2.3.1 基本用法

查看 Binlog 文件内容:

# 直接查看
mysqlbinlog mysql-bin.000001

# 指定数据库
mysqlbinlog --database=your_db mysql-bin.000001

# 指定起始和结束位置
mysqlbinlog --start-position=100 --stop-position=500 mysql-bin.000001

# 指定时间范围
mysqlbinlog --start-datetime="2024-01-01 00:00:00" --stop-datetime="2024-01-02 00:00:00" mysql-bin.000001

2.3.2 解析 ROW 格式的 Binlog

ROW 格式的 Binlog 默认是二进制内容,直接看是乱码。需要加 --base64-output=DECODE-ROWS 和 -v 参数:

mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000001

这样就能看到类似这样的输出:

### UPDATE `your_db`.`users`
### WHERE
###   @1=1001
###   @2='张三'
###   @3='zhangsan@example.com'
### SET
###   @1=1001
###   @2='张三'
###   @3='newemail@example.com'

你看,每一行变更的前后数据都清清楚楚。这就是 CDC 能精确捕获数据变化的基础。

我个人的调试习惯:先用 mysqlbinlog 解析出 SQL,确认数据变更是否符合预期,再部署 CDC 任务。这能省掉很多排查时间。

2.3.3 恢复数据

mysqlbinlog 还可以用来恢复数据。比如你误删了数据,可以把 Binlog 中的操作回放:

# 将 Binlog 导出为 SQL 文件
mysqlbinlog mysql-bin.000001 > binlog.sql

# 然后执行 SQL 恢复
mysql -u root -p < binlog.sql

但要注意,直接回放整个 Binlog 会把所有操作重做一遍。更精细的做法是指定位置或时间范围,只恢复你需要的那部分。

2.4 知识体系总览

下面这张图把本章的核心知识点串起来了。你可以把它当作一个快速索引:

Binlog 知识体系总览 MySQL Binlog 三种格式 STATEMENT(记录SQL) ROW(记录行变更) MIXED(混合模式) 开启与配置 my.cnf 配置参数 在线切换格式 验证配置生效 mysqlbinlog 查看 Binlog 内容 解析 ROW 格式 数据恢复 核心建议 CDC 场景下,推荐使用 ROW 格式 + 合理配置保留天数 + 掌握 mysqlbinlog 调试技巧

这张图把 Binlog 的三大块——格式、配置、工具——串在了一起。你顺着这个结构往下学,思路会清晰很多。

2.5 本章小结

Binlog 是 CDC 的基石。搞懂了这三种格式的区别,你就能选对方案;掌握了配置方法,你就能让系统稳定运行;会用 mysqlbinlog,你就能在出问题时快速定位。我个人觉得,这一章的内容值得你花时间反复消化。毕竟,地基打不牢,后面盖再高的楼也悬。