这是《MySQL 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 Binlog 是 MySQL Server 层的逻辑变更日志,用于复制、时间点恢复、数据同步和审计。它和 InnoDB Redo 分工不同:Redo 服务崩溃恢复,Binlog 服务跨实例传播。
23.1 Binlog 的用途
| 用途 | 说明 |
|---|---|
| 主从复制 | 从库读取并重放主库变更 |
| 时间点恢复 | 全量备份 + Binlog 恢复到目标时刻 |
| CDC | 读取行变更同步 Redis、ES、Kafka、数仓 |
| 审计 | 分析谁在何时修改了什么 |
| 数据订阅 | 构建派生数据 |
Binlog 不属于单个存储引擎,因此 MyISAM 修改也会记录,但没有 InnoDB 事务保证。
23.2 开启与查看
查看:
SHOW VARIABLES LIKE 'log_bin';
SHOW VARIABLES LIKE 'binlog_format';
SHOW VARIABLES LIKE 'server_id';
SHOW BINARY LOGS;
MySQL 8.0 默认开启 Binlog。如果是自建低版本环境,需要在配置文件中开启:
[mysqld]
server-id = 1
log-bin = mysql-bin
binlog_format = ROW
binlog_row_image = FULL
binlog_expire_logs_seconds = 604800
max_binlog_size = 512M
查看当前位点:
SHOW BINARY LOG STATUS;
老版本常使用:
SHOW MASTER STATUS;
23.3 Binlog 文件与事件
Binlog 是追加式文件序列:
mysql-bin.000001
mysql-bin.000002
mysql-bin.000003
文件达到 max_binlog_size 或执行特定操作后切换。每个文件包含事件,事务事件按提交顺序写入。
常用查看:
SHOW BINLOG EVENTS IN 'mysql-bin.000001' LIMIT 20;
命令行解析:
mysqlbinlog --no-defaults mysql-bin.000001 > events.sql
ROW 格式可读化:
mysqlbinlog --no-defaults \
--base64-output=decode-rows \
-vv mysql-bin.000001 > decoded.sql
按时间过滤:
mysqlbinlog --no-defaults \
--start-datetime='2026-08-25 00:00:00' \
--stop-datetime='2026-08-25 12:00:00' \
mysql-bin.000001 > recovery.sql
23.4 三种格式
| 格式 | 记录内容 | 一致性 | 日志大小 |
|---|---|---|---|
| STATEMENT | SQL 语句 | 弱,受不确定函数影响 | 小 |
| ROW | 行前后镜像 | 强 | 较大 |
| MIXED | 自动选择 | 折中 | 中等 |
推荐:
binlog_format = ROW
ROW 的行镜像模式:
SHOW VARIABLES LIKE 'binlog_row_image';
| 值 | 行为 |
|---|---|
| FULL | 记录所有列前后镜像 |
| MINIMAL | 只记录必要列和变更列 |
| NOBLOB | 尽量不记录未变 BLOB / TEXT |
FULL 便于审计和下游同步;MINIMAL 减少日志量,但下游需要能理解镜像含义。
23.5 Binlog 缓存
事务写入 Binlog 前先使用内存缓存:
SHOW VARIABLES LIKE 'binlog_cache_size';
SHOW VARIABLES LIKE 'max_binlog_cache_size';
SHOW GLOBAL STATUS LIKE 'Binlog_cache_disk_use';
SHOW GLOBAL STATUS LIKE 'Binlog_cache_use';
如果 Binlog_cache_disk_use 快速增长,说明大事务频繁落盘。优先拆分事务,不要只加大缓存。
23.6 保留与清理
查看保留策略:
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';
SHOW VARIABLES LIKE 'expire_logs_days';
MySQL 8.0 推荐使用 binlog_expire_logs_seconds。例如保留 7 天:
binlog_expire_logs_seconds = 604800
手工清理:
PURGE BINARY LOGS TO 'mysql-bin.000010';
PURGE BINARY LOGS BEFORE '2026-08-18 00:00:00';
清理原则:
- 必须晚于最新备份和恢复所需位点;
- 必须保留所有从库尚未读取的日志;
- 保留故障切换可能需要的窗口;
- 不直接用操作系统命令删除文件;
- 磁盘告警要提前,不要等 100%。
重置 Binlog 是高危操作,会改变复制和恢复上下文。MySQL 8.4 中相关语句为 RESET BINARY LOGS AND GTIDS,执行前必须确认整组实例和备份策略。
23.7 Binlog 与 CDC
典型链路:
MySQL Binlog
-> Canal / Debezium / Flink CDC
-> Kafka
-> Redis
-> Elasticsearch
-> ClickHouse
ROW 格式适合 CDC,因为可以拿到行级前后镜像。
同步必须考虑:
- DDL 变更顺序;
- 表结构版本;
- 事务边界;
- 乱序和重复;
- 下游幂等;
- 删除事件;
- 全量与增量衔接;
- 延迟监控;
- 主从切换后位点管理;
- 大事务导致的消息洪峰。
23.8 时间点恢复
场景:周一全量备份,周三 10:05 误删表。恢复流程:
1. 恢复周一全量备份到临时实例;
2. 找到全量备份对应 Binlog 位点或 GTID;
3. 重放 Binlog 到误删前一刻;
4. 校验临时实例数据;
5. 导出误删表;
6. 在人工确认后恢复生产表;
示例:
mysqlbinlog --no-defaults \
--start-position=154 \
--stop-position=100000 \
mysql-bin.000010 mysql-bin.000011 \
| mysql -h127.0.0.1 -P3307 -uroot -p shop_recovery
注意:
- 先恢复到临时实例;
- 保存原始 Binlog;
- 记录目标时间前后的所有事件;
- 校验行数和抽样数据;
- 恢复动作本身也要可回滚;
- 演练过才算有恢复能力。
23.9 Binlog 加密
MySQL 8.0 支持 Binlog 加密:
[mysqld]
binlog_encryption = ON
查看:
SHOW VARIABLES LIKE 'binlog_encryption';
同时必须管理:
- keyring 组件;
- 密钥备份;
- 密钥轮换;
- 恢复环境可用性;
- 权限和审计。
只加密文件不管理密钥,灾备时仍可能无法恢复。
23.10 常见问题
| 问题 | 原因 | 处理 |
|---|---|---|
| Binlog 磁盘占满 | 保留策略过久、大事务 | 调整保留、拆事务、扩容 |
| 从库位点不存在 | Binlog 被提前清理 | 重建从库或找其他源 |
| CDC 丢事件 | 位点保存失败 | 事务性位点管理和重启校验 |
| 主从不一致 | STATEMENT 不确定、手工写从库 | ROW + 只读 + 校验 |
| 恢复慢 | 全量太大、Binlog 太多 | 分库、并行恢复、优化备份 |
| 大事务卡同步 | 单事务事件过大 | 拆分并限速 |
本章小结
Binlog 是跨实例传播变更的核心日志,推荐 ROW 格式和明确的保留策略。它服务于复制、CDC 和时间点恢复,清理必须尊重备份链路和从库消费进度。大事务会放大 Binlog 缓存、日志体积和主从延迟。
思考题
- Binlog 和 InnoDB Redo 的定位有什么不同?
- ROW 和 STATEMENT 分别适合什么场景?
Binlog_cache_disk_use增长说明什么?- 为什么不能随意删除 Binlog 文件?
- 写一份误删表的时间点恢复演练步骤。