关注了就能看到更多这么棒的文章哦~
Supporting untorn buffered writes
By Jake Edge
April 4, 2025
LSFMM+BPF
Gemini-1.5-flash translation
https://lwn.net/Articles/1016015/
在去年的 Linux 存储、文件系统、内存管理和 BPF 峰会 (LSFMM+BPF) 上,曾就原子写入 (atomic writes)进行过一次讨论,并随之发布了补丁,以在块层 (block layer) 中支持该特性,以及在 XFS 上支持直接 I/O (direct I/O)。该工作已经合并,但讨论的另一部分内容涉及为缓冲 I/O (buffered I/O) 添加该特性,部分原因是 PostgreSQL 数据库目前必须费尽周折以确保其写入在发生错误或崩溃时不会被“撕裂”(部分写入)。 Luis Chamberlain 在今年的峰会上主持了一个存储和文件系统联合讨论环节,以重新审视为缓冲 I/O 提供原子(或不可撕裂)写入的想法。
Chamberlain 认为,有人相信仅仅为了解决 PostgreSQL 中缺少的功能而研究缓冲原子 I/O 是没有意义的;有些人认为该数据库应该直接支持直接 I/O。他说,MongoDB 的默认存储引擎同时支持缓冲和直接 I/O,但 MongoDB 建议使用缓冲。原因是 MongoDB 默认在磁盘上压缩数据,并在其缓存中保持数据未压缩。数据可以通过 mmap()
访问,这与直接 I/O 不兼容。
他认为数据库开发人员应该能够决定最适合他们需求的架构。提供不可撕裂的缓冲写入允许数据库消除他们现在为解决这个问题而进行做的双缓冲 (double-buffering)。有一些配置选项可以关闭 MySQL 和 PostgreSQL 的双缓冲,可用于测试更改的影响。
原子写入 API 最终可以被数据库使用,以提供防止撕裂写入的功能,但可以在没有它的情况下运行原型,以验证数据库是否正在写入该 API 所需的正确大小和对齐方式。在他的幻灯片中,Chamberlain 展示了在启用和禁用双缓冲选项的情况下运行 MySQL 和 PostgreSQL 的图表。两者都显示了更高的平均每秒事务数,并且在没有双缓冲的情况下,可变性要小得多。为了重现这些结果,Chamberlain 建议使用 blkalgn,他称之为“I/O 原子对齐验证和可视化的最佳工具”。这些测试已集成到他的 kdevops 内核开发和测试工具中。
Chamberlain 想知道下一步可能是什么。 John Garry 说,他认为验证这个想法的测试也应该用更多的线程来运行,因为至少对于 MySQL 来说,他的测试表明当多个线程写入时存在一些争用。 Chamberlain 同意这一点,并指出这些测试可以在 kdevops 中轻松运行,因此需要使用各种数量的线程进行测试;这些测试运行时间很长(12 小时),所以他还没有进行进一步的测试。他说社区的各个成员需要自己做功课,以确定是否支持该功能才有意义;如果是这样,那么问题是 API 应该是什么。
正如 Chamberlain 早些时候提到的,Ted Ts'o 指出,各种大型云厂商(超大规模厂商)已经有了利用不可撕裂写入的托管 MySQL 解决方案。他们这样做“没有任何上游补丁,只是审计代码路径,并且只要你真的非常小心,它在很大程度上就能工作”。因此,他同意社区需要做功课,但供应商已经明确表示他们看到了优势,至少对于 MySQL 和直接 I/O 而言。
他对原子缓冲 I/O 的主要担忧是 RWF_ATOMIC
标志的语义。数据库人员只需要 8KB、16KB 以及可能在将来的 32KB 大小的不可撕裂写入,但文件系统开发社区的某些人认为应该完全支持带有原子标志的 1MB 写入。对于直接 I/O 来说,这将是痛苦的,但对于缓冲 I/O 来说,这极其困难。内核需要跟踪不同的原子写入大小,因为它们会通过页面缓存 (page cache) 并到达存储介质。可能存在“使用大型页 (large folios) 并确保在这种情况下不会拆分大型页的奇特方法”,但他认为限制不可撕裂写入的大小更有意义。
Ts'o 的另一个担忧是当页面被锁定时(例如,页面错误 (page fault) 正在进行中)的回写 (writeback)。目前,回写线程只是跳过任何锁定的页面,这可能会导致撕裂写入。他认为 XFS 对原子写入的实现解决了这个问题,尽管他没有仔细研究,但可能需要更通用的解决方案。
David Howells 询问了原子写入和 mmap()
之间的交互。 Ts'o 说,文件的映射部分的对齐和长度需要与原子写入所需的一致,这大概就是 XFS 所做的事情。 Howells 说,当缓冲和直接 I/O 都对同一个文件进行时,会出现另一个问题。 Ts'o 说,文件系统社区一直建议不要组合缓冲和直接 I/O,但是,由于已知 MySQL 及其备份程序已经这样做了,因此社区“在某些情况下使其安全”;他说,一切都只有 99.9% 的时间有效。
Chamberlain 说,因为 RWF_ATOMIC
标志正在标记 I/O,所以文件系统可以防止有问题的组合。 Amir Goldstein 建议,文件应该打开以进行原子直接 I/O 或原子缓冲 I/O,这类似于为 FUSE 透传模式 (passthrough mode)添加的限制;在文件打开时,文件的 inode 上有一个标志指示其模式。 Jeff Layton 指出, RWF_ATOMIC
是 I/O 操作上的一个标志,而不是 open 操作上的标志,但它可以用于简单地为违反组合规则的操作返回 =EINVAL=。
Ts'o 认为切换到 open 标志是有意义的,并建议 O_UNTORN
将是正确的名称;不可撕裂写入的粒度可以放在 inode 中。他看到的一个问题是,开发人员一直在使用“原子”这个术语,因为这是 SCSI 和 NVMe 使用的术语,但随后人们希望 1MB 的原子写入能够工作,但这根本不是数据库开发人员所关心的。他认为,切换到不可撕裂 (untorn),并清楚地说明支持的粒度将有助于简化 API,并使该功能更快地落地。
Chamberlain 向 Jens Axboe 询问了用于非缓存缓冲 I/O 的 RWF_UNCACHED 标志,以及它是否适合用于不可撕裂写入。 Axboe 并没有真正的意见,因为这主要是一个文件系统问题,而不是一个块层问题,但可以看到该标志的某些效果可能是有用的——例如,立即启动回写。 Ts'o 警告说,PostgreSQL 开发人员实际上希望页面缓存管理数据库的缓存,正如他所理解的那样。他们没有切换到使用直接 I/O 的原因之一是他们需要做自己的用户空间缓存管理;他建议与 PostgreSQL 开发人员交谈以评估他们的需求。
Chris Mason 说,对缓存的、不可撕裂的写入的需求并不意味着不应该支持非缓存的、不可撕裂的写入。 Chamberlain 和其他人都同意这一点。 Christian Brauner 指出,添加 open 标志并标记 inode 意味着该文件的其他用户可能会被排除在外;这意味着应该需要某种权限。 Ts'o 说,“致命的组合”是一个文件打开以进行不可撕裂的写入,然后又打开以进行直接 I/O;这种组合非常罕见,以至于第二次打开可能会失败。
此时,会议时间已经用完,但 Chamberlain 说,开发人员似乎有兴趣支持不可撕裂的缓冲写入,但只能使用一些尚未确定的限制性规则。 Goldstein 建议从某种选择加入 (opt-in) 方式开始,也许是通过挂载选项或文件系统创建标志,然后可能会从那里扩展该功能。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
欢迎分享、转载及基于现有协议再创作~
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~