Appearance
binlog、redo log、undo log 是怎么配合的
MySQL 的三种日志经常一起出现,但它们分工完全不同:
- redo log: 保证 InnoDB 崩溃恢复
- undo log: 支撑回滚和 MVCC
- binlog: 记录逻辑变更,服务复制和恢复
如果把这三者混在一起,很多线上问题都解释不清,比如:
- 为什么事务提交成功但机器宕机后数据还在
- 为什么主从复制能继续同步
- 为什么长事务会拖慢历史版本回收
先说结论
redo log是物理日志,解决“数据页还没落盘时机器崩了怎么办”undo log记录旧版本,解决“事务回滚”和“快照读看历史版本”binlog是逻辑日志,解决“复制、审计、按时间点恢复”- 一次事务提交,三者不是重复干同一件事,而是分别覆盖不同恢复面
先把三种日志分清
redo log
redo log 是 InnoDB 引擎层的物理日志。
它记录的是“这个页做了什么修改”。
作用是:
- 数据页还没来得及刷盘时,先把修改意图顺序写入 redo log
- 宕机重启后,重放 redo log,把已提交但未来得及落盘的修改补回去
它的核心价值是把“随机写数据页”变成“顺序写日志”,这就是 WAL。
undo log
undo log 保存修改前的旧版本。
作用有两个:
- 事务回滚时恢复旧值
- MVCC 读取历史版本时沿链回溯
所以 undo log 既是“回滚日志”,也是“历史版本链”的基础。
binlog
binlog 是 Server 层的逻辑日志。
它记录的是 SQL 或行变更事件,而不是 InnoDB 页修改细节。
主要用途:
- 主从复制
- 数据订阅
- 按时间点恢复
- 审计
一次 update 到底发生了什么
假设执行:
sql
update account set balance = balance - 100 where id = 1;从日志视角看,大致会发生这些事:
- 读取目标行
- 生成该行旧版本,写入 undo log
- 修改 Buffer Pool 中的数据页
- 记录对应的 redo log
- 事务提交时写入 binlog
- 通过两阶段提交保证 redo 和 binlog 一致
这里有两个核心点:
- redo 对应“数据页怎么恢复”
- binlog 对应“变更事件怎么传播和重放”
为什么需要 redo log
因为数据库不能每次事务提交都立刻把数据页完整刷盘。
那样随机 IO 成本太高。
更现实的做法是:
- 先把修改写到内存页
- 同时把 redo 顺序写盘
- 后续再由后台线程把脏页刷盘
这样即使突然宕机,只要 redo 在,提交过的事务就能恢复回来。
这就是“提交成功不等于数据页已经落盘,但仍然能恢复”的根本原因。
为什么需要 undo log
如果事务执行一半失败,数据库得有办法回到修改前。
undo log 就是这份“后悔药”。
例如:
- 事务把余额从 100 改成 80
- 后面业务检查失败,事务回滚
- MySQL 根据 undo log 把余额恢复成 100
除此之外,MVCC 还会借助 undo log 给旧事务看历史版本。
所以长事务不结束,会拖住 undo 清理。
为什么 redo 和 binlog 都要有
它们不是替代关系,而是分层关系。
redo 不能替代 binlog
- redo 是 InnoDB 私有格式
- 只保证本地实例崩溃恢复
- 不适合给从库复制和外部消费
binlog 不能替代 redo
- binlog 是逻辑层事件
- 不保证页级崩溃恢复效率
- 无法直接承担存储引擎的 WAL 职责
一个管引擎恢复,一个管变更传播。
两阶段提交为什么重要
如果 redo 和 binlog 写入顺序不受控,就可能出现:
- redo 已提交,binlog 没写成功
- binlog 写成功,redo 没持久化
这两种都会带来严重问题:
- 主从数据不一致
- 崩溃恢复后事务状态不确定
所以 MySQL 提交事务时,会通过两阶段提交把两者绑定起来,常见可理解为:
- redo prepare
- binlog write and fsync
- redo commit
重启恢复时,MySQL 会结合 redo 状态和 binlog 判断事务是否真正提交。
几个线上高频现象怎么解释
1. 长事务导致 undo 堆积
长事务一直不提交,它早期拍下的 Read View 还在,旧版本就不能及时清理。
结果可能是:
- undo 增长
- purge 跟不上
- 查询回旧版本变慢
2. 主从延迟和 binlog 强相关
复制链路本质上就是从库消费主库 binlog。
binlog 格式、事务大小、提交节奏都会影响复制延迟。
3. 提交慢不一定是 SQL 慢
有时 SQL 执行不慢,但事务提交慢,可能卡在:
- redo 刷盘
- binlog 刷盘
- 大事务 binlog 写出
面试和实战都通用的理解方式
你可以把三者记成:
- undo: 回头看
- redo: 向前补
- binlog: 向外发
再进一步就是:
- undo 负责事务回滚和历史版本
- redo 负责宕机恢复
- binlog 负责复制和逻辑恢复
总结
理解三种日志,不是为了背概念,而是为了在看到“事务提交、主从复制、崩溃恢复、长事务堆积”这些现象时,知道它们分别落在哪个层面。
把这三条线分清,MySQL 的很多核心机制就会更立体。