28.2. 预写式日志(WAL) #
预写式日志(WAL)是确保数据完整性的标准方法。大多数(即使不是全部)事务处理书籍中都能找到详细描述。简而言之,WAL 的核心思想是,对数据文件(即表和索引所在之处)的更改,必须在这些更改被记入日志之后才能写出;也就是说,必须在描述这些更改的 WAL 记录被刷入持久存储之后,再去写数据文件。如果遵循这个过程,就无需在每次事务提交时都把数据页刷盘,因为我们知道,一旦发生崩溃,就可以利用日志恢复数据库:任何尚未应用到数据页上的更改,都可以根据 WAL 记录重做。(这就是前滚恢复,也称 REDO。)
提示
由于 WAL 会在崩溃后恢复数据库文件内容,因此要可靠地存储数据文件或 WAL 文件,并不需要日志化文件系统。实际上,日志开销反而可能降低性能,特别是在日志会导致文件系统数据刷盘时。幸运的是,通常可以通过文件系统挂载选项关闭日志期间的数据刷写,例如
Linux ext3 文件系统上的 data=writeback。不过,日志化文件系统确实能够提高崩溃后的启动速度。
使用 WAL 会显著减少磁盘写入次数,因为要保证事务已提交,通常只需把 WAL 文件刷入磁盘,而不必把该事务修改过的每个数据文件都刷盘。WAL 文件按顺序写入,因此同步 WAL 的代价远低于刷写数据页。对于处理大量小事务、且这些事务触及数据存储不同部分的服务器,这一点尤其明显。此外,当服务器正在处理大量并发的小事务时,对 WAL 文件执行一次 fsync 就可能足以提交多个事务。
WAL 还使在线备份和时间点恢复成为可能,如第 24.3 节所述。通过归档 WAL 数据,我们就能支持回退到可用 WAL 数据覆盖范围内的任意时刻:只需先安装数据库的一个较早物理备份,然后把 WAL 重放到目标时刻即可。更进一步说,这个物理备份不必是数据库状态的瞬时快照 — 即使备份是在一段时间内完成的,重放这段时间内的 WAL 也能修复任何内部不一致。