什么是WAL

“In computer science, write-ahead logging (WAL) is a family of techniques for providing atomicity and durability (two of the ACID properties) in database systems.”——维基百科
在计算机科学中,WAL是提供给数据库系统的一致性和持久性的一系列技术。WAL技术的核心就是将磁盘的随机IO过程转换成顺序IO。Write-ahead logging,意指日志刷盘的过程先于数据页刷盘的过程。

WAL是如何实现的

在Mysql更新数据时,首先会将相应的数据页读入内存,在内存中修改数据页,此时我们将更新后但没有立刻刷回磁盘的数据页称为脏页。在内存中更新相应的数据页后,Mysql将继续在redo log中记录相应的操作,最终在事务提交时将redo log buffer中的内容刷到磁盘中(innodb_flush_log_at_trx_commit=1的情况下)。

innodb_flush_log_at_trx_commit这个参数决定了事务提交时redo log刷盘的策略:

  • innodb_flush_log_at_trx_commit=0时,事务提交将redo log继续保留在redo log buffer中。
  • innodb_flush_log_at_trx_commit=1时,事务提交时直接将redo log buffer中的内容刷到磁盘。
  • innodb_flush_log_at_trx_commit=2时,事务提交时将redo log buffer中的内容提交到page cache
![redo log写盘过程](/assets/wp-content/uploads/2019/05/未命名文件-43.png)
redo log写盘过程

redo log buffer和page cache都是在内存中,所以写入这两者都比较快,而fsync则需要消耗磁盘IO。Mysql的后台每隔1秒也会自动将redo log buffer中的内容刷到磁盘中去。

redo log如何实现crash safe

在数据库崩溃的时候,内存中的脏页就会丢失,此时如何恢复丢失的数据呢?通过redo log的重放功能!我们之前已经提到,redo log的刷盘先于数据页的刷盘,所以我们丢失的数据已经保存在磁盘中的redo log里了。但是在innodb_flush_log_at_trx_commit非1的情况下会丢失redo log buffer和page cache中的数据。

redo log的相关配置

redo log文件大小时固定的,可以通过innodb_log_files_in_group和innodb_log_file_size配置日志文件数量和每个日志文件大小。一般将redo log设置为4个文件,每个文件为1GB的大小。当最后一个redo log文件写满时,Mysql将回头从第一个文件继续写。

![redo log文件](/assets/wp-content/uploads/2019/05/未命名文件-44.png)
redo log文件

Write Pos是redo log当前写入的位置,Checkpoint之前的数据表示已经刷盘,所以Checkpoint会将这些记录清除。Write Pos->Checkpoint之间为空,等待写入新的记录。Checkpoint->Write Pos为脏数据,等待刷盘。当Write Pos追上Checkpoint时,则会阻塞,等待Checkpoint向前推进,空出位置记录新的内容。