4. MySQL Binlog 原理:Binlog 格式与日志结构解析

Binlog,说白了就是 MySQL 的“操作日记”。

它记录了所有改变数据库内容的操作——INSERT、UPDATE、DELETE,以及表结构变更。CDC 管道要捕捉增量数据,Binlog 就是最核心的数据源。我个人习惯把 Binlog 比作飞机的黑匣子:平时你可能不太关注它,但一旦需要排查问题或做数据同步,你就得靠它还原现场。

4.1 Binlog 的三种格式

MySQL 提供了三种 Binlog 格式:STATEMENT、ROW 和 MIXED。它们各有各的脾气,选错了格式,后面 CDC 管道跑起来会非常痛苦。

格式 记录方式 优点 缺点
STATEMENT 记录执行的 SQL 语句 日志量小,易于阅读 非确定性函数(如 NOW()、UUID())会导致主从不一致
ROW 记录每一行数据的变化(前镜像 + 后镜像) 精确、安全,CDC 解析最友好 日志量大,尤其批量操作时
MIXED 混合模式:默认用 STATEMENT,遇到非确定性语句自动切换为 ROW 兼顾日志量和安全性 切换逻辑对 CDC 解析不够透明

我的建议:做 CDC 增量同步,直接选 ROW 格式。别犹豫。

为什么?因为 ROW 格式记录了每一行数据变更的“前值”和“后值”。你解析 Binlog 时,可以直接拿到完整的字段内容,不需要回查数据库。STATEMENT 格式虽然日志小,但解析 SQL 语句再回放,不确定性太大。

避坑指南:我曾经接手过一个项目,生产环境用的是 STATEMENT 格式。结果有一次 UPDATE 语句里用了 LIMIT,主库和从库更新的行数不一样,数据直接对不齐。从那以后,我所有 CDC 项目都强制要求 ROW 格式。

4.2 Binlog 开启配置

开启 Binlog 其实就改几个参数。但很多人踩过坑——改完配置忘了重启,或者日志文件撑爆磁盘。

在 MySQL 配置文件(my.cnf 或 my.ini)的 [mysqld] 段下,加上这几行:

[mysqld]
# 开启 Binlog
log_bin = mysql-bin

# 指定 Binlog 格式(CDC 必选 ROW)
binlog_format = ROW

# 每个 Binlog 文件的最大大小(单位:字节,默认 1G)
max_binlog_size = 1G

# Binlog 保留天数(根据磁盘空间调整)
expire_logs_days = 7

# 可选:指定要记录的数据库(留空表示全部)
# binlog_do_db = your_database

# 可选:指定不记录的数据库
# binlog_ignore_db = mysql

改完后,重启 MySQL 服务。验证是否生效:

mysql> SHOW VARIABLES LIKE 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+

mysql> SHOW VARIABLES LIKE 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+

注意:修改 binlog_format 需要重启 MySQL。如果你用的是云数据库(如 RDS),通常可以在控制台直接修改参数组,但也要触发重启。我建议在业务低峰期操作,避免影响线上服务。

4.3 Binlog 日志结构解析

Binlog 不是纯文本文件,它是二进制格式。你直接用 cat 打开会看到一堆乱码。MySQL 提供了 mysqlbinlog 工具来解析它。

先看一个 ROW 格式的 Binlog 事件片段:

# at 219
#250101 10:00:00 server id 1  end_log_pos 315 CRC32 0x12345678 	Table_map: `test`.`users` mapped to number 89
# at 315
#250101 10:00:00 server id 1  end_log_pos 400 CRC32 0x9abcdef0 	Write_rows: table id 89 flags: STMT_END_FIL
### INSERT INTO `test`.`users`
### SET
###   @1=1001 /* INT meta=0 nullable=0 is_null=0 */
###   @2='Alice' /* VARSTRING(100) meta=100 nullable=0 is_null=0 */
###   @3='alice@example.com' /* VARSTRING(200) meta=200 nullable=1 is_null=0 */

