从 PostgreSQL fsync EIO 失败处理说起

💡 原文中文,约12600字,阅读约需30分钟。
📝

内容提要

2018年,PostgreSQL发现fsync()失败可能导致数据静默丢失,称为“fsyncgate”。该问题揭示了Linux内核与数据库在I/O错误处理上的矛盾,尤其在云存储环境中更为突出。PostgreSQL采取了PANIC策略应对fsync失败,但在云环境下可用性风险增加,需改进错误处理机制。

🎯

关键要点

  • 2018年,PostgreSQL发现fsync()失败可能导致数据静默丢失,称为“fsyncgate”。

  • fsyncgate揭示了Linux内核与数据库在I/O错误处理上的矛盾,尤其在云存储环境中更为突出。

  • PostgreSQL采取了PANIC策略应对fsync失败,但在云环境下可用性风险增加。

  • Craig Ringer报告了fsync失败导致数据丢失的案例,指出PostgreSQL的处理方式存在缺陷。

  • Linux内核在fsync失败后将dirty page标记为clean,导致PostgreSQL重试fsync时误认为数据已成功写入。

  • PostgreSQL开发者对内核行为表示愤怒,认为fsync失败后应保持page的dirty状态。

  • FreeBSD的fsync处理方式与Linux不同,保持page为dirty以便后续重试。

  • 内核开发者面临的挑战是平衡不同用户场景的需求,数据库开发者要求数据持久化的严格性。

  • PostgreSQL在2018年11月合入了PANIC on fsync failure的策略,避免静默数据损坏。

  • PANIC策略的代价是可用性下降,导致数据库实例崩溃和WAL恢复时间延长。

  • Direct I/O被认为是长期解决方案,但PG开发者认为实施难度大。

  • Wisconsin大学的研究表明,许多数据库在fsync失败时的错误处理不足,无法保证数据持久性。

  • fsyncgate并非PostgreSQL第一次因对OS层行为做过多假设而导致问题,历史上还有其他类似问题。

  • 在云原生时代,fsync失败的语义变化使得I/O错误频率显著增加,影响数据库可用性。

  • PlanetScale的实证数据表明,云存储的性能降级率远超本地存储,导致数据库面临更高的可用性风险。

  • CloudJump提出了针对云存储特性进行数据库层面系统性适配的优化准则。

  • 在云环境中,EIO的瞬态性改变了fsync失败处理的决策框架,PostgreSQL的PANIC策略代价过高。

  • 改进思路是区分WAL和数据文件的fsync失败处理,WAL文件的fsync失败应PANIC,而数据文件可考虑重试。

  • Direct I/O被认为是解决fsync失败后优雅重试的根本出路,能够避免状态不一致的问题。

  • 云厂商可以提供更丰富的错误语义,帮助数据库更好地处理瞬态错误。

  • 长期缺失的文档和指导使得数据库开发者难以理解内核的行为,导致错误处理不足。

  • 依赖OS层的隐式保证是危险的,云原生时代的高频瞬态I/O错误暴露了这一问题。

延伸问答

fsyncgate是什么问题,它对PostgreSQL有什么影响?

fsyncgate是PostgreSQL在2018年发现的一个问题,fsync()失败可能导致数据静默丢失,揭示了Linux内核与数据库在I/O错误处理上的矛盾,尤其在云存储环境中影响更大。

PostgreSQL是如何应对fsync失败的?

PostgreSQL采取了PANIC策略应对fsync失败,这意味着在fsync失败时会导致整个数据库实例崩溃,以避免静默数据损坏。

fsync失败后,Linux内核是如何处理dirty page的?

Linux内核在fsync失败后会将相关的dirty page标记为clean,这导致PostgreSQL在重试fsync时误认为数据已成功写入。

为什么PostgreSQL的PANIC策略会导致可用性下降?

PANIC策略会导致数据库实例崩溃,并需要进行WAL恢复,这可能耗时数分钟到数十分钟,从而降低了可用性。

在云存储环境中,fsync失败的语义有什么变化?

在云存储环境中,fsync失败的瞬态性增加,导致I/O错误频率显著上升,这对数据库的可用性构成了更高的风险。

如何改进PostgreSQL对fsync失败的处理?

改进思路是区分WAL和数据文件的fsync失败处理,WAL文件的fsync失败应PANIC,而数据文件可考虑重试。

➡️

继续阅读