RFLUSH: Rethink the Flush [1]
总结报告
我们知道,现在的存储介质,包括机械硬盘(HDD)以及固态硬盘(SSD),它们都有易失的缓冲区,但是目的可能不同。例如,机械硬盘的缓冲区可以用于将多个写请求聚合到一起,从而减少寻道时间;固态硬盘的缓冲区则可能是为了优化随机写性能和/或进行磨损均衡。
由于有了易失的缓冲区,硬盘也就需要相应的命令确保计算机能够强制将数据从缓冲区写入底层持久化存储介质(包括磁盘或者闪存颗粒),这样的命令叫做FLUSH。特别地,考虑一个银行交易系统,为了能够将交易信息立即持久化保存,上面提到的FLUSH命令确实是必要的,否则交易数据有可能因为系统崩溃或掉电而丢失。论文也提到,有的存储系统采用超级电容等方法来提高数据的安全性,但论文认为这类方案增加了制造成本。由此,硬盘的接口可以简化为这样三个命令:READ,读取数据块;WRITE,写入数据块,可能仅仅写入缓冲区;以及FLUSH,将缓冲区内所有数据块真正写入持久化存储介质。这篇论文认为FLUSH命令的粒度太粗,导致每执行一次FLUSH命令就要将缓冲区内全部数据,包括实际上并不需要立即写入的数据,真正写入持久化存储介质。由于额外写入了不需要立即写入的数据,这样的FLUSH命令很大程度上对性能有不利影响。再次考虑那个银行系统,如果在该系统上同时运行了一个“大数据”分析系统,并且分析系统有大量(事实上并不需要立即持久化保存的)中间结果要写入,此时,由交易系统发出的FLUSH命令会同时将这些中间结果也写入,这就造成了性能的损失。并且,论文指出,随着硬盘技术,特别是固态硬盘技术的发展,硬盘内的缓冲区越来越大(固态硬盘可能会使用若干GB的DRAM作为缓冲区),因此,一条FLUSH命令的开销也就越来越大,对性能的不利影响也就越来越大。同时,我认为FLUSH命令带来的额外的写操作还会使得固态硬盘底层存储介质(即闪存颗粒)的磨损增加,从而导致固态硬盘的整体寿命缩短。为此,论文提出了一种新的命令,叫做RFLUSH。该命令是FLUSH命令的更精细的版本,与FLUSH命令的不同之处就在于RFLUSH命令加入了范围作为参数,指定真正需要FLUSH的地址范围。我认为这样的思想和方法容易理解,因为这样的方法在层次存储器系统的其它层次中已经有所体现。一个可能并不是特别恰当的例子是,处理器地址转换单元的TLB就提供了细粒度的刷新地址转换缓存的命令。
虽然思想很纯粹,发送RFLUSH命令时指定需要FLUSH的地址范围,但是实现上有如下一些细节问题需要考虑。
第一,在哪里使用RFLUSH命令。论文认为,使用RFLUSH命令的位置会不同程度上影响性能。这篇论文选择在fsync一类系统调用的实现中使用RFLUSH命令,作为一个例子。同时,论文指出RFLUSH命令也可以在系统的其他地方使用,例如在日志文件系统或者数据库写日志的时候使用。
第二,如何确定地址范围。前文提到,这篇论文修改fsync一类系统调用,利用RFLUSH命令实现将单个文件的元数据和数据写入持久化存储介质。如果RFLUSH命令使用逻辑块地址的范围作为参数,那么这样就需要跟踪文件的每一个数据块,包括其状态,我认为每个数据块可能有这样的状态:是否处于操作系统内核的内存缓冲区中、是否已经执行WRITE命令但未FLUSH、是否已经FLUSH。跟踪文件的每一个数据块是十分繁琐的,为此,论文首先指出,可以近似认为文件是连续存放的,这样就不必跟踪每一个块,而每次fsync也只需很少几条RFLUSH命令即可,但是效果可能在文件碎片较多的情况下并不是十分理想。最后,论文决定改为使用inode号作为RFLUSH命令的参数,只FLUSH这个inode对应文件的数据块。
第三,对于元数据的处理。论文以F2FS作为例子,这个文件系统在硬盘上的内容分为元数据区以及数据区。经过讨论,论文决定对于任一条元数据区的RFLUSH命令,处理整个元数据区。论文表示,这样做可能会在处理某一个文件的元数据时将另外一个文件的元数据也写入底层存储介质,导致某些顺序要求被违反,因为两个文件的元数据有可能位于同一个逻辑块,而一个逻辑块必须整体写入。然而,论文又说明,现在的文件系统,例如F2FS或者ext4,已经考虑到这一点,因此,这个问题不需要这篇论文来解决。这样做确实会包含一些不必要的块,但即便如此,论文提出的方法对于整体性能的提升也是可观的。
最后,如何将RFLUSH命令实现到已有的硬盘接口协议。论文指出,成熟的硬盘接口,如SATA或SAS等,难以添加论文提出的RFLUSH命令作为扩展,而论文发现新兴的NVMe接口则可以做到这一点。论文同时指出,还可以使用新的固态硬盘架构,这种架构允许主机端直接操纵物理闪存颗粒。对于后者,我的理解就是将FTL(层)从硬盘控制芯片移动到主机端。论文选择了后者,因为实现起来比较方便。此外,上面提到,论文使用inode号作为RFLUSH命令的参数。容易想到,为了实现这一点,需要在WRITE命令写入时也给每一个数据块标记上它对应文件的inode号,方便之后的RFLUSH命令。论文中的实现将缓冲区的块按照inode号为键,组织成了哈希表。
上面多次提到,论文使用inode号作为RFLUSH命令的参数,事实上,我认为这样的RFLUSH命令并不一定要局限于inode号,而可以是给每一个WRITE命令写入的块记录一个通用的标签,执行RFLUSH命令时按照标签匹配相应的块的集合。这样做,可以很容易地将其推广到数据库系统,以及可以很容易地实现隔离。
基于以上讨论,论文使用BlueDBM作为存储设备,实现了RFLUSH命令,并且在F2FS文件系统上修改了fsync一类系统调用,然后做了性能测试。实验具体数据这里不再赘述,但值得注意的是本论文的实验分为micro-benchmark以及macro-benchmark,测试时默认关闭了硬盘的页缓存机制。Micro-benchmark基于fio,使用合成的测试代码,对IOPS、响应时间以及实际写入底层存储介质的数据量进行测量。更具体地,fio生成出的测试代码近似了典型的负载场景,包括同步写以及异步写,也包括写完一定数量的数据后调用或者不调用fsync。Micro-benchmark结果表明,对于IOPS,RFLUSH相比FLUSH有所提升,但是还达不到完全没有FLUSH操作时的理想情况;对于响应时间,RFLUSH能够消除FLUSH的长尾,基本达到与完全没有FLUSH操作时的理想情况差不多的性能;对于实际写入底层存储介质的数据量,RFLUSH能够大幅减少FLUSH带来的写入,基本达到与完全没有FLUSH操作时的理想情况差不多的写入量。Macro-benchmark则使用更真实的软件作为负载,包括Fileserver、Linkbench以及TPC-C,测试时两两组合,测试它们在这样的系统中的实际性能。此外,macro-benchmark还分别测试了关闭和开启页缓存机制两种情况下的性能,RFLUSH相对于FLUSH基本上都能够在性能上有所提升,甚至在个别情况下RFLUSH比完全没有FLUSH操作时的理想情况表现得更好。
总体而言,可以看出RFLUSH对于性能确实有一定提升。
论文内容的分析就到这里,我认为若今后的固态硬盘将FTL(层)从硬盘控制芯片移动到主机端,那么对于硬盘块的操作就直接对应到对物理闪存颗粒的操作,这样自然也就可以从本质上做到更细粒度的FLUSH。
总之,这篇论文的实际价值以及应用场景还需要我们进一步探索与思考。
参考文献
[1] J. Yeon., M. Jeong., S. Lee., E. Lee. RFLUSH: Rethink the Flush. In Proceeding of the 16th USENIX Conference on File and Storage Technologies (2018), FAST, pp. 201-210.
发表评论