2. MySQL Binlog 基础:Binlog 的概念与作用、三种格式、开启与配置

聊到 CDC,尤其是基于 MySQL 的增量数据同步,Binlog 是绕不开的核心。说白了,Binlog 就是 MySQL 的“操作日记本”。你想想看,数据库里每一条 INSERT、UPDATE、DELETE,甚至表结构的变更,都会被记录在这个日志里。我们做数据同步,就是去“偷看”这个日记本,然后把变更内容复制到别的地方去。

我记得刚接触 Binlog 那会儿,总觉得它跟 Redo Log 是一回事。后来踩了坑才明白——Redo Log 是 InnoDB 存储引擎用来保证崩溃恢复的,而 Binlog 是 MySQL Server 层的东西,主要服务于数据复制和恢复。两者分工完全不同。

2.1 Binlog 到底能干什么?

Binlog 的作用,我归纳为三个核心场景:

  • 主从复制:这是最经典的应用。主库写 Binlog,从库拉取并回放,实现数据同步。
  • 数据恢复:当你做了全量备份后,可以用 Binlog 把数据恢复到某个时间点。我遇到过有人误删了整张表,靠 Binlog 一点一点把数据捞回来的情况。
  • 增量数据捕获(CDC):这就是我们课程的核心。通过解析 Binlog,实时获取数据库的变更事件,然后推送到消息队列、数据湖或者另一个数据库。

一句话总结:Binlog 是 MySQL 生态里所有“数据流动”场景的基石。没有它,CDC 就是空中楼阁。

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

MySQL 提供了三种 Binlog 记录格式。每种格式都有它的脾气,选错了会出大问题。我一个个说。

2.2.1 STATEMENT 格式

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

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

缺点:不安全。为什么?因为有些 SQL 是“上下文敏感”的。比如用了 NOW()、UUID()、LIMIT 不带 ORDER BY 的语句,在主库和从库上执行的结果可能不一样。我早期做主从复制时就遇到过,一条带 RAND() 的 SQL 导致主从数据不一致,排查了一整天才找到原因。

避坑指南:我曾经在生产环境遇到过因为 STATEMENT 格式导致的数据不一致问题。从那以后,只要涉及数据同步,我坚决不用 STATEMENT 格式。

2.2.2 ROW 格式

这种格式记录的是 每一行数据的变化。比如你更新了 1000 行数据,Binlog 里就会记录这 1000 行数据更新前和更新后的完整值。

优点:精确、安全。每一行怎么变的,清清楚楚。主从复制一致,CDC 解析也最方便——你能直接拿到变更前后的数据。

缺点:日志量大。尤其是批量操作,比如 UPDATE 全表,Binlog 会膨胀得非常厉害。

我个人习惯,做 CDC 项目时 默认使用 ROW 格式。虽然日志量大一点,但换来的是数据的一致性和解析的便利性,这笔账划算。

2.2.3 MIXED 格式

这种格式是前两种的“混合体”。MySQL 自己判断:如果 SQL 是“安全的”(比如简单的 INSERT),就用 STATEMENT 格式;如果 SQL 可能产生不确定性(比如用了 UUID()),就自动切换成 ROW 格式。

优点:兼顾了 STATEMENT 的小日志量和 ROW 的安全性。

缺点:对 CDC 不友好。因为 CDC 工具(比如 Canal、Debezium)需要解析 Binlog 事件,MIXED 格式下,你无法预知某条记录是 STATEMENT 还是 ROW,解析逻辑会变得复杂。而且,一旦遇到 STATEMENT 格式的事件,CDC 工具拿不到具体的数据行,只能拿到 SQL 文本,这基本等于废了。

我的建议:如果你在做 CDC 数据同步,直接选 ROW 格式。别犹豫。MIXED 看起来很美,但在 CDC 场景下是个坑。

三种格式的对比,我整理了一张表:

格式 记录内容 日志大小 安全性 CDC 友好度
STATEMENT SQL 语句 小 低(可能不一致) 差(拿不到数据行)
ROW 行数据变更 大 高(一致) 好(直接解析行数据)
MIXED 混合(自动判断) 中等 中等 差(格式不确定)

2.3 Binlog 的开启与配置

Binlog 默认是关闭的。你需要手动开启。配置很简单,修改 MySQL 的配置文件(通常是 my.cnf 或 my.ini)。

下面是我常用的配置模板:

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

# 设置 Binlog 格式为 ROW(CDC 推荐)
binlog-format=ROW

# 设置 server-id,主从复制或 CDC 必须唯一
server-id=1

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

# 单个 Binlog 文件的最大大小
max_binlog_size=1G

# 需要记录 Binlog 的数据库(可选,默认全部)
# binlog-do-db=your_database

# 忽略记录 Binlog 的数据库(可选)
# binlog-ignore-db=mysql

配置项说明:

  • log-bin:指定 Binlog 文件的前缀。比如 mysql-bin,生成的文件就是 mysql-bin.000001、mysql-bin.000002 这样递增。
  • server-id:每个 MySQL 实例必须唯一。CDC 工具连接时也会用到这个 ID。
  • expire_logs_days:Binlog 的保留天数。我建议根据你的磁盘空间和数据恢复需求来定。7 天是一个比较稳妥的值。
  • max_binlog_size:单个 Binlog 文件达到这个大小后,会自动切换到下一个文件。

注意:修改配置后,需要重启 MySQL 服务才能生效。重启前,记得确认你的 CDC 工具已经消费完当前的 Binlog,否则可能丢失数据。

配置完成后,可以用以下命令验证 Binlog 是否开启:

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

-- 查看当前 Binlog 文件列表
SHOW BINARY LOGS;

-- 查看当前正在写入的 Binlog 文件
SHOW MASTER STATUS;

如果 log_bin 的值为 ON,说明开启成功。你就能看到类似这样的输出:

+---------------+----------+--------------+------------------+-------------------+
| File          | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      154 |              |                  |                   |
+---------------+----------+--------------+------------------+-------------------+

这里的 Position 就是当前 Binlog 的写入位置。CDC 工具就是从这个位置开始“追”数据的。

2.4 知识体系总览

为了让你对本章内容有个整体印象,我画了一张图:

MySQL Binlog 知识体系 MySQL Binlog 概念与作用 三种格式 开启与配置 主从复制 数据恢复 增量数据捕获 STATEMENT ROW MIXED log-bin binlog-format server-id expire_logs_days 核心结论:CDC 场景下,推荐使用 ROW 格式 日志量大但数据一致,解析方便,是增量同步的最佳选择

这张图把本章的知识点串起来了。你可以看到,Binlog 的核心是三个维度:它是什么、有哪几种格式、怎么配置。而 ROW 格式,是我们做 CDC 的“黄金选择”。

小提示:如果你刚接触 Binlog,建议先在自己的测试环境里把配置跑起来,然后用 SHOW BINLOG EVENTS 命令看看 Binlog 里到底长什么样。亲手操作一遍,比看十遍文档都管用。