redo log 是 innodb 引擎层物理日志,记录数据页偏移量级变更;binlog 是 server 层逻辑日志,记录 sql 或行级变更,两者用途、格式、生命周期及文件行为均不同,需通过两阶段提交协同保证一致性。

redo log 是 InnoDB 引擎层的物理日志,binlog 是 Server 层的逻辑日志
这是最根本的差异,直接决定它们的用途、格式和生命周期。redo log 只在 InnoDB 引擎启用时存在,记录的是“某个数据页偏移量处写了多少字节”,比如 page_no=1234, offset=64, data=0x0102...;而 binlog 对所有引擎通用,记录的是“执行了哪条 SQL”或“哪一行发生了什么变化”,比如 UPDATE t SET c = c + 1 WHERE id = 5 或某行的前/后镜像(取决于 binlog_format)。
这意味着:你换用 MyISAM 引擎,binlog 依然能正常工作,但 redo log 完全不生效——MyISAM 没有 crash-safe 能力,也不写 redo log。
redo log 用于崩溃恢复,binlog 用于主从复制和归档恢复
两者目标不同,不可互相替代:
-
redo log的唯一使命是保证 MySQL 实例异常重启后,已提交事务的数据不丢失。它靠 WAL(Write-Ahead Logging)机制实现:先写日志再改内存,崩溃后通过重放日志把未刷盘的脏页补上。 -
binlog不参与崩溃恢复。它被设计成可长期保留、可传输、可解析的归档日志。主从复制靠它同步变更;误删数据后,靠mysqlbinlog解析 + 过滤 + 回放来恢复;审计也依赖它。 - 如果只开
binlog关redo log(InnoDB 配置innodb_log_file_size=0等同于禁用),MySQL 崩溃后可能丢掉最后几秒已提交的事务——binlog写入时机(受sync_binlog控制)和事务提交不是原子绑定的。
两阶段提交(2PC)是它们协同工作的关键机制
MySQL 为保证 redo log 和 binlog 数据一致,引入了两阶段提交:
-
prepare 阶段:InnoDB 将事务修改写入
redo log并标记为PREPARE状态,返回成功给 Server 层; -
write binlog 阶段:Server 层将该事务的变更写入
binlog文件(是否刷盘由sync_binlog决定); -
commit 阶段:Server 层通知 InnoDB 提交,InnoDB 把对应
redo log改为COMMIT状态。
这个流程确保:要么两个日志都完整,要么都不完整。否则主从同步或恢复时会出现数据不一致。比如崩溃发生在 write binlog 后、commit 前,MySQL 启动时会检查 redo log 中处于 PREPARE 状态的事务,再核对 binlog 是否存在对应 XID——存在则提交,不存在则回滚。
日志文件行为差异极大:循环覆盖 vs 追加写入
运维和排查时必须注意这点:
-
redo log是固定大小的循环文件(如 4×1GB)。write_pos和checkpoint之间是可用空间,追上就阻塞写入。你无法“查某天的 redo log”,它只存最近若干秒/分钟的变更。 -
binlog是无限追加的文件序列(binlog.000001,binlog.000002…),按大小(max_binlog_size)或时间(binlog_expire_logs_seconds)自动轮转。你可以保留 30 天的 binlog 用于恢复,但不能保留 30 天的 redo log。 - 误删表后想用
binlog恢复?得确认对应时间段的 binlog 文件还没被 purge。而想看崩溃前最后一刻的 redo log?得靠innodb_print_all_deadlocks=ON或提前采集SHOW ENGINE INNODB STATUS输出——redo log 本身不提供易读的文本接口。
真正容易被忽略的是:innodb_flush_log_at_trx_commit 和 sync_binlog 的组合配置,决定了数据安全与性能之间的实际取舍。设成 (1,1) 最安全但最慢;(2,1) 或 (1,N) 在多数业务中更现实——但你要清楚,这中间的窗口期(比如 1 秒或 N 个事务)内,MySQL 崩溃可能导致 binlog 已落盘而 redo log 未落盘,或反之,从而触发 2PC 的恢复逻辑。这不是 bug,是设计权衡。











