为了账号安全,请及时绑定邮箱和手机立即绑定

基于闪存的缓存替换算法CFLRU:优化干净与脏页面淘汰策略

由AI生成的图片

最近我阅读了一些关于NAND闪存缓存淘汰算法的研究论文,这些算法优化了干净页面的淘汰而非脏页面,包括这篇:CFLRU: 一种用于闪存的替换算法 由Seon-yeong Park等人撰写 [1]。这是一篇较短的论文,我很喜欢作者用可视化的方法清晰地解释问题和解决方案。此外,这篇论文也被许多其他研究引用。在这篇博客里,我会总结这篇论文,并从工程师的角度分享我的一些见解。

页面缓存机制和缓存替换

为了说明背景,操作系统(以及其他存储系统如数据库系统)需要一个缓存淘汰算法来管理磁盘数据的内存页缓存,比如文件和交换空间。通常,操作系统有一个有限的内存来缓存最近从硬盘读取的数据,以4KB的页面大小。当页面缓存已满时,如果一个进程需要更多空间,操作系统需要先淘汰一个页面来释放内存空间。这就需要一个缓存淘汰算法来决定淘汰哪个页面。

一个理想的缓存淘汰算法应该提高缓存命中率,避免淘汰那些很快会被再次访问的页面。通常会使用LRU(最近最少使用)或LFU(最不频繁使用)算法或它们的变体。

硬盘和SSD

这篇关于CFLRU的文章发表于2006年,当时SSD正迅速兴起,需要新的缓存方案来优化针对NAND闪存的特定特点。

更具体地说,传统磁盘在“寻道时间”上特别慢,即机械头定位到磁盘上特定位置所需的时间。一旦这个时间过去,读写磁盘上的数据的额外成本就会小得多。

在NAND闪存中,读取和写入操作没有寻址时间。然而,随机写入明显慢于随机读取。写入一个4KB页面的操作需要先擦除整个128KB或类似大小的擦除块,然后将该4KB页面写入。下表给出了读取和写入操作的相对时间成本[3]:

此外,一个 SSD 单元只能承受有限次数的擦除操作,之后就会老化。因此,我们希望能减少块擦除的次数,从而延长 SSD 的寿命。

干净页面和脏页面的区别

这些特性要求为固态硬盘(SSD)设计不同的缓存淘汰算法,主要是在选择淘汰“干净”页还是“脏”页上。如果一个页是从磁盘读取而未被修改,那么它是干净的。一旦被修改,它就会变成脏页。淘汰干净的页成本很低。但是要淘汰一个脏页,操作系统需要先将该脏页从内存写入到磁盘。如果你推迟淘汰一个“热”脏页,并且应用程序很快再次更新该页,你可以避免额外的写入I/O操作,从而免费节省一次写入操作。

尽管如此,传统上并没有多少算法优化来优先驱逐干净页面而非脏页面。我认为这主要是因为1. 这种算法会增加额外的复杂性和运行时开销,以及2. 驱逐热干净的页面比驱逐冷脏的页面更糟:驱逐热干净的页面意味着你很快会再次从磁盘读取该页面,从而浪费昂贵的磁盘寻道时间。

然而,在SSD中,由于写入操作大约比读取慢10倍,并且考虑到磨损影响,设计一种优先驱逐干净页面的缓存替换算法更显必要,因此引入了CFLRU(Clean-First Least Recently Used)算法。

先清空, LRU (CFLRU) 算法

尽管名字如此,该算法并不总是优先驱逐干净的页面。驱逐一个非常热度很高且干净的页面可能比驱逐一个不常访问且脏的页面代价更高,因此,需要一个精巧的方法来平衡两边的代价,以降低总的驱逐成本。

这个算法很容易理解,

在这里,完整的LRU队列被分为两个部分:一个工作区和一个先清理区。

当你插入新页面到队列时,只需将其添加到链表的最近使用的MRU位置(即图中的最左位置),这会自动将工作区域最后一个使用的页面(即LRU位置)推到干净优先区域的最前端(即MRU位置)。如果干净优先区域满了,则需要逐出一个页面。

在驱逐时,算法顺序扫描干净优先区域中,找到并将其驱逐最后一个(LRU,最近最少使用)干净页面。如果干净优先区域中的所有页面都是脏页面,则驱逐最后一个脏页。

确定窗口大小

该算法试图通过调整窗口大小 w 在淘汰热且干净的页面与冷且脏的页面之间找到平衡。想象一下极端情况:如果 w = 1,算法就相当于简单的 LRU,因此会比预期更频繁地淘汰脏页面。另一方面,如果 w 等于 LRU 列表的大小,算法将尝试淘汰最热的干净页面以保留最冷的脏页面,这种情况也不符合预期。

所以,怎么选合适的 w 呢?论文给出了定量分析。

在这里,Y轴表示页面再次被进程使用的概率p。每个直方图条形代表一个页面缓存槽。随着页面缓存列表从MRU端移动到LRU端,论文假设概率从高到低变化,这是一个公平(尽管并不总是正确的)假设。正如你所见,随着窗口大小w的扩大,概率p较高的干净页面会被选择淘汰,而非概率极低的脏页面,最终成本高过收益。

为了找到最佳的 w,一种方法是手动基准测试并调整(CFLRU-static)参数的值。另一种方法是在运行时动态调整窗口大小 (w),通过定时测量成本函数并根据结果调整:如果缓存中页面丢失过多,则表明 w 过大,降低 w 可使更多热清洁页面保留在缓存中。如果脏页面刷新次数过多,则需要增大 w,以优先驱逐清洁页面。该论文采用固定 1:8 的比率,表示从存储读取一页的代价与刷新一页的代价之比。

