一、日志总览类
Q1:MySQL 有哪些日志?各自作用是什么?
面试重点通常是前三个。
Q2:redo log、undo log、binlog 的核心区别?
二、redo log 类
Q3:redo log 是什么?为什么需要它?
物理日志,记录“在某个数据页上做了什么修改”。
作用:WAL(Write-Ahead Logging),先写日志再刷脏页,保证崩溃后能恢复已提交事务。
没有它,每次提交都要随机写磁盘数据页,性能极差。
Q4:什么是 WAL?为什么能提升性能?
Write-Ahead Logging:修改先写 redo log(顺序写),再择机刷数据页(随机写)。
顺序写远快于随机写,且日志体积小,刷盘快。
崩溃时用 redo log 重放,恢复数据。
Q5:redo log 的组成和循环写机制?
由多个固定大小文件组成,如
ib_logfile0、ib_logfile1。循环写:
write pos写位置,checkpoint可擦除位置。write pos追上checkpoint时,必须停下来刷脏页,腾出空间。
Q6:redo log 什么时候刷盘?
由 innodb_flush_log_at_trx_commit 控制:
=1:每次提交都刷盘,最安全,默认。=0:每秒刷一次,崩溃可能丢 1 秒。=2:每次提交写 OS cache,每秒刷盘,宕机可能丢。
Q7:redo log 和 binlog 的写入顺序?
两阶段提交:redo prepare → 写 binlog → redo commit。
保证两份日志逻辑一致。
三、undo log 类
Q8:undo log 是什么?有什么作用?
逻辑日志,记录数据的“反向操作”,如 INSERT 对应 DELETE。
两大作用:
事务回滚:原子性。
MVCC:版本链,供快照读找历史版本。
Q9:undo log 和 MVCC 的关系?
每行有
roll_pointer指向 undo log 中的旧版本。多个版本串成版本链。
快照读时沿版本链找对 ReadView 可见的版本。
Q10:undo log 什么时候删除?
事务提交后不一定立即删。
还要供 MVCC 读旧版本,等没有 ReadView 需要它时,由 purge 线程清理。
Q11:undo log 是物理还是逻辑日志?
逻辑日志。记录的是“反向 SQL 操作”,不是页的物理修改。
但回滚时可能涉及多个页,所以是逻辑层面的。
四、binlog 类
Q12:binlog 是什么?有什么作用?
Server 层逻辑日志,记录所有变更。
作用:主从复制、数据恢复、归档。
与存储引擎无关,InnoDB、MyISAM 都有。
Q13:binlog 的三种格式?
生产推荐 ROW,主从一致性强。
Q14:binlog 什么时候写入?
事务提交时写入,先写 binlog cache,再刷盘。
sync_binlog=1每次提交刷盘,最安全。sync_binlog=0由 OS 决定,可能丢。
Q15:binlog 和 redo log 的区别?
层次:binlog 在 Server,redo 在 InnoDB。
类型:binlog 逻辑,redo 物理。
写入:binlog 追加,redo 循环写。
用途:binlog 复制归档,redo 崩溃恢复。
Q16:为什么 binlog 不能做崩溃恢复?
binlog 是逻辑日志,不记录页的物理状态,重放成本高且不精确。
崩溃恢复需要 redo log 的物理重放,快速且确定。
五、两阶段提交类
Q17:什么是两阶段提交?为什么需要?
流程:写 redo(prepare)→ 写 binlog → 提交 redo(commit)。
目的:保证 redo log 和 binlog 逻辑一致。
不用的话,崩溃时可能出现:
redo 有、binlog 没有 → 主库有数据,从库没有。
binlog 有、redo 没有 → 从库有数据,主库没有。
背景:两份日志,两个层次
MySQL 里一次数据修改会涉及两份日志:
问题在于:这两份日志必须逻辑一致。否则会出现:
redo 有、binlog 没有:主库恢复后有这条数据,但从库没收到,主从不一致。
binlog 有、redo 没有:从库重放后有这条数据,但主库没有,主从不一致。
如果不用两阶段提交
假设简单按“先写 redo,再写 binlog”:
写完 redo 后宕机,binlog 没写 → 主库有、从库没有。
先写 binlog,再写 redo,写完 binlog 宕机 → 从库有、主库没有。
无论哪种顺序,崩溃点都可能导致两份日志不一致,进而主从不一致。
两阶段提交的流程
以一条 UPDATE 为例,核心顺序是:
1. 写 redo log,标记为 prepare 状态
2. 写 binlog
3. 写 redo log,标记为 commit 状态拆开看:
阶段一:Prepare
InnoDB 把修改写入 redo log,但不标记 commit,而是标记 prepare。
此时事务还未真正提交,数据页也没刷盘。
阶段二:Commit
Server 层写 binlog,并刷盘(受
sync_binlog控制)。binlog 写成功后,InnoDB 把 redo log 的状态从 prepare 改为 commit。
事务提交完成。
关键点:binlog 写在 redo prepare 之后、redo commit 之前。这个顺序是整个协议的核心。
崩溃恢复时怎么判断
崩溃后重启,InnoDB 扫描 redo log,遇到 prepare 状态的事务时,会去检查对应的 binlog:
判断依据:
binlog 完整:说明 binlog 已成功落盘,从库能收到,主库必须提交,否则主从缺这条。
binlog 不完整:说明 binlog 没写完,从库不会有这条,主库回滚,保持一致。
这样无论崩溃发生在哪个点,主库和从库的最终状态都一致。
为什么这个顺序能保证一致
可以用反证法理解:
为什么 binlog 必须在 redo commit 之前?
如果先 redo commit,再写 binlog:
redo commit 后宕机,binlog 没写 → 主库有、从库没有,不一致。
为什么 binlog 必须在 redo prepare 之后?
如果先写 binlog,再写 redo prepare:
binlog 写完后宕机,redo 还没 prepare → 从库有、主库没有,不一致。
所以顺序必须是:redo prepare → binlog → redo commit。prepare 是“占位”,commit 是“确认”,中间夹着 binlog,形成可判断的中间状态。
与组提交的关系
两阶段提交每次都要刷盘,性能有开销。MySQL 用组提交(Group Commit)优化:
多个事务的 redo 和 binlog 合并成一次 fsync。
分为三个阶段:
Flush 阶段:把 redo 从 Log Buffer 写到文件。
Sync 阶段:fsync 刷盘。
Commit 阶段:写 binlog 并提交 redo。
组提交让多个事务共享一次刷盘,显著降低 fsync 次数,提升并发。
组提交不会破坏 innodb_flush_log_at_trx_commit=1 和 sync_binlog=1 的语义。它合并的是“多个事务的刷盘动作”,不是“把某个事务的刷盘推迟到配置之外”。每个事务在返回客户端之前,其 redo 和 binlog 都已经被 fsync 落盘。
MySQL 的组提交把提交过程分成三个阶段,多个事务在这三个阶段里排队、成组:
阶段 1:Flush
多个事务的 redo log 从 Log Buffer 写入 redo 文件(write,不 fsync)。
这些事务组成一个组。
阶段 2:Sync
对这一组的 redo 文件执行一次 fsync。
这一组里所有事务的 redo 都随之落盘。
同时,这一组事务的 binlog 也从 binlog cache 写入 binlog 文件。
阶段 3:Commit
对 binlog 执行 fsync(
sync_binlog=1时)。然后把这一组事务的 redo 状态改为 commit。
组内事务依次返回客户端。
用图表示:
事务 T1, T2, T3 同时提交
│
▼
[Flush] T1/T2/T3 的 redo 写入文件
│
▼
[Sync] 一次 fsync → T1/T2/T3 的 redo 全部落盘
│
▼
[Commit] 写 binlog → 一次 fsync → redo 改 commit → 返回客户端一次 fsync 覆盖了三个事务,而不是三次 fsync。
相关参数
要求不丢数据:两个都设 1。
常见追问
Q:两阶段提交能保证绝对不丢吗?
保证的是 redo 和 binlog 一致,不是绝对不丢。
不丢还依赖
innodb_flush_log_at_trx_commit=1和sync_binlog=1。
Q:binlog 写完但 redo 没 commit,宕机后提交还是回滚?
提交。因为 binlog 完整,从库会有这条,主库必须提交保持一致。
Q:redo prepare 后宕机,binlog 没写,怎么办?
回滚。binlog 不完整,从库不会有,主库也回滚。
Q:为什么不让 binlog 也由 InnoDB 管?
binlog 属于 Server 层,要支持多种存储引擎,且用于复制,不能绑死在 InnoDB。
Q:组提交会破坏一致性吗?
不会。组提交只是合并刷盘,逻辑顺序仍是 prepare → binlog → commit。
Q18:崩溃恢复时怎么判断提交还是回滚?
redo 处于 prepare:
binlog 完整 → 提交。
binlog 不完整 → 回滚。
redo 已 commit → 直接恢复。
Q19:两阶段提交有什么缺点?
增加一次网络/磁盘交互,延迟略高。
组提交(group commit)可缓解:多个事务一起刷盘。
Q20:组提交是什么?
多个事务的 redo/binlog 合并成一次刷盘,减少 fsync 次数。
分为 flush、sync、commit 三个阶段。
六、日志与持久性类
Q21:如何保证事务不丢?
innodb_flush_log_at_trx_commit=1sync_binlog=1两者都设 1,每次提交都刷盘。
配合半同步复制、多副本。
Q22:innodb_flush_log_at_trx_commit 三个值区别?
Q23:redo log 写满会怎样?
write pos追上checkpoint,必须刷脏页推进 checkpoint。此时写入会阻塞,直到腾出空间。
所以 redo 太小会导致频繁刷盘、性能抖动。
Q24:redo log 能设置多大?
innodb_log_file_size和innodb_log_files_in_group。太小:频繁 checkpoint,性能差。
太大:崩溃恢复慢。
一般几 GB 级别,按写入量调。
七、实战与排查类
Q25:如何查看 binlog?
SHOW BINARY LOGS;SHOW BINLOG EVENTS IN 'mysql-bin.000001';mysqlbinlog mysql-bin.000001
Q26:如何用 binlog 恢复数据?
全量备份 + 重放 binlog 到指定时间点。
mysqlbinlog --start-datetime --stop-datetime ... | mysql -u ...
Q27:主从复制中 binlog 怎么流转?
主库写 binlog。
dump 线程发给从库。
从库 IO 线程写 relay log。
SQL 线程重放 relay log。
Q28:redo log 和 binlog 不一致会怎样?
主从数据不一致,主库有从库没有,或反之。
两阶段提交就是为避免这个。
Q29:undo log 太大有什么问题?
长事务导致版本链长,占用空间。
影响 MVCC 查询性能,purge 压力大。
应避免长事务。
Q30:binlog 格式怎么选?
生产推荐 ROW:精确、安全,主从一致。
STATEMENT 日志小但有函数/随机问题。
MIXED 折中,但仍有风险。
八、高频陷阱题
Q31:redo log 是事务提交就写数据页吗?
不是。提交只保证 redo 刷盘,数据页由后台线程择机刷。
这是 WAL 的核心:先日志后数据。
Q32:binlog 是事务提交前还是后写?
提交过程中写,在 redo prepare 之后、redo commit 之前。
这是两阶段提交的关键顺序。
Q33:undo log 是回滚用的,为什么提交后还保留?
供 MVCC 快照读找旧版本。
没有 ReadView 需要时才由 purge 清理。
Q34:redo log 能关闭吗?
不能。InnoDB 持久性依赖它。
只能调刷盘策略,不能完全关。
Q35:binlog 能代替 redo log 做崩溃恢复吗?
不能。binlog 是逻辑日志,重放慢且不精确。
崩溃恢复必须用 redo 物理重放。
评论