PostgreSQL Write Ahead Logging WAL
前言
WAL 是 Write Ahead Log 的缩写,预写式日志。WAL log 也被称为 xlog 。WalWriter 进程就是写 WAL 日志的进程。预写式日志的概念就是在修改数据之前,必须要把这些修改操作记录到磁盘中,这样后面更新实际数据时,就不需要实时地把数据持久化到文件中了。即使机器突然宕机或数据库异常退出,导致一部分内存中的脏数据没有及时地刷新到文件中,在数据库重启后,通过读取 WAL 日志,并把最后一部分的 WAL 日志重新执行一遍,就可以恢复到宕机时的状态。
作用
WAL 可以理解为 pg 数据库的重做日志与 Oracle 的Redo Log 的功能是一样的。
因为 WAL 的存在,所以日志类型的文件系统对于 pg 来说不是必须的。例如 zfs 就是日志类型的文件系统,在持久化之前会记录日志,保证数据的原子性。(而且每当新数据写入 ZFS 时,它都会为该数据创建校验和(checksum)。当读取该数据时,校验和被验证。如果校验和不匹配,则 ZFS 知道已检测到错误。然后 ZFS 将自动尝试更正错误。)
日志文件系统 在日志记录开销会降低性能,特别是当日志记录导致文件系统数据被刷新到磁盘时。不过,日志记录期间的数据刷新通常可以通过文件系统挂载选项禁用,例如在Linux ext3文件系统上。但是日志文件系统可以提高崩溃后的启动速度。
使用 WAL 可以显著减少磁盘写入次数,因为只需要将日志文件刷新到磁盘以保证提交事务,而不是事务更改的每个数据文件。日志文件是按顺序写入的,因此同步日志的成本远低于刷新数据页的成本。对于处理许多涉及数据存储不同部分的小事务的服务器来说,尤其如此。此外,当服务器正在处理许多小型并发事务时,其中一个日志文件可能足以提交许多事务。
WAL 还可以支持在线备份和时间点恢复。通过存档 WAL 数据,我们可以支持恢复到可用 WAL 数据所覆盖的任何时间:我们只需安装数据库的先前物理备份,并在所需时间重放 WAL 日志。更重要的是,物理备份不必是数据库状态的实时快照。 如果它是在一段时间内进行的,那么重放该时间段的 WAL 日志将解决任何内部数据不一致的问题。
文件位置
WAL 文件在 PostgreSQL9.X 及以下版本是在 pg_xlog 目录下的,而在 PostgreSQL10.X 及以上版本是在 pg_wal 目录下的。查看 WAL 文件所在的目录,会看到如下文件列表:
1
2
3
4
5
## 文件名为24个字母长度的都是WAL文件
pg15@TheDarkStar:/data_dir/PostgreSQL/data$ ll pg15/pg_wal/
total 16388
-rw------- 1 pg15 pg15 16777216 Sep 9 19:30 000000010000000000000001
drwx------ 2 pg15 pg15 4096 Sep 8 16:18 archive_status
WAL 日志保存在 pg_xlog/pg_wal 下。每个 xlog 文件默认是 16MB,为了满足恢复要求,在 xlog 目录下会产生多个 WAL 日志,这样就可保证在宕机后,未持久化的数据都可以通过 WAL 日志来恢复,那些不需要的 WAL 日志将会被自动覆盖
WAL 文件名的意义
WAL 文件名的长度是固定的 24 位,由三部分组成,每一个部分 8 个字符长度:
- 时间线:英文为 timeline,是以 1 开始的递增数字,如 1,2,3……
- LogId: 32 bit 长的一个数字,是以 0 开始递增的,如 0,1,2 实际为 LSN 的高 32 bit。
- LogSeg: 32 bit 长的一个数字,是以 0 开始递增的,如 0,1,2, 3,···。LogSeg 是 LSN 的低 32 bit 的值再除以 WAL 文件大小 (通常为 16 MB) 的结果。注意: 当 LogId 为 0 时,LogSeg 是从 1 开始的。
如果WAL文件是默认大小,即16MB时,LogSeg最大为FF,即000000~0000FF,即在文件名中,最后8字节中前6字节总是0。这是因为LSN的低32bit的值再除以WAL文件大小[2^32/(16*1024*1024)=256]最大只能是256,换算成十六进制,即FF。
总结
WAL 相当于 Oracle 的 redo log,用于 pg 实例崩溃恢复是保证数据完整一致。WAL 采用顺序写入的方式,而且在数据的变更刷盘之前先行写入
可以参考官网描述