在 Linux 内核中,作者引入了一个后台程序,用于定期测量最近一段时间内的页面替换代价,并与之前的一段时间比较,以决定是否增加或减少窗口尺寸。为了防止 w 值波动,两个时间段之间的差异必须超过预定义的阈值。

图4显示,一个良好调校的静态参数在特定的工作负载模式下表现最佳。一个动态调校的参数表现也不错,但有时不如静态参数,这可能是由于运行时调校的开销及次优的自动调校决策导致的?无论如何,动态调校允许系统根据应用程序需求的变化迅速调整(例如在个人电脑上)。

自动调谐的实践

可惜的是,在论文中没找到自动调谐的算法呢。

在实践中,在动态变化的环境中自动调整参数从来都不是一件容易的事。这涉及一个反馈控制环路,这种环路广泛存在于各种跨学科的控制系统中(比如你家中的温控器)。振荡是常见的第一个挑战:就像你的温控器可能在房间过热和不足之间振荡一样,一个简单的控制系统往往会因输入信号而对调整目标过度补偿,从而导致振荡 [4]。

这样的自动调谐算法增加复杂性,往往会伴随着额外的CPU和内存开销,特别是在内核页面缓存驱逐算法中,这种开销可能相当大。

这就是为什么(我猜)后续的研究(如CFLRU/C、CFLRU/E、DL-CFLRU/E [5]、CCF-LRU[6]、LRU-WSR[7]、APRA [3]等)没有继续采用自动调整。

扫描费用

我认为实践中另一个限制是扫描整个clean-first窗口在实际操作中可能比较费时。假设你有一个4GB的页缓存,每个页大小为4KB,这将提供100万个页缓存槽。假设w占用了一半的页缓存空间(如图4所示的某些基准测试中),这将导致clean-first窗口中有50万个槽。在最坏的情况下,如果所有这些槽都是脏页(也就是你已经从窗口中驱逐了所有干净的页),内核可能需要扫描多达50万个数组才能找到第一个干净的页。作为经验法则[8],主内存访问的速度大约比SSD随机访问快1000倍。因此,扫描50万个内存项目[9]的成本可能会大大超过减少脏页驱逐带来的好处。

显然,一种优化方法是将干净页面和脏页面分成两个单独的列表,这样可以低成本地找到一个干净的页面来进行驱逐。这一方法是在后续算法DL-CFLRU/E [5] 中引入的(由于篇幅关系,这里不详细讲解)。我认为,这种拆分列表的方法的一个复杂之处在于,随着应用程序对页面进行写入和刷新,页面可能会在干净和脏之间动态切换。这需要缓存淘汰算法能够动态地在干净列表和脏列表之间移动页面,同时保持页面在相应列表中的正确位置,以正确反映LRU / LFU优先级,同时保持性能开销较低。我还没有花太多时间来寻找深入探讨这个问题的论文。

概述

尽管存在上述限制,这仍然是一个很好的起点,特别是在问题空间中。我真的很喜欢这篇论文提供了一个非常简单的起点,只需要少量的编码工作(从LRU缓存转换过来)就能实现。它提供了一个清晰的思维模型,有助于思考如何设计一个高效的、以清理优先的页面缓存淘汰算法。

注释
  1. Park, S.y., Jung, D., Kang, J.u., Kim, J.s., & Lee, J. (2006). CFLRU算法:适合闪存的替换算法. 在 Proceedings of the 2006 International Conference on Compilers, Architecture and Synthesis for Embedded Systems (第234-241页). Association for Computing Machinery. https://doi.org/10.1145/1176760.1176789

  2. 有些设计旨在减少擦除块带来的影响。我发现这本书的第44章很好地解释了SSD的内部工作原理:Arpaci-Dusseau, R. H., & Arpaci-Dusseau, A. C. (2018). Flash-based SSDs. 在 Operating Systems: Three Easy Pieces (第44章). Arpaci-Dusseau Books. https://pages.cs.wisc.edu/~remzi/OSTEP/ .

  3. Shen, B., Jin, X., Song, Y., & Lee, S. (2009). APRA:NAND闪存存储的自适应页面替换算法. 在 2009 International Forum on Computer Science-Technology and Applications (第11-14页). https://ieeexplore.ieee.org/document/5385144 。SSD的IO特性随着时间发生了变化,但这仍然提供了一个大致的概念或想法。

  4. 在某些情况下,一个调整得当的PID控制器可以用来稳定系统:https://en.wikipedia.org/wiki/Proportional%E2%80%93integral%E2%80%93derivative_controller 虽然它并不直接适用于CFLRU的优化情境。

  5. Yoo, H. (2007). NAND闪存存储的页面替换算法. 在 Computational Science and Its Applications — ICCSA 2007 (第201-212页). Springer Berlin Heidelberg. https://link.springer.com/chapter/10.1007/978-3-540-74472-6_16

  6. Li, Z., Jin, P., Su, X., Cui, K., & Yue, L. (2009). CCF-LRU:一种新的闪存替换算法. IEEE Transactions on Consumer Electronics, 55(3), 1351–1359. https://ieeexplore.ieee.org/document/5277999

  7. Jung, H., Shim, H., Park, S., Kang, S., & Cha, J. (2008). LRU-WSR:一种结合了LRU与写入顺序重排的闪存算法. IEEE Transactions on Consumer Electronics, 54(3), 1215–1223. https://ieeexplore.ieee.org/document/4637609

  8. https://github.com/dem0nix/Latency-numbers-every-programmer-should-know-2018

  9. 记住页面缓存是一个链表,而不是顺序数组,因此链表遍历可能比顺序遍历更随机,因此即使在主内存中也可能更慢。此外,如果主内存中有500,000个项目,很可能其中的许多项目并未被缓存在CPU硬件缓存中。
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消