Jeremy Schneider:Postgres recovery_prefetch 有害且会导致宕机

Jeremy Schneider:Postgres recovery_prefetch 有害且会导致宕机

💡 原文英文,约1000词,阅读约需4分钟。
📝

内容提要

文章指出 PostgreSQL 的 recovery_prefetch 参数可能引发生产事故:它把主库的大顺序 I/O 转为备库的 8k 随机读,IOPS 放大最高 16 倍,易耗尽备库 IOPS 造成严重延迟;若同步复制连接中断,备库需追平 WAL 才恢复流复制,主库则阻塞所有写入,形成宕机。作者提供了复现方法,倾向全面禁用该参数,或采用双备库加 quorum commit 提升健壮性。

🔎

延伸解读

IOPS放大机制:从顺序I/O到随机读

文章指出,recovery_prefetch 的核心问题在于将主库的大顺序 I/O 转换为备库上的 8k 随机读。对于相同读取字节数,备库的 IOPS 可能被放大至 16 倍。这容易耗尽备库可用 IOPS,导致备库在写入活动后显著滞后。该机制与 FPI/FPW 无关,是独立于常见认知的新发现。

同步复制下的宕机链条

在同步复制中,主库提交依赖至少一个健康备库。当网络故障中断流复制,同时出现写入突发,备库因 IOPS 放大而严重滞后,并进入 WAL 恢复模式;该模式要求备库追平 WAL 后才恢复流复制。若追平耗时数小时,主库将阻塞所有写入,形成宕机。作者提供了可复现步骤。

禁用与架构缓解的权衡

作者倾向全面禁用 recovery_prefetch,测试显示禁用后(FPW 仍开启)备库不再出现读 IOPS 突发,能基本保持同步。另一种思路是采用双备库加 quorum commit(ANY 1),虽增加一个副本成本,但可提升同步复制的健壮性,避免单一备库连接中断即导致主库阻塞。

❓

Q&A

PostgreSQL 的 recovery_prefetch 参数为什么会导致宕机?

recovery_prefetch 会将主库的大顺序 I/O 转换为备库的 8k 随机读,导致 IOPS 放大最高 16 倍,可能耗尽备库 IOPS,使备库严重延迟。在同步复制下,若流复制连接中断,备库需追平 WAL 才能恢复流复制,期间主库阻塞所有写入,从而引发宕机。

recovery_prefetch 对备库 IOPS 有什么具体影响?

对于相同的读取字节数,recovery_prefetch 会将顺序 I/O 转为 8k 随机读,使备库的 IOPS 放大最高 16 倍,容易耗尽备库可用 IOPS,导致备库在写入活动后显著滞后。

如何复现 recovery_prefetch 导致的宕机?

作者提供了复现步骤,详见 GitHub 仓库:https://github.com/ardentperf-labs/walreceiver-outage-repro。基本场景是:网络故障中断流复制的同时发生大量写入活动,备库因 IOPS 放大而严重延迟,无法及时恢复流复制,导致主库阻塞写入。

禁用 recovery_prefetch 能解决问题吗?效果如何?

禁用 recovery_prefetch(保持 FPW 启用)后,UPDATE 期间仍有暂停,但 UPDATE 完成后不再出现长时间暂停,没有读取 IOPS 的爆发,备库基本保持同步,应用 5% 的更新在 10 分钟内完成。作者倾向于全面禁用该参数。

除了禁用 recovery_prefetch,还有什么提升健壮性的方案?

可以考虑使用两个备库并配置 quorum commit(ANY 1),这样虽然总副本数变为三个、成本增加,但能显著提高数据库的健壮性,避免单备库故障导致主库阻塞。

为什么同步复制下备库延迟会导致主库阻塞写入?

在同步复制中,主库提交事务前必须确保 WAL 已传到至少一个健康备库。如果备库因 IOPS 放大而严重延迟,且流复制连接中断,备库需追平 WAL 才能重新进入流复制模式;在此期间主库无法接受写入,所有写操作被阻塞。

🏷️

标签

➡️

继续阅读