PostgreSQL: 使用 pg_checksums 控制数据校验

John Doe 八月 7, 2025

你需要对数据库中数据进行校验,防止其出现损坏吗?

在山坡漫步的大象

pg_checksums 介绍

PostgreSQL 11 引入了一个 pg_checksums 工具。PostgreSQL 12 为其新增了多项功能。

现在,我们可以对离线实例启用和禁用校验和了。

对于离线实例,现在 pg_checksums 可以支持更多运行模式:

  • --enable 用于启用实例中的校验和,更新所有数据块使其具备正确的校验和,并在最后更新控制文件。
  • --disable 用于禁用实例中的校验和,仅更新控制文件。
  • --check 是一个额外选项,能够验证实例的校验和,若未指定模式则默认使用该选项。

当运行--enable--disable时,数据文件夹会进行刷写以保证持久性,随后会更新控制文件并刷新,以确保在工具被中断、终止或主机断电时,操作仍能保持一致性。如果未在选项中指定模式,则会使用 --check,以与旧版本的 pg_checksums 保持兼容。

其工作原理如下。该工具现在总共有三种模式:

  • --check 是默认模式(若未指定任何模式),也是该工具原本就具备的功能。此模式会扫描所有关系文件块,并报告任何不匹配的情况。
  • --enable 用于启用数据校验和。它会重写所有关系的数据块,并在操作最后更新控制文件。请注意,根据不同的实例大小,这可能要花费一定时间,而且该工具不支持并行模式。
  • --disable 仅通过更新控制文件来禁用数据校验和。

使用示例

对于一个已禁用数据校验和的实例,可以按以下方式启用校验和。首先,需要切换的实例必须被干净地关闭:

$ pg_controldata -D /my/data/folder/ | grep state
Database cluster state:               shut down

然后,运行以下命令即可启用数据校验和,所做的更改会反映到控制文件中:

$ pg_checksums --enable -D /my/data/folder/
Checksum operation completed
Files scanned:  1144
Blocks scanned: 3487
pg_checksums: syncing data directory
pg_checksums: updating control file
Checksums enabled in cluster

$ pg_controldata -D /my/data/folder/ | grep checksum
Data page checksum version:           1

重复相同的操作会导致失败,在已禁用数据校验和的情况下再次禁用,也会出现同样的情况:

$ pg_checksums --enable -D /my/data/folder/
pg_checksums: error: data checksums are already enabled in cluster

然后,可以按以下方式禁用校验和:

$ pg_checksums --disable -D /my/data/folder/
pg_checksums: syncing data directory
pg_checksums: updating control file
Checksums disabled in cluster

$ pg_checksums --disable -D /my/data/folder/
pg_checksums: error: data checksums are already disabled in cluster

$ pg_controldata | grep checksum
Data page checksum version:           0

最后,需要注意的是,该工具能够妥善处理操作过程中的失败或中断情况。例如,如果在启用数据校验和的过程中主机断电,由于控制文件的更新是最后一步,数据文件夹将保持校验和禁用的状态。因此,可以从头重试该操作。

此外,pg_checksums 还添加了一个选项-P/--progress,可以输出任何正在运行的操作的进度。这样,可以每秒钟显示--check--enable操作的处理进度信息(--disable 仅更新控制文件,速度很快)。这需要预先扫描数据文件夹,以便计算所有可校验项的总大小,然后将其与已处理的量进行比较。

与 pg_rewind 和 pg_basebackup 类似,进度报告中显示的信息,包括当前已处理的数据量和待处理的总数据量。

请注意,进度选项仅适用于--check--enable。进度报告每秒钟更新一次,如下所示:

$ pg_checksums --enable --progress
27/27 MB (100%) computed

这需要额外扫描数据文件夹,以便预先了解所有可校验项的总大小,这会额外消耗一些资源,但当在大型实例上执行操作需要很长时间时,进度报告非常有用。

升级启用校验和

在备份验证方面,pg_checksums 已经是一个相当强大的工具,但在升级 PostgreSQL 老版本实例后,启用校验和时仍然会存在障碍。在 PostgreSQL 中,可以通过逻辑复制将数据复制到一个使用 initdb 初始化且已启用数据校验和的新实例,但初始数据复制可能需要很长时间和大量资源。请注意,如果实例依赖于对关系数据块进行物理复制的备份工具(如 pg_rewind),可能会出现这样的情况:实例已启用校验和,但某些页面可能已损坏,因为这些页面来自未启用校验和的实例。因此,在一组 PostgreSQL 节点中切换校验和时,应注意在所有节点上同时一致地启用校验和。

现在,由于数据校验和仅在后台将页面刷新到磁盘或共享缓冲区被换出时才会计算,并且即使进行全页写入,WAL 日志也不需要计算校验和,因此依靠物理复制(WAL 流)可以更轻松地以最小的停机时间启用校验和。例如,假设有两个节点(一个主节点和一个备用节点),且没有在多个节点之间对关系数据块进行物理复制,可以按以下步骤来操作:

假设主节点和备用节点都已禁用数据校验和,然后我们来启用数据校验和。

  1. 正常地停止备用节点,并使用 --enable 启用校验和。
  2. 启动备用节点,使其与主节点同步。
  3. 正常地停止主节点。
  4. 将备用节点提升为主节点,并进行故障转移。
  5. 在之前的主节点上启用校验和。
  6. 将其重新连接到已提升的备用节点(现在是主节点),此时两个实例都已完成启用校验和。