MySQLNotes

第 23 章:Binlog 原理

zjc 于 2026-01-23 发布

这是《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';

清理原则:

  1. 必须晚于最新备份和恢复所需位点;
  2. 必须保留所有从库尚未读取的日志;
  3. 保留故障切换可能需要的窗口;
  4. 不直接用操作系统命令删除文件;
  5. 磁盘告警要提前,不要等 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,因为可以拿到行级前后镜像。

同步必须考虑:

  1. DDL 变更顺序;
  2. 表结构版本;
  3. 事务边界;
  4. 乱序和重复;
  5. 下游幂等;
  6. 删除事件;
  7. 全量与增量衔接;
  8. 延迟监控;
  9. 主从切换后位点管理;
  10. 大事务导致的消息洪峰。

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

注意:

  1. 先恢复到临时实例;
  2. 保存原始 Binlog;
  3. 记录目标时间前后的所有事件;
  4. 校验行数和抽样数据;
  5. 恢复动作本身也要可回滚;
  6. 演练过才算有恢复能力。

23.9 Binlog 加密

MySQL 8.0 支持 Binlog 加密:

[mysqld]
binlog_encryption = ON

查看:

SHOW VARIABLES LIKE 'binlog_encryption';

同时必须管理:

  1. keyring 组件;
  2. 密钥备份;
  3. 密钥轮换;
  4. 恢复环境可用性;
  5. 权限和审计。

只加密文件不管理密钥,灾备时仍可能无法恢复。

23.10 常见问题

问题 原因 处理
Binlog 磁盘占满 保留策略过久、大事务 调整保留、拆事务、扩容
从库位点不存在 Binlog 被提前清理 重建从库或找其他源
CDC 丢事件 位点保存失败 事务性位点管理和重启校验
主从不一致 STATEMENT 不确定、手工写从库 ROW + 只读 + 校验
恢复慢 全量太大、Binlog 太多 分库、并行恢复、优化备份
大事务卡同步 单事务事件过大 拆分并限速

本章小结

Binlog 是跨实例传播变更的核心日志,推荐 ROW 格式和明确的保留策略。它服务于复制、CDC 和时间点恢复,清理必须尊重备份链路和从库消费进度。大事务会放大 Binlog 缓存、日志体积和主从延迟。

思考题

  1. Binlog 和 InnoDB Redo 的定位有什么不同?
  2. ROW 和 STATEMENT 分别适合什么场景?
  3. Binlog_cache_disk_use 增长说明什么?
  4. 为什么不能随意删除 Binlog 文件?
  5. 写一份误删表的时间点恢复演练步骤。