这里面有几个关键信息:

  • 位置(at 219):事件在 Binlog 文件中的偏移量。CDC 管道就是靠这个位置来断点续传的。
  • 时间戳:事件发生的时间。
  • server id:哪个 MySQL 实例产生的。主从复制时靠这个区分来源。
  • end_log_pos:下一个事件的起始位置。
  • 事件类型:Table_map 映射表结构,Write_rows 表示插入行。
  • 字段值:@1 表示第 1 列,后面跟着实际数据。

4.4 Binlog 事件类型与结构

Binlog 里的事件类型很多,但 CDC 管道最关心的是这几种:

事件类型 含义 CDC 处理方式
TABLE_MAP 映射表 ID 到表结构 解析表名、列名、列类型
WRITE_ROWS INSERT 操作 提取后镜像(新增的行数据)
UPDATE_ROWS UPDATE 操作 提取前镜像和后镜像(修改前后的数据)
DELETE_ROWS DELETE 操作 提取前镜像(被删除的行数据)
ROTATE Binlog 文件切换 更新当前读取的文件名和位置
FORMAT_DESCRIPTION Binlog 文件头信息 校验 Binlog 版本和服务器信息

每个事件的结构大致如下:

+---------------------+
|  Event Header       |  ← 固定 19 字节:时间戳、事件类型、server id、end_log_pos 等
+---------------------+
|  Event Body         |  ← 变长:具体数据(行数据、表映射信息等)
+---------------------+
|  CRC32 Checksum     |  ← 可选(MySQL 5.6+ 默认开启)
+---------------------+

经验之谈:解析 Binlog 时,TABLE_MAP 事件和 WRITE_ROWS / UPDATE_ROWS / DELETE_ROWS 事件是成对出现的。先有 TABLE_MAP 告诉你表结构,再有行事件告诉你具体数据。我见过有人只解析行事件,结果拿不到列名,数据对不上号。

4.5 Binlog 整体结构图

下面这张图展示了 Binlog 文件的整体结构,以及 CDC 管道如何消费它:

Binlog 文件结构与 CDC 消费流程 mysql-bin.000001 FORMAT_DESCRIPTION TABLE_MAP (表结构) WRITE_ROWS (数据) ROTATE (切换) CDC 管道(Canal / Debezium / Maxwell) Kafka / Pulsar 消息队列 数据湖 / 数据仓库 缓存 / 搜索引擎 关键点: • Binlog 文件由多个事件顺序组成,CDC 管道从第一个事件开始顺序读取。 • 每个事件都有 end_log_pos,CDC 管道用它来记录消费进度,实现断点续传。

4.6 实战:用 mysqlbinlog 查看 Binlog

你可以在服务器上直接跑 mysqlbinlog 命令,看看 Binlog 里到底长什么样:

# 查看某个 Binlog 文件的内容(ROW 格式,带详细注释)
mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000001

# 只看某个时间范围的事件
mysqlbinlog --start-datetime="2025-01-01 10:00:00" --stop-datetime="2025-01-01 11:00:00" mysql-bin.000001

# 只看某个位置之后的事件(断点续传时常用)
mysqlbinlog --start-position=219 mysql-bin.000001

注意:如果你用 ROW 格式,不加 --base64-output=DECODE-ROWS -v 参数,看到的是一堆 Base64 编码的乱码。加上 -v 才会显示可读的 SQL 注释。我第一次用 mysqlbinlog 时没加这个参数,还以为 Binlog 坏了。

4.7 总结一下

Binlog 是 CDC 管道的基石。你只要记住三件事:

  • 格式选 ROW,别给自己找麻烦。
  • 配置要合理,日志保留天数、文件大小、磁盘空间都得算清楚。
  • 结构要搞懂,事件类型、位置偏移、表映射,这些是解析 Binlog 的核心。

嗯,这一章的内容就到这儿。Binlog 的原理搞清楚了,后面搭建 CDC 管道时你就能理解每一步在做什么。