LWN: 在block layer中取得功能和性能的平衡?
关注了就能看到更多这么棒的文章哦~
The balance between features and performance in the block layer
By Jonathan Corbet
November 5, 2021
DeepL assisted translation
https://lwn.net/Articles/874643/
早在 9 月份的时候,LWN 就介绍了一系列的 block layer 的优化,使一个具有合适硬件配置的系统能够维持每秒 350 万次 I/O 操作(IOPS)。在那之后,这项优化工作也一直在继续,而现在这 350 万次 IOPS 已经完全算不上值得骄傲的内容了。不过,最近关于是否要增加一项新功能引出的争议,就凸显对 block layer 进行深度优化所带来的额外成本。那么什么时机最适合判定一项功能是足够重要,以至于宁愿牺牲最大性能呢?
block subsystem 维护者 Jens Axboe 一直在努力使 block I/O 操作更快。最近一轮的 patch 调整了各种快速路径(fast path),修改插入(plugging)机制来使用单向链表,并做了其他各种小改动。每一个改动都是一些小优化,但随着时间的推移,这些优化会累计起来带来令人震惊的成果。现在能达到的的性能指标是 820 万次 IOPS,已经远远超过 9 月份的性能了,而当时的数据在当时已经很令人震惊了。这项工作后来作为 5.16 版本的 block 子系统的 pull request 的一部分合入了 mainline。
到目前为止,情况还不错。很少有人会对性能大幅改进的情况提出异议。但他们却可能会对那些有可能干扰到这些改进的那些改动提出反对意见,哪怕仅仅是很小的干扰。
比如说 Jane Chu 的 patch set。它为 preadv2() 和 pwritev2() 系统调用添加了一个新的 flag(RWF_RECOVERY_DATA),可以由那些试图从非易失性存储器(nonvolatile-memory)的 "poisoning" 状态中恢复出来的应用来调用。非易失性存储器的实现中有多种不同的方法来检测和处理损坏了的数据。Intel memory 会将这个区域改成 poison 状态,它的意思是说之后每次访问的时候都会产生一个错误(会被转化成为一个 SIGBUS 信号)。应用程序可以通过对这个 poisoned 区域进行 read 或 write 的时候确保设置这个新的 flag。read 的时候会用全零数据来替换这些 poisoned 数据(也就是应用程序仍然可以读到那些此刻仍然可读取的数据),而 write 操作将把该区域覆盖写入,并试图清除这个 poisoned 状态。使用这两种方式之一的话,应用程序就可以试着从错误状态中恢复出来并继续运行。
Christoph Hellwig 反对这个新的 flag,理由是它会拖慢 I/O fast path:
好吧,我的观点是,从 bit errors 中恢复出来,从定义上来讲就不应该属于 fast path 的工作。这就是为什么我希望让它不要影响 pmem read/write 的 fast path,更重要的是,这部分代码也会在那些不是 pmem read/write 的操作中执行到。
Pavel Begunkov 也抱怨说,每个 flag 都会引入一些开销,随着时间的推移而堆积起来。"当涉及到真正的快速设备时,默认配置的内核已经显得很慢了,而且还没有改善的迹象"。这引起了 Darrick Wong 的疑问:"所以我们不能有 data recovery 动作,就是因为数据访问的速度[是]唯一的目标?"。Begunkov 否认了这句话,但并不清楚他具体是什么意思。
在不使用该 flag 的情况下,这个 flag 引入的开销很小,也许甚至根本测量不出来。但是对于那些正在努力使 sustained IOPS 的数字尽可能高的开发人员来说,哪怕是这种微小开销也是不可接受的。一个 flag 接着另一个 flag,在未来的某一天,这里引入的性能开销就会变得影响更加大了,当然这也许只是一个论点而已。按照这个观点,那么为了避免这种问题,像非易失性内存 poison 状态恢复这样的小众功能就应该被限制在内核中那些不属于 fast path 的部分。在这种情况下,有人建议并尝试着在 fallocate() 中添加这些功能,但最终看下来 fallocate() 并不是一个实现 poison 状态清理这类硬件管理功能的正确位置。
因此,目前的实现代码就被 fast-path 相关的担忧给阻碍住了。这反过来又引起了 Dave Chinner 的大爆发,他认为目前的许多优化工作都是不合适的:
目前这种以牺牲其他功能为代价、专门针对最大的每 CPU 核 IOPS 而对 IO path 进行极端优化的方法,在过去已经被证明是 IO path 开发中的错误方式。是的,我们需要关注性能,并努力提高性能,但我们不应该以牺牲 IO stack 的其他目的作为代价。
他继续说道,优化应该在所需的功能出现之后再进行。"用 'fast path 优化' 作为一种暴力阻止新功能实现的方式是……令人厌恶的"。
在那之后,对话很快就停止了。几十年来,这种关于功能和性能的分歧已经在内核社区中出现过多次了。更快的速度,是一个受欢迎的目标,而那些专注于性能的开发者已经知道他们已经厌倦了新功能添加时所引入的性能退步,而这些功能又是随着时间的推移而逐渐积累起来的。但是,功能也是很重要的,开发人员厌倦了为了那些看似无关紧要的性能问题而阻挠所需的功能。
通常情况下,与性能有关的反对意见会引出对解决方案的修改和调整,从而得到没有那么多性能影响的新的实现。值得注意的,Hellwig 接下来提出了一些想法,希望可以改进这些针对非易失性存储器的 I/O 操作。其他时候则可能会导致这个新功能被延迟或直接阻塞住了。这次的情况下会发生什么,目前还不清楚,但像这样的争论在未来几十年里几乎肯定也会伴随着我们。归根结底,这就是如何在性能和功能之间找到正确的平衡(希望能找到这样的平衡点)。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~