日志系统

日志系统是 MySQL 数据安全和高可用的基石。本章深入讲解 Redo Log、Undo Log 和 Binlog 的实现细节。

基础概念请参考 事务 - 日志系统,本章将深入原理层面。

日志系统概述

三种核心日志

MySQL 的日志系统由三种核心日志组成,它们分别位于不同的层级:

                      MySQL Server 层
                    ┌──────────────────┐
                    │      Binlog      │ ─→ 主从复制、数据恢复
                    │   (二进制日志)    │
                    └────────┬─────────┘

        ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┼─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─

                      InnoDB 存储引擎层
         ┌───────────────────┼───────────────────┐
         │                   │                   │
    ┌────▼────┐        ┌─────▼─────┐       ┌────▼────┐
    │Redo Log │        │ Undo Log  │       │ Buffer  │
    │ (重做)   │        │  (回滚)   │       │  Pool   │
    │ 持久性   │        │  原子性   │       │         │
    └─────────┘        └───────────┘       └─────────┘

日志与 ACID 的对应关系

日志
层级
保证的特性
核心作用

Redo Log

InnoDB 引擎层

Durability(持久性)

崩溃恢复

Undo Log

InnoDB 引擎层

Atomicity(原子性)

回滚 + MVCC

Binlog

MySQL Server 层

-

主从复制、数据恢复

日志的协作关系


Redo Log 深入 ⭐⭐⭐⭐⭐

Redo Log 是 InnoDB 实现持久性的核心机制,理解其工作原理对于优化 MySQL 性能至关重要。

Redo Log 的本质

物理日志:记录的是对数据页的物理修改。

循环写机制 ⭐⭐⭐⭐⭐

Redo Log 采用循环写(circular write)的方式,使用固定大小的文件组。

关键理解

  • write pos 追上 checkpoint 时,必须等待脏页刷盘

  • 这也是为什么 Redo Log 不能设置太小的原因

Log Sequence Number (LSN) ⭐⭐⭐⭐

LSN 是 Redo Log 的逻辑序列号,是一个单调递增的数字。

LSN 的作用

  1. 标识日志位置:每条 Redo Log 记录都有唯一的 LSN

  2. 跟踪脏页:每个脏页记录最后修改它的 LSN

  3. 判断恢复起点:checkpoint 记录已刷盘的 LSN 位置

示例输出解读

Mini-Transaction (mtr)

Mini-Transaction 是 Redo Log 的最小写入单位,保证一组相关操作的原子性。

mtr 的特点

  • 一个事务包含多个 mtr

  • 每个 mtr 要么全部写入,要么全部不写入

  • mtr 结束时会写入一个特殊的 MLOG_MULTI_REC_END 标记

Redo Log Buffer 刷盘时机 ⭐⭐⭐⭐

Redo Log Buffer 中的内容会在以下时机刷到磁盘:

触发条件
说明

事务提交

innodb_flush_log_at_trx_commit 控制

Buffer 空间不足

Log Buffer 使用超过一半时触发

后台线程

每秒定时刷盘

Checkpoint

推进 checkpoint 时需要刷盘

关闭数据库

正常关闭时刷盘

innodb_flush_log_at_trx_commit 深入 ⭐⭐⭐⭐⭐

这是控制 Redo Log 刷盘策略的核心参数:

详细对比

行为
崩溃影响
性能
适用场景

0

每秒 write + fsync

MySQL 崩溃:丢 1 秒 OS 崩溃:丢 1 秒

最高

非关键数据

1

每次提交 write + fsync

不丢数据

最低

生产环境默认

2

每次提交 write,每秒 fsync

MySQL 崩溃:不丢 OS 崩溃:丢 1 秒

中等

允许少量丢失

示例场景

Checkpoint 机制详解 ⭐⭐⭐⭐

Checkpoint 是协调 Redo Log 和 Buffer Pool 的关键机制。

为什么需要 Checkpoint

  1. Redo Log 空间有限,需要循环使用

  2. 缩短数据库恢复时间

  3. 将脏页按一定频率刷到磁盘

两种 Checkpoint 类型

类型
触发条件
特点

Sharp Checkpoint

数据库关闭时

刷新所有脏页,停止服务

Fuzzy Checkpoint

运行时

部分刷新,不影响服务

Fuzzy Checkpoint 的触发条件

关键参数

查看 Redo Log 状态


Undo Log 深入 ⭐⭐⭐⭐⭐

Undo Log 承担两个重要职责:保证事务原子性(回滚)和支持 MVCC。

Undo Log 的本质

逻辑日志:记录的是如何撤销操作的逻辑信息。

Undo Log 的两种类型 ⭐⭐⭐⭐

类型
对应操作
提交后
用途

Insert Undo Log

INSERT

可立即删除

仅回滚

Update Undo Log

UPDATE/DELETE

需保留

回滚 + MVCC

