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 知识体系总览
为了让你对本章内容有个整体印象,我画了一张图:
这张图把本章的知识点串起来了。你可以看到,Binlog 的核心是三个维度:它是什么、有哪几种格式、怎么配置。而 ROW 格式,是我们做 CDC 的“黄金选择”。
小提示:如果你刚接触 Binlog,建议先在自己的测试环境里把配置跑起来,然后用 SHOW BINLOG EVENTS 命令看看 Binlog 里到底长什么样。亲手操作一遍,比看十遍文档都管用。