redo log、undo log 与 binlog 各有什么作用,如何协同完成事务?
未标记
考查重点:日志职责与提交协调。undo 回滚/版本,redo 恢复,binlog 复制与逻辑恢复;两阶段提交协调 redo/binlog 的提交决定
本题目录
参考答案
核心回答
以 MySQL 8.4、InnoDB 普通持久表,并开启 binlog 为例,三类日志各有分工:undo log 支持回滚和历史版本读取,redo log 支持崩溃恢复,binlog 记录可供复制与备份恢复的数据变更。 提交时,MySQL 通过内部两阶段提交,让 InnoDB 的提交结果与 binlog 中的事务记录保持一致;undo 并不是其中独立的第三个提交阶段。
undo log保存撤销修改所需的信息,例如更新前的列值。事务回滚时用它撤销修改;一致性读也可以沿版本链构造符合Read View的历史记录。它不是简单保存一条“反向SQL”,提交后也不一定立即清理,其他事务可能仍需要旧版本。redo log记录InnoDB数据页相关的修改,使数据库能在崩溃后重做尚未完整写入数据文件的变化。它配合WAL:脏页写入数据文件前,相关redo必须先满足持久化要求,因此提交不必等待所有修改过的数据页都写盘。binlog位于MySQL Server层,以事件记录数据变更,主要用于复制,以及恢复备份之后继续重放增量。它可以采用ROW、STATEMENT等格式;ROW记录行变化,不能把所有binlog都说成原始SQL。它也不能代替InnoDB的页级崩溃恢复。
可以把三者理解为:undo 负责“需要撤销或读取旧版本时怎么办”,redo 负责“内存里的页修改还没完全落到数据文件时怎么办”,binlog 负责“怎样把已记录的数据变更用于其他实例或历史恢复”。
一次事务怎样使用这些日志
假设事务把一条余额记录从 100 改为 80。执行期间,InnoDB 记录撤销所需的信息,修改 Buffer Pool 中的数据页,并产生相应 redo;持久表的 undo 页修改本身也需要 redo 保护。Server 层则收集该事务对应的 binlog 事件,通常先放在事务缓存中。
redo 可以在事务尚未提交时写出,数据页也可能在事务结束前被刷出。因此不能用“日志或数据页已写盘”直接判断事务已经提交。最终是否保留这些修改,还要结合事务提交状态;未提交的修改可以借助 undo 撤销。
在常见的耐久配置下,提交的逻辑过程是:
InnoDB准备事务。 记录prepare状态,保留后续提交或回滚所需的信息,并保证在需要作出耐久提交决定前,相关redo已经可靠保存。- Server 写入并同步完整
binlog事务。 事务事件及相应的XID提交记录构成恢复时的提交依据。只有写到文件系统缓存,还不等于已经耐久保存。 InnoDB完成提交。 根据协调结果提交事务,随后向客户端返回结果。数据页可以再由后台逐步刷盘,不要求在这个阶段全部写完。
这里描述的是事务协调的先后关系。实际实现有组提交等机制,可以合并多个事务的日志写入或同步,不能据此推导每个事务必然独占固定次数的 fsync。
两阶段提交怎样处理崩溃
如果分别完成 redo 提交和 binlog 写入,中间宕机就可能出现“本地恢复保留了修改,但复制或备份恢复没有这次修改”,或者相反的结果。内部两阶段提交保留 prepare 状态,让恢复过程能够作出同一决定。
对于崩溃后仍处于 prepared 状态的内部事务,关键看有效、完整且持久保存的 binlog 中,是否存在对应 XID 的提交记录:
- 没有对应提交记录:不能把它当作已经提交的事务,应回滚其修改。
- 存在对应提交记录:即使
InnoDB的最终commit记录尚未完成,也可以继续完成提交,使本地结果与binlog一致。
恢复时,redo 会先帮助恢复需要的数据页状态,再结合事务状态与 undo 处理未完成事务。不能简单地说“redo 中的内容全部算已提交”,也不能只看到一个孤立 XID 就忽略事务记录是否完整有效。
持久化配置影响什么
通常所说的“双 1”是 innodb_flush_log_at_trx_commit=1 和 sync_binlog=1:前者要求提交相关的 redo 写入并同步,后者要求同步 binlog 提交组。它们是保证本地崩溃恢复与日志一致性的重要条件,但仍依赖操作系统和存储设备正确兑现同步请求。
放宽这些配置,可以减少同步开销,也可能丢失已经向客户端确认的事务或相应日志。两阶段提交解决的是提交协调,不能把尚在易失缓存中的数据自动变成耐久数据,更不能保证副本已经执行完成。
常见追问
为什么有 binlog 还需要 redo?
binlog 面向数据变更的复制和重放,不负责直接修复 InnoDB 数据文件里哪些页更新到了一半。redo 与检查点、数据页和引擎恢复过程配合,解决的是本地存储恢复问题;备份加 binlog 的历史恢复是另一条路径。
undo 在提交后为什么还会占空间?
回滚不再需要,不代表历史读取也不再需要。部分 undo 仍可能被活跃事务的一致性读使用,要等不再需要后才能清理。长事务可能延长历史版本保留时间。
客户端提交超时,能认定事务失败吗?
不能。事务可能已经完成耐久提交,只是响应没到客户端。应通过稳定的业务标识查询结果,必要时幂等重试,不能根据网络超时直接重复执行扣款等动作。数据库内部两阶段提交也不等于已经解决跨服务的分布式事务。
参考资料
- 国内:程序猿阿星/JavaGuide:MySQL 日志详解:redo、binlog、两阶段提交与 undo 部分说明三类日志怎样分工,以及 prepare 状态为什么能帮助处理提交中途的崩溃。
- 国内:小林 coding:细聊 MySQL undo log、redo log、binlog:借鉴记录更新、内部 XA、崩溃窗口与组提交的说明,解释正文中执行阶段日志如何衔接最终提交决定。
- 国内:美团技术团队:DB 数据同步到数据仓库的架构与实践:Binlog 采集、存量快照和增量合并部分,展示 binlog 在数据同步中的实际用途,区别于本地数据页恢复。
- 国外:MySQL 8.4:The Binary Log:事务缓存、日志格式、同步配置和崩溃恢复时的 XID 协调,说明完整 binlog 事务怎样成为 prepared 事务的提交依据。
- 国外:MySQL 8.4:Undo Logs:undo 记录与一致性读的定义,解释撤销信息和历史版本读取的关系,以及持久表与临时表 undo 的恢复区别。
相关面经
10 篇腾讯音乐
后端开发工程师MySQL 中的 redo log、undo log、binlog 分别是什么?有什么作用?
字节跳动
后端开发工程师MySQL 为什么需要两阶段提交?redo log 和 binlog 如何协调,故障后如何恢复?
钛松科技
后端开发工程师InnoDB 崩溃恢复日志有哪些?
百度
Agent 应用开发工程师binlog、undo log 和 redo log 分别有什么作用?