为什么 Insert Undo Log 可以立即删除

  • INSERT 的数据对其他事务不可见(不存在历史版本)

  • 提交后不再需要为 MVCC 保留

为什么 Update Undo Log 需要保留

  • 其他事务可能需要读取旧版本(MVCC)

  • 必须等到没有事务需要这个版本才能删除

Undo Log 的存储结构 ⭐⭐⭐⭐

版本链的形成 ⭐⭐⭐⭐⭐

每次 UPDATE 操作都会在 Undo Log 中形成一个版本节点,通过 ROLL_PTR 指针串联成版本链。

详细的 MVCC 可见性判断请参考 MVCC 原理

Purge 机制详解 ⭐⭐⭐⭐

Purge 是清理不再需要的 Undo Log 的后台操作。

Purge 的触发条件

  • Undo Log 对应的事务已提交

  • 没有任何活跃事务需要读取这个版本

History List

查看 History List 长度

长事务的危害 ⭐⭐⭐⭐⭐

长事务是 Undo Log 膨胀的主要原因。

危害分析

监控长事务

预防措施

查看 Undo Log 状态


Binlog 深入 ⭐⭐⭐⭐

Binlog 是 MySQL Server 层的日志,是主从复制和数据恢复的基础。

Binlog 的本质

逻辑日志:记录的是对数据的逻辑修改(SQL 语句或行变化)。

Binlog vs Redo Log ⭐⭐⭐⭐⭐

特性
Redo Log
Binlog

层级

InnoDB 存储引擎层

MySQL Server 层

类型

物理日志(页修改)

逻辑日志(SQL/行变化)

写入方式

循环写,固定大小

追加写,无限增长

作用

崩溃恢复

主从复制、数据恢复

存储引擎

仅 InnoDB

所有存储引擎

是否必需

InnoDB 必需

可选(但生产必开)

为什么需要两种日志

Binlog 格式详解 ⭐⭐⭐⭐⭐

Binlog 有三种格式,由 binlog_format 参数控制:

STATEMENT 格式

STATEMENT 格式的问题

ROW 格式

ROW 格式的日志量问题

MIXED 格式

格式选择建议

场景
推荐格式
原因

生产环境

ROW

保证主从一致性

日志量敏感

MIXED

折中方案

开发测试

STATEMENT

可读性好,方便调试

大批量更新频繁

谨慎使用 ROW

考虑分批执行

sync_binlog 参数 ⭐⭐⭐⭐

控制 Binlog 刷盘策略:

行为
性能
安全性

0

由 OS 决定何时刷盘

最高

最低

1

每次提交都 fsync

最低

最高

N

每 N 次提交 fsync

中等

中等

生产建议

Binlog 实用命令

使用 mysqlbinlog 工具


两阶段提交 ⭐⭐⭐⭐⭐

两阶段提交(2PC)是保证 Redo Log 和 Binlog 一致性的关键机制。

为什么需要两阶段提交

问题场景:如果 Redo Log 和 Binlog 分别独立写入

两阶段提交流程 ⭐⭐⭐⭐⭐

简化记忆

崩溃恢复场景分析 ⭐⭐⭐⭐⭐

根据崩溃发生的时间点,恢复策略不同:

崩溃时间点
Redo Log 状态
Binlog 状态
恢复策略

Prepare 之前

事务自然回滚

Prepare 之后,Binlog 之前

prepare

回滚

Binlog 之后,Commit 之前

prepare

完整

提交

Commit 之后

commit

完整

已提交,无需处理

恢复决策逻辑

示例场景

XID 的作用 ⭐⭐⭐⭐

XID(Transaction ID)是关联 Redo Log 和 Binlog 的纽带。


崩溃恢复机制

InnoDB 崩溃恢复流程 ⭐⭐⭐⭐

Double Write Buffer ⭐⭐⭐⭐

Double Write 是防止部分页写入(Partial Page Write)的机制。

问题背景

Double Write 的解决方案

相关参数

恢复时间影响因素

因素
影响
优化建议

Redo Log 大小

越大,恢复时间越长

不要设置过大(推荐 1-4GB)

Checkpoint 频率

频率越低,恢复时间越长

适当调整 checkpoint 参数

脏页数量

越多,恢复时间越长

控制 innodb_max_dirty_pages_pct

磁盘性能

IO 性能影响恢复速度

使用 SSD


日志参数调优

Redo Log 参数

Binlog 参数

"双一" 配置详解 ⭐⭐⭐⭐⭐

"双一" 是指两个关键参数都设置为 1,是最安全的配置组合

性能与安全的权衡

配置组合
安全性
性能
适用场景

flush=1, sync=1

最高

最低

金融、交易系统

flush=1, sync=0

中等

重要业务数据

flush=2, sync=100

中等

较高

普通业务

flush=0, sync=0

最低

最高

批量导入、测试环境

批量导入时的临时调整


面试高频问题 ⭐⭐⭐⭐⭐

Q1: Redo Log 和 Binlog 的区别?

答案要点

维度
Redo Log
Binlog

