「“星”技术」How to Copy Files— FAST'20 论文解读
01
导读
这篇发表于FAST20会议的论文,是关于如何高效率的对文件目录树进行快速克隆操作,由来自北卡罗来纳大学教堂山分校的Yang Zhan,Yizheng Jiao以及 罗格斯大学,佩斯大学,石溪大学,VMWare研究中心的相关研究人员合作开发完成的。文章中所用图表,除非特别注明,都来自于原版论文。
02
概述
作者在一开始先介绍了快速克隆的背景和重要性。随着虚拟化的广为流行,各种应用对快速克隆都有着很强的需求,典型的,如快速创建虚拟机,就需要快速克隆出虚拟机的“root filesystem”即一个image磁盘文件。而在容器场景下,如docker会非常频繁的对一个特定的文件系统目录树进行快速拷贝,这些都需要高效的克隆机制。针对于这些应用场景,现有的文件系统已经实现了一些“逻辑拷贝”功能,有别于“物理拷贝”,逻辑拷贝一般在实现时只进行一些元数据级别的拷贝,而只有在后续的修改中,才按需对文件数据进行拷贝并修改,这种功能称作COW(copy-on-write),这种方法在拷贝的时效性和空间的利用率方面都得到了较大的提升,因此现在已经成为克隆的基础技术。在实现时,一般存在着基于block粒度的COW和基于file或者dir级别的COW,比如btrfs和xfs使用的cp –reflink技术。这里作者指出,对于经典的COW技术,主要存在着“拷贝粒度”的问题,比如对于基于file级别的COW,一次微小的修改就可能导致昂贵的拷贝,比如1G大小的文件,只修改其中的1个字节,也会触发1G文件的拷贝。这会极大的增加初次COW写入时延,而且也不可避免的造成了空间上的浪费。反之,如果拷贝粒度过小,则初次COW写入时延有保证,但却容易造成碎片化(想象一下1个很大的文件,4K拷贝粒度,随机写入则会造成很多个4K COW块),后续顺序读的时候,因为这些4K数据并不是连续的,则读取速度会很慢。因此这里作者提出了自己对高效克隆的看法,需要满足如下4个特性才能被称作是合格的,作者称为“Nimble clones (敏捷克隆)”必须能快速的完成克隆操作。
必须有良好的read locality (读取局部性),这样逻辑上相关的文件集读取起来会比较快,同时经过COW后,性能也应该保持一致。
必须有良好的写性能,不管是对克隆前的文件集和克隆后的文件集进行写入。
空间利用率必须要好。写放大应该尽量保持比较低的水平。
设计和实现了Bε-DAG数据结构,作为Nimble clones的基础。该方法扩展了Bε-tree,用来聚集小的修改,再择机进行批量写入。
写优化的克隆实现。在进行克隆操作时,仅需简单的向DAG root节点写入一个GOTO message消息。
量化的渐进分析表明,增加克隆不会影响其它的操作。克隆算法开销是对数级别的。
全面的测试表明,优化过的BetrFS并没有对原来的BetrFS基线产生不利的影响,而在clone特性上,对比传统的支持克隆特性的文件系统,在性能上有3-4倍的提高,而对比不支持克隆特性的文件系统,则有2个数量级的提高。
03
BetrFS背景知识
为深入理解这篇论文,需要先理解BetrFS的背景知识。BetrFS是该团队开发的一个用于研究型的文件系统,从2015年到现在,作者团队已经基于该文件系统发布了多篇论文,详情请参考BetrFS官网。BetrFS是一个内核态的基于KV存储的本地文件系统。不同于传统的文件系统,如XFS,Ext4,这些文件系统都是基于inode和B-tree(或B-tree变体)来管理和组织元数据和文件系统数据的。而BetrFS是基于Key-Value的,它有2个KV stores。其中,元数据KV存储的是 文件全路径(fullpath) 到 文件系统元数据(struct stat)的映射。数据KV 存储的是 {fullpath+block number} 到 4K block的映射。图片来源:附2
range查询
因为采用了基于fullpath的KV存储,比如基于下面的文件名,在存储时都有相同的前缀,所以在实际算法运行中,基本都会落在同一个node上,因此在做range查询时,比如遍历目录下面的所有子目录或者文件时,落在磁盘上的IO,也将会是连续的,所以遍历速度会很快。同时,在删除操作中,也比较容易对删除流程进行优化,比如设计一个delete message,实现标记删除,然后后续在进行删除操作。
基于fullpath的 rename操作
对于基于fullpath的文件rename操作来说,是比较有挑战性的。回想一下,在Bε-tree中,所有key都是全路径的,因此在rename一个文件夹时,比如文件夹A rename成B,那么A下面所有子文件夹和子文件的key都要做对应的修改。作者团队在 附3 的论文中给出的解决方案是使用range rename操作,这种方案的关键之处在于在内部存有一个指针,用来指向文件夹源和目的的子树,range rename的操作可以转换成将这个指针转向,即所谓“pointer swing”,后续子树会进行自愈,以达到rename的目的。关于这种方法的更多细节,请参考附3论文,这里不再展开。
掉电恢复一致性问题
文件系统掉电恢复一致性向来是文件系统值得研究的一个关键问题,典型如ext4,xfs都使用了journal机制和事务性来保证在异常掉电时,文件系统依然能正确恢复,从而达到一致性的状态。BetrFS的Bε-tree也使用了类似的机制,对Bε-tree进行的任何修改,都需要提前记录日志,Bε-tree会周期性的进行checkpoint,比如每60s 进行一次checkpoint,完成后,会修剪redo log。在异常掉电时,依靠回放redo log来达到一致性的状态。04Cloning in BetrFS 0.5
这一章作者介绍了如何在BetrFS中实现克隆特性,首先作者先从克隆最基础的语义开始讲起
克隆操作语义
克隆动作是原子的,即要么成功要么失败,不允许有中间状态。
从KV-store的key空间角度来看,clone(s,d)意味着拷贝所有以s为前缀的key到新的以d为前缀的key,另外,它还会同时删除原来的以d为开头的key。
Lifted Bε-DAGs
克隆的本质是要在Bε-tree树上增加新的edge,以使得在访问克隆后的文件夹时,能通过某种方法访问克隆前的数据(克隆后的数据在不修改内容前,都是完全共享的)。在Bε-tree这样的数据结构上访问,是做不到这点的,因此,需要对Bε-tree进行改进,以支持共享访问,而DAG(有向无环图)可以完成这个功能。如下图所示,底层的node节点在DAG数据结构中,是可以被上面两个路径来访问的。
图片来源:附4
在对Bε-tree进行改进时,作者强调需要解决3个问题:
1、因为对node可能有来自多个路径的访问,所以需要对node维护一份引用计数,引用计数并不存放在node本身的数据结构中,而是存放在专门的 node translation table 中,这样在修改引用计数时,并不需要更改node数据结构本身,避免了需要加速解锁等操作,以便于提升性能。
2、问题2是在Bε-tree中,node通常设置的比较大,如2M~4M大小,这样也就意味着1个node上会有很多key值。因此,共享target node意味着会有一些冗余的key也会被共享,例如如下图2所示:
底下的node包含了所有以s为前缀的key空间,但同时也包含了以q和v开头的key,而这些key是冗余的,不应该被访问到的。因此,作者在这里对pivots域内的key使用了过滤技术,以用来过滤那些冗余的key。
3、使用translation prefix(前缀转换)技术,还是如上面图2所示,在将s开头的目录转换成以p开头的目录后,会在上面的节点上插入指针,指向下面的节点,那后续查询pw时,在pivots找到指向下面的节点,但因为是clone过来的,所以这里需要进行translation prefix,即先去掉p,在下面节点查询时,按照sw进行查询。这种转换只是临时的,因为克隆最终完成时,需要将节点变成一般的节点,后文会有描述。
Creating clones with GOTO messages
论文接下来讲述创建克隆的过程。首先,如下图3所示,要clone所有以s开头的key到以p开头的key,则需要先找到所有以s开头的key node的父节点,称作 LCA (lowest-common ancestor);
接着要做的是一次flush操作,即将从最开始的root节点到LCA之间节点暂存的所有以s开头的key都持久化下来,以保证LCA是完整的包含了以s开头的完整key空间。待flush完成后,再向root节点插入一条GOTO message,则完成clone过程。
而在部分重叠的情况下,还要更为复杂一些。比如上图左边的(pa,pz) 和(r,w)的部分重叠于 (pab,t)。
值得注意的是,这些复杂的步骤只是在clone以后,有数据写入时,而且达到一定条件后才触发的,或者是在后台为了平衡Bε-DAG状态而进行的。对于那些未修改的共享node,是不需要进行这些复杂的过程的。
05
算法渐进分析
对Bε-DAG的渐进分析表明,插入,查询,和克隆的复杂度都只与Bε-DAG的高度有关,它的渐进复杂度与lifted Bε-tree是一致的。可以这样考虑,如果我们将GOTO message都flush下去,转换成一般的pivots,这样消除掉GOTO message后,再断开共享的node链接后,就会形成一棵Bε-tree,这棵树的高度最高也就和Bε-DAG的高度相同。Bε-tree和Bε-DAG的高度都是 O(logB N), 前者N是指tree的key number,后者的N是指clone前的key加上clone的key个数。查询:因为Bε-DAG的高度是 O(logB N),因此IO查询代价也是O(logB N)插入:插入的复杂度和Bε-tree也是一样,为:克隆:克隆的过程可以分为2个阶段,第一个阶段是在线的,第二个阶段是后台的。在线阶段只包含将LCA以上的含有s的消息flush到LCA上和向root node上插入一条GOTO message的代价。这个代价是O(logB N)级别,后台处理阶段主要是后台进程将GOTO message向下flush,并且最终转换为一般的pivots。其算法复杂度也是O(logB N)级别。
06
评估分析
论文在评估分析一章中给出了性能测试结果,主要回答了如下几个问题:BetrFS 0.5中实现的克隆特性是否满足如下这4个设计目标:能高速创建克隆吗,读满足局部性原理吗,满足快速写吗,空间浪费如何;
引入克隆特性,是否会对以前版本的性能造成冲击;
克隆特性是否能提高真实应用的性能。
在目录操作性能测试中,主要进行了递归的grep,find和delete操作,结果如下表所示,BetrFS 0.5和BetrFS 0.4性能基本一致,不会因为clone的引入而对性能有所损失,而比起传统的文件系统性能,都是有数量级的性能提高。
在具体应用程序的评测方面,作者选取了 git clone,tar,rsync,IMAP server进行测试,结果如下:
如表所示,BetrFS实现的容器后端克隆特性比ZFS和BetrFS要快好几倍,比起传统的Dir实现,则是好几个数量级的提高。
07
结语
通过将CoW特性中的copy和write进行解耦,作者团队在已有的BetrFS之上,开发出了具有高效率的clone/读/写以及高效的空间使用率的新的文件系统。从性能测试结果以及真实应用的表现来看,都完成了这些看似矛盾的目标。同时,使用的一些如诸如小IO汇聚,批量写入,Bε-DAG等数据结构与技术都是比较通用的技术,可以用于任何以Key-value store为基础的应用软件上,而不仅仅只是文件系统。附1:FAST15 BetrFS: A Right-Optimized Write-Optimized File System(http://supertech.csail.mit.edu/papers/JannenYuZh15a.pdf)附2:An Introduction to Bε-trees and WriteOptimization(https://www.usenix.org/system/files/login/articles/login_oct15_05_bender.pdf)附3:The Full Path to Full-Path Indexing(https://www.usenix.org/system/files/conference/fast18/fast18-zhan.pdf)附4:How to Copy Files slide(https://www.usenix.org/sites/default/files/conference/protected-files/fast20_slides_conway.pdf)附5:原始论文链接 how to copy file(https://www.usenix.org/system/files/fast20-zhan.pdf)“星”招聘
--JOIN US--
资深存储研发(文件系统方向)
深圳
职位描述:
1、5年以上相关领域开发经验,有良好的C/C++开发能力,扎实的计算机底层技术,包括操作系统原理,数据结构算法知识,虚拟化技术。
2、熟悉Linux存储IO栈路径,有用户态和内核态开发经验。
3、熟悉Linux下的XFS或者Ext4文件系统,理解其实现原理。
4、至少熟悉以下几种分布式文件系统之一,CephFS,GlusterFS,GFS2,Lustre,HDFS,理解其设计宗旨和实现原理。
阅读原文,查询更多热招岗位