默认情况下,数据页受校验和保护,但也可以选择为集簇禁用。启用后,每个数据页 都包含一个校验和,在页面写入时更新,并在页面每次被读取时进行验证。只有数据 页受校验和保护;内部数据结构和临时文件不受保护。
可以在使用 initdb 初始化集簇时禁用校验和。之后也可以作为离线操作,或者在允许并发访问的运行中 集簇上在线启用或禁用。数据校验和是在整个集簇级别启用或禁用的,不能为单个 数据库、表或复制的集簇成员分别指定。
可以通过查看只读配置变量 data_checksums 的值来确认 集簇当前的校验和状态,执行命令 SHOW data_checksums 即可。
在尝试从页面损坏中恢复时,可能需要绕过校验和保护。为此,请临时设置配置参数 ignore_checksum_failure。
pg_checksums 程序可用于在离线集簇上启用或禁用数据校验和,也可以用来验证校验和。
可以通过调用相应的 函数 在线启用 或禁用校验和。
启用和禁用数据校验和都分两个阶段完成,中间由一次检查点分隔,以确保持久性。 不同状态及其转换关系如 Figure 28.1 所示,本节 将进一步说明。
Figure 28.1. 数据校验和状态
启用校验和会把集簇校验和状态设为 inprogress-on。在此期间, 校验和会被写入,但不会被验证。除此之外,还会启动一个后台工作进程,用于为集簇 中所有现有数据启用校验和。该工作进程完成集簇中所有数据库的处理后,校验和状态 会自动切换为 on。该处理会占用两个后台工作进程,因此要 确保 max_worker_processes 至少还能容纳另外两个进程。
该过程在开始前会先等待所有打开的事务结束,以便确认不存在在尚未提交的事务内部 创建、从而对启用校验和的过程不可见的表。它还会在完成前,针对每个数据库等待所 有预先存在的临时表被移除。如果应用中使用了生命周期较长的临时表,则可能需要终 止这些应用连接,以便该过程完成。
如果集簇在 inprogress-on 状态下由于任何原因停止,或者处理 被中断,那么必须手工重新启动校验和启用过程。为此,在集簇重启后重新执行 pg_enable_data_checksums() 函数。该过程会从头开始,不支 持从中断处继续。若集簇在 inprogress-off 状态下停止,则在 集簇重启时,校验和状态会被设为 off。
禁用数据校验和会把数据校验和状态设为 inprogress-off。 在此期间,校验和会被写入,但不会被验证。所有进程确认该变更后,状态会自动设为 off。
在数据校验和正在被启用时禁用数据校验和,会中止当前处理。
启用数据校验和会给系统带来显著的 I/O 压力,因为所有数据库页面都需要重写, 并且既要写入数据文件,也要写入 WAL。可以通过 pg_enable_data_checksums() 函数的 cost_delay 和 cost_limit 参数进行节流,从而限制影响。
I/O:所有页面都需要计算并写入数据校验和,这会生成大量脏页,之后这些脏页还 需要刷盘,同时也会写入 WAL。
复制:当备库在 WAL 流中收到数据校验和状态变更时,它会发起一个 重启点,以便把 当前状态刷入 pg_control 文件。重启点会把当前状态刷到 磁盘,并在完成前阻塞重做。这反过来会引入复制延迟,在同步备库上还会阻塞 主库。在过程启动前减小 max_wal_size,有助于缩短 重启点完成所需的时间。
关闭/重启:如果在启用数据校验和期间服务器被关闭或重启,处理过程不会恢复, 所有页面都需要重新计算并重写。应当在无需常规维护或处于服务窗口期间启用数据 校验和。
禁用数据校验和时不会产生 I/O,但仍然需要检查点。