MySQL 三大日志和两阶段提交

2025/06/04

Categories: 技术 Tags: MySQL

WAL(Write-Ahead Logging)

WAL 是 MySQL 数据库的核心日志机制,其核心原则是在将数据变更应用到数据库之前,先将这些变更写入日志。这种方式保证了即使系统发生崩溃,数据库也能通过回放日志恢复到一致的状态。

以 InnoDB 存储引擎为例,当事务修改数据时,MySQL 会先将变更记录到 Redo log 中,再将数据写入磁盘。这样可以避免每次数据修改都要直接写入到数据文件,因为日志文件的写入操作通常比直接写入数据文件更高效。这种机制减少了直接磁盘 IO 的开销,并确保在崩溃恢复时能通过日志重放恢复未落盘的数据。

MySQL 三大日志

MySQL 使用多种日志来实现不同的功能,不同的日志类型解决了数据库运行中不同层面的关键问题,最常见的是 Redo log、Undo log 和 Binlog。它们都遵循 WAL 机制,但用途和实现方式不同。

Redo Log

Redo Log 是 MySQL InnoDB 存储引擎的重要组成部分,用于记录数据页的物理变更,保证事务的持久性和数据恢复,确保了数据库的稳定性和数据的一致性。

Redo Log 首先存储在内存中的日志缓冲区中,在合适的时间从缓冲区刷写到磁盘上的日志文件中,默认有 ib_logfile1 和 ib_logfile2 两个日志文件,大小固定,循环使用。Redo Log 中记录的数据页变更信息通常包括表空间 ID、页号、偏移量和新值等。有了 Redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。

Undo Log

Undo Log 是 MySQL InnoDB 存储引擎中的一种核心日志机制,它主要解决了事务的回滚和实现多版本并发控制 (MVCC)。它是保证数据库 ACID 特性 中 原子性和隔离性的重要基础。

Binlog

两阶段提交

MySQL 的两阶段提交是 WAL 技术的具体实现 ,用于协调 Redo Log(InnoDB 层) 和 Binlog(Server 层) 的一致性。由于事务可能同时涉及存储引擎层(Redo Log)和 Server 层(Binlog),两阶段提交确保两者在事务提交时保持原子性和一致性。其核心流程如下:

Prepare 阶段

Commit 阶段

通过这种分阶段提交,即使在提交过程中发生崩溃,MySQL 也能通过 Redo Log 和 Binlog 的协调恢复数据。

相关问题

为何需要两阶段提交?

如果只有 Redo log 或者只有 Binlog,那么事务就不需要两阶段提交。但是如果同时使用了 Redo log 和 Binlog,那么就需要保证这两种日志之间的一致性。

  1. 数据一致性:Redo Log 和 Binlog 是 MySQL 实现崩溃恢复(Crash Recovery)和主从复制(Replication)的关键日志。若两者不一致,可能导致主从数据差异或恢复失败。
  2. 原子性保障:两阶段提交确保事务要么全部生效,要么全部回滚,避免部分日志提交导致的不一致问题。
  3. 崩溃恢复能力:崩溃后,MySQL 通过 Redo Log 重放未完成的事务,并通过 Binlog 补偿主从同步的缺失数据。

WAL 与两阶段提交的关系?

MySQL 通过 WAL 技术 和 两阶段提交机制 的结合,既保证了单机事务的可靠性(Redo Log),又实现了跨节点的数据一致性(Binlog)。这一设计是 MySQL 高可用性和数据安全性的核心基础。

只用其中一种日志是否可以保证数据一致性?

MySQL 需要同时记录 Binlog 和 Redo log,因为它们在数据库中承担不同的职责,且存在本质差异。

Binlog 是逻辑日志,无法直接用于物理层面的数据恢复;而 Redo log 是物理日志,无法直接用于逻辑复制或归档,两者缺一不可。

MySQL 如何查看 Binlog?

通过下面命令查看 Binlog 配置和文件位置:

SHOW VARIABLES LIKE "log_bin%"

再使用官方提供的 mysqlbinlog 工具查看:

mysqlbinlog binlog.xxx -d database_name | tail -n 100

MySQL Binlog 有那些格式?

MySQL Binlog主要有 STATEMENT、ROW、MIXED 三种格式。

STATEMENT

记录实际执行的 SQL 语句本身。

适用场景:对数据一致性要求不高、能确保不使用不确定性函数且没有复杂上下文依赖的简单环境。现在已较少推荐使用。

ROW

记录每一行数据是如何被修改的。对于 INSERT,记录插入的整行新数据;对于 DELETE,记录被删除行的唯一标识或整行旧数据;对于 UPDATE,记录被修改行的唯一标识以及修改后的新数据。

适用场景:当前最推荐且主流的格式,尤其是在要求高数据一致性的场景,MySQL 5.7.7 及以后版本的默认格式就是 ROW。

MIXED

默认情况下使用 STATEMENT 格式记录 Binlog,但是当 MySQL 检测到语句可能引发不一致,如语句中包含不确定性函数时,会自动切换到 ROW 格式来记录该语句。

适用场景:希望平衡日志大小和数据一致性的场景。当绝大多数操作都是安全的(无不确定性函数),偶尔有风险操作时,MIXED 是一个折衷方案。

参考资料