PostgreSQL的WAL日志概述与Full-Page Writes

PostgreSQL通过预写式日志(wal日志)来保证数据不丢失

没有WAL机制的场景

没有 WAL 的数据库容易受到系统故障的影响,如下图,如果操作系统或 PostgreSQL 服务器发生故障,则所有插入的数据都可能丢失。

(1) 发出第一条 INSERT 语句,PostgreSQL 将 TABLE_A 的页面从数据库集群加载到内存共享缓冲池中,并在页面中插入一个元组。此页面不会立即写入数据库。

(2) 发出第二条 INSERT 语句,PostgreSQL 在缓冲池上的页中插入一个新的元组。此页尚未写入存储。

(3) 如果操作系统或PostgreSQL服务器因停电等任何原因出现故障,所有插入的数据都将丢失。

 引入WAL机制后

XLOG 将更改操作(例如插入、删除或提交操作)写入内存中的WAL 缓冲区当事务提交/中止时,它们会立即写入存储上的WAL 段文件

XLOG 记录的LSN(日志序列号)表示其记录在事务日志上的写入位置。记录的 LSN 用作 XLOG 记录的唯一 ID。

在崩溃发生后重新启动数据库,PG会从redo point开始恢复

下图为使用 WAL 进行插入操作

 (1) checkpointe是一个后台进程,周期性地执行checkpoint。每当检查点启动时,它都会将一个名为检查点记录的 XLOG 记录写入当前 WAL 段。此记录包含最新REDO 点的位置。

(2) 发出第一条INSERT语句,PostgreSQL将TABLE_A的页面加载到共享缓冲池中,在页面中插入元组,在位置LSN_1处创建并写入该语句的XLOG记录到WAL缓冲区中,并更新TABLE_A的LSN从LSN_0到LSN_1。
(3) 当这个事务提交时,PostgreSQL 会创建这个提交操作的 XLOG 记录并将其写入 WAL 缓冲区,然后,将 WAL 缓冲区上的所有 XLOG 记录写入并刷新到 WAL 段文件,更新LSN_0为LSN_1。

(4) 发出第二条 INSERT 语句,PostgreSQL 在页面中插入一个新的元组,创建并写入这个元组的 XLOG 记录到LSN_2处的 WAL 缓冲区,并将 TABLE_A 的 LSN 从LSN_1更新为LSN_2。

(5) 当这条语句的事务提交时,PostgreSQL 的操作方式与步骤 (3) 中相同。

(6) 此时即使共享缓冲池上的所有数据都丢失了,页面的所有修改也已作为历史数据写入 WAL 段文件。

下图为使用 WAL 进行数据库恢复

(1) PostgreSQL 从相应的 WAL 段文件中读取第一个 INSERT 语句的 XLOG 记录,将 TABLE_A 的页面加载到共享缓冲池中。

(2) 在尝试重放XLOG 记录之前,PostgreSQL 会比较XLOG 记录的LSN 与对应页面的LSN

  如果 XLOG 记录的 LSN 大于页面的 LSN,则将 XLOG 记录的数据部分插入到页面中,并将页面的 LSN 更新为 XLOG 记录的 LSN

  如果 XLOG 记录的 LSN 较小,则只能读取下一个 WAL 数据

在此示例中,由于XLOG记录的 LSN ( LSN_1 ) 大于 TABLE_A 的 LSN ( LSN_0 ),因此重放 XLOG 记录;然后,TABLE_A'LSN_1。

(3) PostgreSQL 以同样的方式重放剩余的 XLOG 记录。

关于Full-Page Writes

上面的恢复是基于从存储中拿到的页面是未被破坏的场景,WAL机制当前无法在损坏的页面上重放 XLOG 记录

为了支持这一能力,PG引入了整页写入(full-page writes )的功能来处理此类故障。如果启用,PostgreSQL在每个检查点后每个页面的第一次更改期间写入一对 header-data 和整个页面作为 XLOG 记录;

  • (1) checkpointer启动一个checkpoint进程。
  • (2) 在第一条INSERT语句的插入中,虽然PostgreSQL的操作方式与上一小节几乎相同,但这条XLOG记录是该页备份块(即它包含了整个页),因为这是在最新的检查点之后首次写入此页面。
  • (3) 当这个事务提交时,PostgreSQL 以与上一小节相同的方式运行。
  • (4) 在第二条INSERT语句的插入中,由于这条XLOG记录不是备份块,PostgreSQL的操作方式与上一小节相同。
  • (5) 当这条语句的事务提交时,PostgreSQL 以与上一小节相同的方式运行。
  • (6) 为了证明整页写入的有效性,这里我们考虑在后台写入器一直在将其写入硬盘时,由于操作系统发生故障,存储上的TABLE_A页面已损坏的情况。

使用备份块进行数据库恢复

(1) PostgreSQL 读取第一个 INSERT 语句的 XLOG 记录,并将损坏的 TABLE_A 页面从数据库集群加载到共享缓冲池中。在这个例子中,XLOG记录是一个备份块,因为按照整页写的写规则,每页的第一个XLOG记录总是它的备份块。

(2) 当 XLOG 记录是它的备份块时,应用另一个重放规则:

  无论两个 LSN 的值如何,记录的数据部分(即页面本身)都将被覆盖到页面上,并且页面的 LSN 更新到 XLOG 记录的 LSN。

  在此示例中,PostgreSQL 将记录的数据部分覆盖到损坏的页面,并将 TABLE_A 的 LSN 更新为LSN_1。通过这种方式,损坏的页面由其备份块恢复。

(3) 由于第二条 XLOG 记录是一个非备份块,PostgreSQL 的操作方式与上一小节中的指令相同。

但行好事,莫问前程
原文地址:https://www.cnblogs.com/mingfan/p/15340989.html