MySQL binlog、redolog 和 undolog 的区别是什么?

一则或许对你有用的小广告

欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于 Spring AI + Spring Boot3.x + JDK 21...点击查看;
  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot3.x + JDK 17...点击查看项目介绍; 演示链接: http://116.62.199.48:7070/;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/

面试考察点

  1. 日志体系理解:面试官不仅仅是想知道三种日志的名字和定义,更是想知道你是否理解 MySQL 的日志体系架构,以及每种日志在整个事务生命周期中扮演的角色。

  2. 崩溃恢复机制:考察你是否清楚 MySQL 如何通过 redo log 保证持久性(D)、通过 undo log 保证原子性(A)和实现 MVCC,以及 binlog 在主从复制中的作用。

  3. 两阶段提交原理:是否理解 redo log 和 binlog 的 "两阶段提交" 机制,为什么需要这个机制来保证数据一致性。

核心答案

MySQL 中这三种日志各司其职,核心区别如下:

对比维度redo logundo logbinlog
归属层级InnoDB 引擎层InnoDB 引擎层MySQL Server 层
核心作用崩溃恢复,保证持久性事务回滚、MVCC,保证原子性主从复制、数据备份
写入方式循环写,空间固定按事务写入追加写,文件可配置
内容形式物理日志(在某某页修改了什么)逻辑日志(反向 SQL)逻辑日志(SQL 语句或行变更)
事务关联事务提交时刷盘事务执行中持续写事务提交时一次性写入

一句话总结:redo log 是 "崩溃恢复的救命稻草",undo log 是 "后悔药的原料",binlog 是 "主从复制的信使"。

深度解析

一、三种日志的架构位置

上图展示了 MySQL 三种日志的架构层级关系:

  • binlog:位于 Server 层,所有存储引擎都可以使用。它是 MySQL 的 "归档日志",主要用于主从复制和数据备份恢复。以事件形式记录所有修改数据的 SQL 语句或行变更。

  • redo logundo log:位于 InnoDB 引擎层,是 InnoDB 特有的。redo log 用于崩溃恢复,采用 WAL(Write-Ahead Logging)机制;undo log 用于事务回滚和 MVCC 实现。

  • 层级分离的意义:正因为 binlog 在 Server 层,redo log 在引擎层,才需要 "两阶段提交" 来保证两者的一致性。

二、redo log 详解

上图展示了 redo log 的循环写入机制:

  • 循环写入:redo log 不是无限追加的,而是固定大小(默认两个文件各 1GB)循环使用。write pos 记录当前写入位置,checkpoint 记录检查点位置。

  • WAL 机制:事务提交时,先写 redo log(顺序 I/O),再异步刷脏页到数据文件(随机 I/O)。这样即使数据库崩溃,也可以通过 redo log 恢复未刷盘的数据。

  • 刷盘时机

    • 事务提交时(innodb_flush_log_at_trx_commit=1,最安全)
    • 后台线程定时刷
    • redo log 空间不足时

关键配置

-- 查看 redo log 配置
SHOW VARIABLES LIKE 'innodb_log%';

-- innodb_log_file_size:单个日志文件大小(默认 48MB,建议 1-2GB)
-- innodb_log_files_in_group:日志文件数量(默认 2)
-- innodb_flush_log_at_trx_commit:刷盘策略(0/1/2,建议 1)

三、undo log 详解

上图展示了 undo log 的两大核心作用:

  • 事务回滚:记录数据的 "反向操作"。UPDATE 记录旧值,DELETE 记录整行,INSERT 记录主键。当事务回滚时,用 undo log 中的信息恢复数据。

  • MVCC 实现:每行数据都有隐藏列 trx_id(事务 ID)和 roll_pointer(回滚指针)。通过 roll_pointer 找到 undo log 中的旧版本,实现 "读已提交" 和 "可重复读" 隔离级别。

undo log 存储位置

-- MySQL 5.6 之前:存储在共享表空间 ibdata1
-- MySQL 5.6+:可配置独立的 undo 表空间
SHOW VARIABLES LIKE 'innodb_undo%';