层级

InnoDB 引擎层

MySQL Server 层

类型

物理日志(页修改)

逻辑日志(SQL/行变化)

写入

循环写,固定大小

追加写,无限增长

作用

崩溃恢复

主从复制、数据恢复

时机

事务执行过程中

事务提交时


Q2: 为什么需要两阶段提交?

答案要点

  1. 核心目的:保证 Redo Log 和 Binlog 的一致性

  2. 问题场景

    • 先写 Redo 后崩溃:主库有数据,从库没有

    • 先写 Binlog 后崩溃:主库没数据,从库有

  3. 解决方案

    • Prepare 阶段:Redo Log 写入,状态为 prepare

    • Commit 阶段:Binlog 写入后,Redo Log 状态改为 commit

  4. 恢复逻辑

    • Prepare + Binlog 完整 → 提交

    • Prepare + Binlog 不完整 → 回滚


Q3: innodb_flush_log_at_trx_commit 各值的含义?

答案要点

行为
数据丢失风险

0

每秒 write + fsync

MySQL/OS 崩溃:丢 1 秒

1

每次提交 write + fsync

不丢失

2

每次提交 write,每秒 fsync

OS 崩溃:丢 1 秒

生产建议:值 = 1(安全第一)


Q4: Binlog 为什么推荐 ROW 格式?

答案要点

  1. STATEMENT 的问题

    • NOW()、RAND()、UUID() 等函数主从结果不同

    • 不确定性 SQL(无 ORDER BY 的 LIMIT)

  2. ROW 的优势

    • 精确记录每行的变化

    • 保证主从数据一致

  3. ROW 的代价

    • 批量操作时日志量大

    • 可通过分批执行缓解


Q5: Undo Log 的两个作用?

答案要点

  1. 保证原子性(回滚)

    • 记录数据的旧值

    • ROLLBACK 时使用 Undo Log 恢复

  2. 支持 MVCC

    • 形成版本链

    • 其他事务可以读取历史版本

    • 实现非锁定读


Q6: 长事务对 Undo Log 有什么影响?

答案要点

  1. Undo Log 无法 Purge

    • 长事务的 Read View 可能需要旧版本

    • 即使其他事务提交,Undo Log 也不能清理

  2. 危害

    • History List 增长

    • Undo Tablespace 膨胀

    • 版本链过长,查询变慢

  3. 预防

    • 监控长事务

    • 设置事务超时

    • 避免在事务中执行耗时操作


Q7: MySQL 崩溃恢复是如何进行的?

答案要点

  1. Redo 阶段(前滚)

    • 从 checkpoint 开始扫描 Redo Log

    • 重放已提交事务(commit 状态)

    • 重放 prepare + Binlog 完整的事务

  2. Undo 阶段(回滚)

    • 回滚未提交事务

    • 回滚 prepare + Binlog 不完整的事务

  3. 关键判断

    • 以 Binlog 是否完整作为最终提交依据


Q8: 如何保证 MySQL 数据不丢失?

答案要点

  1. "双一" 配置

  2. 主从复制

    • 半同步复制(Semi-Sync)

    • 组复制(Group Replication)

  3. 备份策略

    • 定期全量备份

    • 结合 Binlog 增量恢复


Q9: Redo Log 的 checkpoint 机制?

答案要点

  1. 作用

    • 释放 Redo Log 空间(循环写)

    • 缩短崩溃恢复时间

  2. 触发条件

    • 后台线程定时触发

    • Redo Log 空间不足

    • 脏页比例过高

  3. 过程

    • 将 checkpoint 之前的脏页刷盘

    • 推进 checkpoint 位置


Q10: Redo Log 为什么能提高写入性能?

答案要点

  1. WAL 机制

    • Write-Ahead Logging

    • 先写日志,后写数据

  2. 性能优势

    • Redo Log:顺序写(追加)

    • 数据文件:随机写(分散在各处)

    • 顺序写比随机写快 100+ 倍

  3. 代价转移

    • 脏页由后台线程异步刷盘

    • 用户无需等待数据页落盘


总结

核心要点 ⭐⭐⭐⭐⭐

1. 三种日志的作用

日志
作用
实现的特性

Redo Log

崩溃恢复

持久性(D)

Undo Log

回滚 + MVCC

原子性(A)

Binlog

主从复制、数据恢复

-

2. 两阶段提交

3. 关键参数

4. 崩溃恢复

  • Redo 阶段:重放已提交事务

  • Undo 阶段:回滚未提交事务

记住这些关键点

  • Redo Log 是物理日志,Binlog 是逻辑日志

  • 两阶段提交保证主从一致

  • Undo Log 形成版本链支持 MVCC

  • "双一" 配置保证数据安全

  • 长事务影响 Undo Log 清理

  • Binlog 推荐 ROW 格式


相关文档

下一步:学习 MySQL 性能优化arrow-up-right,掌握索引优化、查询优化和参数调优。

Last updated