30.5. WAL 内部

WAL 自动启用;除了确保满足 WAL 日志的磁盘空间要求并已进行任何必要的调整(请参阅Section 30.4)外,Management 员无需执行任何操作。

在写入每个新记录时,WAL 记录将附加到 WAL 日志中。插入位置由日志序列号(LSN)描述,该序列号是日志中的字节偏移量,随每个新记录单调增加。 LSN 值作为数据类型pg_lsn返回。可以比较这些值以计算将它们分开的 WAL 数据量,因此可以使用它们来衡量复制和恢复的进度。

WAL 日志作为一组段文件存储在数据目录下的目录pg_wal中,通常每个文件大小为 16 MB(但可以通过更改--wal-segsize initdb 选项来更改大小)。每个段分为几页,通常每个页 8 kB(可通过--with-wal-blocksize configure 选项更改此大小)。日志记录头在access/xlogrecord.h中描述;记录的内容取决于正在记录的事件的类型。段文件的名称越来越多,从000000010000000000000001开始。数字不会自动换行,但是要耗尽可用的数字库存将需要非常非常长的时间。

如果日志与主数据库文件位于不同的磁盘上,则是有利的。这可以通过以下方式实现:将pg_wal目录移动到另一个位置(当然,当服务器关闭时),并创建一个从主数据目录中的原始位置到新位置的符号链接。

WAL 的目的是确保在更改数据库记录之前写入日志,但是可以通过磁盘驱动器来颠覆日志,磁盘驱动器错误地向内核报告了成功的写入操作,而实际上它们只缓存了数据但尚未存储它在磁盘上。在这种情况下断电可能会导致不可恢复的数据损坏。Management 员应尝试确保保存 PostgreSQL WAL 日志文件的磁盘不会做出此类错误报告。 (请参阅Section 30.1。)

构建检查点并刷新日志后,检查点的位置将保存在文件pg_control中。因此,在恢复开始时,服务器首先读取pg_control,然后读取检查点记录。然后它通过从检查点 Logging 指示的日志位置向前扫描来执行 REDO 操作。因为数据页的全部内容都在检查点之后保存在第一个页面修改的日志中(假定未禁用full_page_writes),所以自检查点以来所有已更改的页面都将恢复为一致状态。

为了处理pg_control损坏的情况,我们应该支持以相反的 Sequences(最新到最旧)扫描现有日志段的可能性,以便找到最新的检查点。尚未实现。 pg_control足够小(小于一个磁盘页面),因此不会出现部分写入问题,并且在撰写本文时,还没有关于数据库故障的报告,完全是由于无法读取pg_control本身引起的。因此,尽管从理论上讲它是一个弱点,但实际上pg_control似乎并不是问题。