-- innodb_undo_tablespaces:undo 表空间数量
-- innodb_max_undo_log_size:undo 表空间最大值
-- innodb_undo_log_truncate:是否自动截断

四、binlog 详解

上图展示了 binlog 在主从复制中的作用:

  • 主库写入:事务提交时,将修改操作写入 binlog(追加写入,文件可配置滚动)

  • 从库同步

    • I/O Thread:连接主库,读取 binlog,写入本地的 Relay Log(中继日志)
    • SQL Thread:读取 Relay Log,重放 SQL 语句,保持与主库数据一致

binlog 三种格式

格式记录内容优点缺点
STATEMENTSQL 语句本身日志量小不确定函数可能导致不一致
ROW行数据变更数据一致性最好日志量大
MIXED混合模式兼顾两者复杂场景可能仍有问题
-- 查看 binlog 配置
SHOW VARIABLES LIKE '%binlog%';

-- binlog_format:日志格式(推荐 ROW)
-- binlog_cache_size:事务缓存大小
-- sync_binlog:刷盘策略(1 = 每次提交都刷盘,最安全)

五、两阶段提交

上图展示了 redo log 和 binlog 的两阶段提交流程:

  • 为什么需要两阶段提交:因为 redo log 和 binlog 是两个独立的日志系统,如果不协调,可能出现:

    • redo log 写了但 binlog 没写 → 主库恢复后数据丢失,从库没收到
    • binlog 写了但 redo log 没写 → 主库恢复后数据回滚,从库却收到了
  • 两阶段提交流程

    1. Prepare 阶段:写 redo log,标记为 prepare 状态
    2. Commit 阶段:写 binlog,然后写 redo log 标记为 commit 状态
  • 崩溃恢复:如果崩溃时 redo log 处于 prepare 状态,通过检查 binlog 是否完整来决定提交还是回滚。

面试高频追问

  1. 追问一:redo log 为什么采用循环写而不是追加写?

    循环写的目的是空间复用。redo log 只需要保留 "从检查点到当前" 的数据,更早的日志对应的数据已经刷盘,可以覆盖。追加写会导致磁盘空间无限增长,不现实。

  2. 追问二:innodb_flush_log_at_trx_commit 设为 0/1/2 有什么区别?

    行为安全性性能
    0每秒刷盘一次❌ 可能丢 1 秒数据最高
    1每次提交都刷盘✅ 不丢数据(最安全)较低
    2每次提交写入 OS 缓存,每秒刷盘⚠️ 可能丢 1 秒数据中等

    生产环境强烈推荐设为 1

  3. 追问三:为什么 binlog 不能代替 redo log 做崩溃恢复?

    • binlog 是逻辑日志(SQL 或行变更),恢复时需要重新执行,效率低
    • redo log 是物理日志(页修改),恢复时直接应用,效率高
    • binlog 是追加写,没有记录 "哪些页已刷盘" 的信息,无法精确恢复
  4. 追问四:undo log 什么时候会被删除?

    undo log 不会在事务提交后立即删除,因为可能还有其他事务在用它做 MVCC 读。只有当所有活跃事务都不再需要这个 undo log 时,才会被 purge 线程清理。

常见面试变体

  • "MySQL 是如何保证事务的 ACID 特性的?"
  • "redo log 和 binlog 有什么区别?为什么要两阶段提交?"
  • "MVCC 是怎么实现的?undo log 在其中扮演什么角色?"
  • "数据库崩溃后如何恢复数据?"

记忆口诀

三大日志定位

  • redo log:引擎层,循环写,崩溃恢复保持久
  • undo log:引擎层,反向记,回滚 MVCC 都靠它
  • binlog:Server 层,追加写,主从复制做备份

两阶段提交:先 prepare 后 commit,中间写 binlog,崩溃查状态

总结

redo log、undo log、binlog 是 MySQL 的三大核心日志。redo log 在 InnoDB 引擎层,采用循环写的 WAL 机制,保证崩溃恢复时的持久性;undo log 记录反向操作,支持事务回滚MVCC 实现;binlog 在 Server 层,追加写入,用于主从复制数据备份。三者通过 "两阶段提交" 保证一致性,是 MySQL 高可用架构的基石。