Skip to content

MySQL 第九章:日志系统与恢复机制

本章目标:理解 MySQL 核心日志体系(redo log、undo log、binlog)各自职责,掌握崩溃恢复与主从复制的基本原理。


1. 为什么数据库需要日志

数据库是“高并发 + 强一致 + 持久化”系统,日志是它的生命线。

日志主要解决三件事:

  • 保证持久性:宕机后数据不丢
  • 支持回滚:事务失败可撤销
  • 支持复制与恢复:数据同步、误操作恢复
graph LR
    A[SQL 写入请求] --> B[InnoDB 执行]
    B --> C[redo log]
    B --> D[undo log]
    B --> E[binlog]
    C --> F[崩溃恢复]
    D --> G[事务回滚/MVCC]
    E --> H[主从复制/数据恢复]

2. redo log:崩溃恢复核心

2.1 redo log 是什么

  • InnoDB 引擎级日志
  • 记录“页的物理变更”(重做信息)
  • 解决“事务已提交但数据页未落盘”场景下的数据恢复

2.2 为什么需要 redo log

MySQL 写数据不是每次都立刻刷盘(随机 IO 成本高),通常先写内存页(Buffer Pool),再异步刷盘。
如果此时宕机,内存数据会丢失,所以要先有 redo log 兜底。

2.3 WAL 思想

WAL(Write-Ahead Logging):先写日志,再写数据页


3. undo log:回滚与 MVCC 基础

3.1 undo log 是什么

  • 记录数据被修改前的“旧值”
  • 用于事务回滚与一致性读

3.2 主要作用

  1. 事务回滚:执行 ROLLBACK 时根据 undo log 撤销变更
  2. MVCC:生成历史版本,支持快照读

3.3 简单理解

  • redo log:记录“做了什么”,用于重做
  • undo log:记录“原来是什么”,用于撤销

4. binlog:归档、复制与恢复

4.1 binlog 是什么

  • MySQL Server 层日志(不是 InnoDB 私有)
  • 记录逻辑层操作(SQL 或行变更)
  • 常用于主从复制、增量恢复、审计

4.2 binlog 常见格式

  • STATEMENT:记录原始 SQL(体积小,但部分场景不够精确)
  • ROW:记录每行变更(更准确,主流推荐)
  • MIXED:混合模式

推荐:生产环境优先考虑 ROW


5. redo / undo / binlog 对比

日志所在层记录内容主要用途
redo logInnoDB 引擎层物理页变更崩溃恢复,保证持久性
undo logInnoDB 引擎层数据旧版本回滚、MVCC
binlogServer 层逻辑操作/行变更主从复制、增量恢复

6. 一次事务提交发生了什么(简化版)

sequenceDiagram
    participant App as 应用
    participant MySQL as MySQL
    participant Redo as redo log
    participant Binlog as binlog
    App->>MySQL: BEGIN + UPDATE
    MySQL->>Redo: 写入redo(prepare)
    MySQL->>Binlog: 写入binlog
    MySQL->>Redo: 写入redo(commit)
    MySQL-->>App: COMMIT成功

上述流程是“两阶段提交”思想的简化表达,用于保证 redo 与 binlog 的一致性。


7. 崩溃恢复机制(Crash Recovery)

数据库异常宕机后,重启时会做恢复:

  1. 扫描 redo log,重做已提交事务但尚未落盘的变更
  2. 对未完成事务,借助 undo log 回滚未提交操作

结果:恢复到“最近一次一致状态”。


8. 基于 binlog 的恢复思路

常见恢复策略:

  1. 全量备份(如凌晨)
  2. 持续保存 binlog
  3. 误操作后:先恢复全量,再按 binlog 回放到目标时刻(Point In Time Recovery)

场景举例:

  • 10:00 做全量备份
  • 15:00 误删数据
  • 可恢复到 14:59:59,最大限度减少损失

9. 主从复制与日志关系

主从复制核心依赖 binlog:

  1. 主库写 binlog
  2. 从库 IO 线程拉取主库 binlog
  3. 从库 SQL 线程回放日志,重做变更
graph LR
    A[主库写入] --> B[主库binlog]
    B --> C[从库IO线程拉取]
    C --> D[relay log]
    D --> E[从库SQL线程回放]

10. 运维与开发建议

  1. 开启并妥善保留 binlog(按恢复需求设置保留策略)
  2. 定期全量备份 + 增量日志,演练恢复流程
  3. 对核心业务库监控事务提交延迟与日志刷盘状态
  4. 避免长事务,减少 undo 膨胀和 purge 压力
  5. 线上变更前评估“可恢复性”(备份点 + 回滚方案)

11. 面试高频点

11.1 redo log 和 binlog 区别

  • redo 是引擎层物理日志,保障崩溃恢复
  • binlog 是服务层逻辑日志,保障复制与恢复

11.2 为什么有了 binlog 还要 redo log

binlog 不能替代引擎级崩溃恢复能力,redo 更贴近页变更,恢复效率和语义不同。

11.3 undo log 除了回滚还有什么用

支持 MVCC 一致性读(快照读可见性判断)。

11.4 什么是两阶段提交

通过 redo prepare -> binlog -> redo commit 的顺序,减少跨日志不一致风险。


12. 练习题

  1. 用自己的话解释 redo、undo、binlog 各自作用。
  2. 为什么数据库宕机后可以恢复已提交事务?
  3. 设计一个“全量 + binlog 增量恢复”的操作流程。
  4. 解释主从复制中 relay log 的作用。
  5. 若线上误删数据,你会如何制定恢复步骤?

13. 本章小结

  • 日志系统是 MySQL 可靠性的基础设施,不只是“记录文本”。
  • redo 保持“提交不丢”,undo 保证“可撤销与可见性”,binlog 支撑“复制与恢复”。
  • 真正可用的生产体系一定是:日志策略 + 备份策略 + 恢复演练 三位一体。