redo log 的写入过程
InnoDB 的 Redo Log(重做日志)是保证事务 持久性(Durability) 和 崩溃恢复(Crash Recovery) 的核心机制。其写入过程是一个高效且精心设计的流水线,主要涉及内存缓冲和磁盘持久化两个阶段。以下是详细步骤:
Redo Log 写入的核心步骤
产生 Redo 记录 (During Transaction Execution)
当事务执行数据修改操作(INSERT、UPDATE、DELETE)时,InnoDB 并不会立即修改磁盘上的数据页。
它会先在内存中的 Buffer Pool 中找到或加载相应的数据页进行修改(产生“脏页”)。
同时,InnoDB 会立即为这个物理修改生成一条对应的 Redo Log Record(重做日志记录)。这条记录描述了:“在某个表空间的某个页偏移量(Page+Offset)处,将数据从 X 改为 Y”。
这些 Redo Log Record 是顺序写入的,并且是物理逻辑日志(物理到页,逻辑到页内的操作)。
写入 Redo Log Buffer (Memory Buffer)
生成的 Redo Log Record 首先被写入到内存中的一个特定区域:Redo Log Buffer。
Redo Log Buffer 是一个环形缓冲区(Circular Buffer)。
写入 Redo Log Buffer 的速度非常快(内存操作)。
刷盘到 Redo Log File (Disk Persistence - The Critical Part)
这是保证持久性的关键步骤。Redo Log Buffer 中的内容需要被刷新(Flush)到磁盘上的 Redo Log Files(通常是
ib_logfile0
和ib_logfile1
)中,才能真正保证即使服务器崩溃,修改也不会丢失。刷盘的时机由参数
innodb_flush_log_at_trx_commit
严格控制,这个参数直接决定了事务提交时的持久性级别和性能:innodb_flush_log_at_trx_commit = 1
(默认值,最安全):每次事务提交时,都会执行以下操作:
Write: 将 Redo Log Buffer 中与该事务相关的所有 Redo Log Records 写入到操作系统的文件系统缓存(Page Cache)。
Fsync: 立即调用
fsync()
系统调用,强制将文件系统缓存中的 Redo Log 数据刷到物理磁盘上。效果:确保事务提交后,其修改绝对持久化到磁盘。崩溃后数据不会丢失。性能开销最大(因为每次提交都要等磁盘 I/O)。
innodb_flush_log_at_trx_commit = 2
(折衷方案):每次事务提交时:
Write: 将 Redo Log Buffer 中与该事务相关的所有 Redo Log Records 写入到操作系统的文件系统缓存(Page Cache)。
不执行
fsync()
。操作系统会每秒(大约) 自动调用一次fsync()
将文件系统缓存中的数据刷到物理磁盘。效果:如果 MySQL 进程崩溃(Crash),由于日志在操作系统的 Page Cache 里,重启后还能恢复,数据不会丢失。如果操作系统或机器宕机(Power Failure),则可能丢失最后约 1 秒内提交的事务(因为 Page Cache 中的数据没来得及刷盘)。性能比
=1
好很多(不需要等磁盘 I/O)innodb_flush_log_at_trx_commit = 0
(最快,最不安全):每秒进行一次刷盘操作:
Write: 将 Redo Log Buffer 中的内容写入到操作系统的文件系统缓存(Page Cache)。
Fsync: 调用
fsync()
将 Page Cache 中的数据刷到物理磁盘。事务提交时不做任何保证的刷盘操作。
效果:如果 MySQL 进程崩溃或操作系统/机器宕机,都可能丢失最多约 1 秒内提交的所有事务。性能最好(事务提交几乎无等待)。
其他刷盘触发点 (Regardless of
innodb_flush_log_at_trx_commit
):Redo Log Buffer 空间不足时:当 Buffer 使用超过一定比例(约 3/4),后台线程会自动触发刷盘。
后台线程定期刷盘:有一个专门的 InnoDB 后台线程(
log_writer
/log_flusher
)大约每秒会检查并尝试刷盘一次。Checkpoint 推进时:需要保证 Checkpoint LSN 之前的 Redo Log 已被安全覆盖。
Binary Log 组提交 (Group Commit) 协调时:在 Prepare 阶段(两阶段提交的第一步),即使
innodb_flush_log_at_trx_commit=0
,也会强制将 Redo Log 刷盘(fsync
),以保证 Binlog 和 Redo Log 的一致性基础。写入 Redo Log Files (物理结构)
Redo Log Files 通常是两个(或更多)固定大小的文件(如
ib_logfile0
,ib_logfile1
),以循环写入(Circular Writing) 的方式工作。InnoDB 维护一个指针 Write Position (LSN),指示下一个 Redo Record 应该写入文件中的哪个位置。
当写满最后一个文件时,会回绕(Wrap Around) 到第一个文件的开头继续写。
为了保证数据安全,被覆盖的 Redo Log 区域必须满足一个条件:这个区域对应的脏页修改已经刷新到了磁盘上的数据文件(.ibd)。这个确保安全覆盖的点称为 Checkpoint。Checkpoint LSN 之前的 Redo Log 可以被安全覆盖。
关键概念:LSN (Log Sequence Number)
LSN 是什么? 一个单调递增的 64 位整数,代表自系统启动以来产生的 Redo Log 总量(字节数)。
作用:
唯一标识:每个 Redo Log Record、每个数据页(记录
page_lsn
)、每个 Checkpoint 都关联一个 LSN。顺序控制:决定 Redo Log 的写入顺序和恢复时的应用顺序。
恢复起点:崩溃恢复时,从 Checkpoint LSN 开始扫描和应用后续的 Redo Log。
进度追踪:跟踪 Buffer Pool 中脏页的刷新进度(
oldest_modification
LSN)。
总结:Redo Log 写入流程的本质
生成日志:数据修改 => 生成 Redo Log Record (物理逻辑)。
缓冲加速:先写入内存中的 Redo Log Buffer (顺序, 快速)。
持久化关键:
根据
innodb_flush_log_at_trx_commit
设置,在事务提交时或特定时间点。执行
write
(到 OS Page Cache) 和fsync
(到物理磁盘)。确保
fsync
才能真正保证崩溃后不丢数据。循环写入:顺序写入固定大小的 Redo Log Files,循环覆盖(受 Checkpoint 保护)。
LSN 贯穿始终:LSN 是整个流程的全局逻辑时钟,用于追踪、恢复和一致性控制。