你是否知道,在 PostgreSQL 的物理从库(Standby)中,虽然没有与主库完全相同的检查点(checkpoint),但却有一个功能相似的核心机制——重启点(restartpoint)。了解它为何存在以及如何工作,对于管理和优化你的 PostgreSQL 高可用架构至关重要。
从库需要执行 restartpoint 的原因
主库的检查点主要是为了将缓冲区中的脏数据刷新到磁盘,并记录一个一致的状态点,以缩短崩溃恢复时间。那么,一个处于持续恢复状态的从库,为什么也需要类似的操作呢?主要原因有以下几点:
- 控制 WAL 文件增长:这是最直接的原因。restartpoint 会回收那些从库已经回放完毕且不再需要的 WAL 段文件,防止
pg_wal 目录无限膨胀,耗尽磁盘空间。
- 优化恢复性能:通过定期将恢复状态刷新到磁盘并更新
pg_control 文件,restartpoint 为从库自身建立了一个已知的“安全点”。万一从库实例发生崩溃,重启后可以基于这个点进行恢复,避免重新扫描大量已处理的 WAL 数据,从而加快恢复速度。
- 资源管理:与主库的 checkpoint 类似,restartpoint 也会触发脏缓冲区的刷新和同步操作,管理从库本地的内存和 I/O 资源。
根本的设计原因
为什么从库不直接叫 checkpoint 而发明了 restartpoint 这个概念?这背后有两个关键的设计约束:
- 恢复模式的限制:从库运行在持续的恢复模式(Recovery Mode)下。在此模式下,不能创建新的 WAL 记录,包括 checkpoint 记录。因此,从库无法像主库一样“原创”一个检查点,它只能在回放到的、由主库创建好的 checkpoint 记录位置执行操作,这就是 restartpoint。
- 保持主从一致性:restartpoint 确保了从库的状态与主库的某个历史 checkpoint 保持一致。同时,它又赋予了从库独立管理本地资源(如清理旧 WAL)的能力。
主库 checkpoint 与从库回放的关系
一个常见的误解是:主库做一个 checkpoint,从库回放到那里就一定会同步做一个(restartpoint)。实际上,这两者并非一一对应,从库的 restartpoint 频率通常低于主库的 checkpoint。
- 时机不同步:从库只有在回放到主库的 checkpoint 记录时,才具备执行 restartpoint 的资格。
- 触发条件独立:restartpoint 的执行由从库本地的调度器(基于时间或WAL大小)触发,但它受限于“可用的 checkpoint 记录位置”这一前提。
- 性能考虑:过于频繁的 restartpoint(涉及磁盘I/O)会影响从库的回放性能,因此其执行频率会被主动调节。
在从库上,checkpointer 后台进程依然活跃,但它执行的是 restartpoint 任务而非 checkpoint。
Restartpoint 与 Checkpoint 的详细关系
1. 依赖关系
Restartpoint 必须在主库的某个 checkpoint 记录位置执行。从库需要先回放到这个记录点,才能以此为基础发起 restartpoint。
2. 执行条件
即使从库回放到了一个 checkpoint 记录,也可能跳过本次 restartpoint 的执行,具体条件包括:
- 时间条件:距离上一次成功的 restartpoint 时间间隔必须大于等于
checkpoint_timeout 参数设置的值。
- 重复检查:如果上一次 restartpoint 已经是基于当前的 checkpoint 记录执行的,则会跳过。
- 失败重试:如果上一次尝试的 restartpoint 失败了,进程会等待约15秒后重试。
3. 统计计数
从库的统计信息视图(如 pg_stat_bgwriter)清晰地划分了 restartpoint 的计数:
restartpoints_timed:由时间条件(checkpoint_timeout)触发的次数。
restartpoints_req:由其他请求(如WAL文件即将写满)触发的次数。
restartpoints_done:实际成功执行的次数。这个数通常远小于前两者之和。
一个实际场景示例
假设主库按序发生了 3 次 checkpoint (C1, C2, C3),从库的 checkpoint_timeout 设置为 5 分钟,可能发生如下情况:
- 回放 C1:从库回放到 C1,满足时间条件,执行一次 restartpoint (R1)。
- 回放 C2:2分钟后从库回放到 C2。由于距离 R1 仅2分钟(<5分钟),跳过执行 restartpoint。
- 回放 C3:又过了4分钟,从库回放到 C3。此时距离 R1 已6分钟(>5分钟),执行一次 restartpoint (R2)。
最终,主库 3 次 checkpoint,从库只执行了 2 次 restartpoint。这种设计在控制 WAL 增长和避免过多磁盘 I/O 之间取得了平衡。
其他重要注意事项
- restartpoint 的执行频率虽然也受
checkpoint_timeout 参数影响,但实际频率往往低于主库的 checkpoint。
- restartpoint 不会创建新的 WAL 记录,它只是更新从库本地的磁盘状态(如
pg_control 文件)并清理 WAL。
- 在进行从库的增量备份时,备份的起始位置通常依赖于最近一次成功的 restartpoint 位置。
- 即使在从库上手动执行
CHECKPOINT; 命令,实际触发的也是一个 restartpoint,而非创建新的 checkpoint。
- 在高 WAL 生成率的场景下,你可能看到
restartpoints_req 计数快速增长(因为WAL文件回收需求迫切),但 restartpoints_done 受限于时间条件,增长缓慢。
理解 restartpoint 机制,能帮助你更好地监控 PostgreSQL 从库的健康状态,合理设置参数,并有效管理存储空间。例如,当你发现从库的 pg_wal 目录异常增大时,检查 restartpoint 的执行情况应该成为首要的排查步骤之一。如果你在实践中有更多心得或疑问,欢迎在技术社区交流探讨。
|