一种海量小文件对象存储优化方案
2019-08-22屠雪真黄震江
屠雪真,黄震江
(1.河南大学 计算机与信息工程学院,河南 开封 475001;2.南京中兴新软件公司,江苏 南京 210012)
0 引 言
随着移动互联网和云计算技术的迅速发展,数字化信息呈爆炸式增长,特别是科学计算、高性能计算、Web服务等应用领域中图片、邮件、文本、互联网档案、小视频等小文件正以指数级速度增长,使得存储系统面临着巨大挑战。
传统的分布式文件系统是面向大文件数据存储与访问而设计的,在对海量小文件存储与访问时,存在元数据结构效率低、元数据服务器性能瓶颈、磁盘I/O效率低、磁盘空间利用率低和网络通信延时高等一系列问题[1]。究其原因,主要是由元数据和数据两个方面造成的。(1)元数据占比高、访问频率高、耗时开销大。由元数据结构效率公式Pm=Sm/(Sm+Sd),其中Sm为元数据大小,Sd为有效数据大小,每个文件不论大小其元数据大小相同。显然,文件越小,元数据占比就越高,有效数据率就低。而且,依照pNFS的访问规则,读访问一个小文件会经历readdir、Open、layoutget、read和close五个步骤。其中read为数据访问,其余4个步骤均为元数据访问[2]。可见,当小文件数量巨大时,元数据处理就是系统性能瓶颈和存储效率低下的根本所在。(2)数据访问随机性强、I/O粒度小导致磁盘吞吐量低。磁盘仍是当前最主要的存储介质,由于磁盘访址的物理特性使得磁盘“善于顺序读,不善于随机读”和“善于大粒度IO,不善于小粒度IO”,这与海量小文件访问“大量随机小粒度I/O”的特点相对立,导致磁盘吞吐量低。虽然近年来SSD发展迅速,但是海量小文件场景的“大量随机小粒度I/O”依然会影响SSD的性能和寿命。
因此,对海量小文件进行高效存储与访问支持,是存储系统必须面对的现实问题。文中介绍了近年来有关小文件优化的研究和系统实现,对基于对象文件系统的海量小文件优化方案的关键技术展开讨论,并给出实际运行结果及分析。
1 相关工作
业界对解决小文件存储访问的问题进行了大量研究,将小文件聚合成大文件再进行存储访问是主要思路。研究者也提出了其他一些优化小文件存储访问的技术,例如通过简化元数据结构减少元数据服务器负荷,利用缓存提高磁盘I/O效率并降低网络时延等。
这些研究可分为两类:一类是针对特定问题的解决方案,根据特定的应用环境和存储需求,针对小文件带来的某个或某几个问题进行优化,侧重点各不相同,不具有通用性。例如Facebook的Haystacke[3]、淘宝的TFS(Taobao File-System)[4]等。另一类是通用解决方案,其中最广泛的就是文件合并技术。例如基于HDFS研制的海量小文件系统SMDFS[5],提供了基于目录聚合以及针对地理栅格数据金字塔结构局部优化的海量小文件存储方法。
随着非结构化数据日益增长,具有高扩展性、数据存储位置灵活的基于对象接口的分布式文件系统(简称对象文件系统)应运而生。它以对象作为数据存储单元,将所有对象以扁平方式进行存储,元数据和数据一起下放至OSD(object storage device)管理,POSIX接口所涉及的元数据仍由MDS管理。对象文件系统摒弃了传统的集中式存储元数据寻址的方案,客户端只需通过哈希计算的方式即可完成oid到对象存储设备物理位置的映射。元数据服务器的功能被弱化,客户端更多地与均衡分布的OSD集群交互。
典型的对象文件系统有:Inktank公司的Ceph系统[6]、Cluster File Systems公司的Lustre系统[7-8]、Rackspace公司的Swift系统等。其中,Ceph因其在数据访问和信息存储方面的灵活性以及得益于OpenStack的青睐,成为了当前最炙手可热的分布式存储系统。
对象文件系统虽然解决了元数据访问瓶颈的问题,但是对小文件的支持仍是短板。例如,大小为128 KB的8个小文件,每个小文件所占用的存储空间为一个对象,假设对象大小为4 MB,总量1 MB的数据实际共占用了32 MB的存储空间。这样,整个系统的存储空间利用率非常低,对象内大块的“碎片”空间没有得到有效使用。
CephFS支持元数据和数据分离存储,但是对小文件的优化仍然局限在元数据层面。如果上层应用允许,优选RGW对象接口,对象接口天然具备更少的元数据,能支撑更大的容量。虽然CRUSH算法机制解决了元数据的问题,但是Ceph对于海量小文件带来的第二个问题尚不能很好地解决。Ceph社区曾对此问题进行了描述并提出了一种基于rgw的方案,不过在最新代码中,一直未找到方案的实现[9-10]。
许艳艳等通过修改Ceph实现了一个基于可变长分块的文件系统VarFS[11],一个对象可以被多个文件包含。但是合并在同一对象中的小文件没有关联,不能发挥数据“预取”的优势;且VarFS额外的对象元数据服务器增加了内部消息交互负担和系统复杂性,新增的文件接口和Ceph原生接口不兼容。
从这些研究来看,聚合后的小文件没有避开从聚合结构到具体文件的二次映射问题,无论是采用全局索引目录方式,还是聚合结构中的局部索引方式,都是属于“查表检索”的传统理念[12]。而“无中心结构”的对象存储系统更青睐于“计算检索”的设计理念,因此需要一种与对象存储系统设计理念相一致的小文件优化存储与访问方式。
2 基于对象的海量小文件存储优化方案
针对上述问题,文中提出了一种基于对象文件系统的海量小文件存储优化方案。采用“特征聚合、计算定位”的方法获得对象存储位置,根本改变元数据的查表索引方式,在客户端采用小文件数据大粒度预读技术将物理上和逻辑上连续的小文件数据批量预读到本地缓存,聚合小粒度I/O为大粒度I/O,提升了磁盘效率,并使用页面热缓存和温缓存两级队列管理和识别热数据,充分利用文件的局部特征提升后续读访问时缓存命中,降低访问时延。
如图1所示,该系统由客户端、元数据服务器、对象存储集群三部分组成。
图1 基于对象的海量小文件存储优化方案架构
(1)客户端模块。该模块为上层应用提供对象存储接口,实现了读写处理函数,并处理与文件元数据服务器、对象存储集群之间的通讯。在读写数据时,首先需到MDS获取对应文件的元数据,主要包括ino和ono。ino用于全局标识每一个文件,ono是文件分片的编号,用于标识该文件所处的对象。然后通过计算的方式获得该文件的物理位置,即oid。最后直接读写访问OSD,并在读写结束后更新MDS中的元数据。
(2)元数据服务器。该模块为文件接口提供元数据服务,管理的元数据信息主要包括访问权限信息和逻辑视图信息,如ino、ono、最后修改时间、访问权限、文件大小等。只有在需要提供Posix等文件接口时,才需要配置MDS模块。
(3)对象存储集群。负责集群中所有数据与对象的存储,处理集群数据的复制、恢复、再均衡,监控集群状态并保证集群数据的一致性。对象的大小一般配置为2 MB或4 MB。每个对象对应一个Oid,由ino和ono根据算法生成。大文件和小文件的界限也可配置,本方案中设为1 MB。在处理文件读写操作时,首先判断文件的大小。若该文件为小文件,则交由小文件聚合模块处理。若不是小文件,则继续判断文件是否小于一个对象大小,是则由ino直接计算oid,否则将该文件进行切片处理。编号为ino的大文件的第ono个对象的编号oid计算公式为:
Oid=(ino≪32)|ono
(1)
小文件聚合模块负责小文件的特征聚合和计算定位管理。小文件写操作时,计算文件之间的局部性特征,并根据特征选取若干小文件聚合为文件组,将聚合后的文件组作为一个对象发起存储请求;文件读操作时,通过ino和ono计算出小文件所在的对象以及小文件在对象内的区域。
2.1 小文件聚合管理
文中小文件聚合算法的核心思想为“特征聚合,计算定位”,根据文件局部性特征将小文件聚合为文件组,通过条带化规则将一个文件组聚合在一个对象中,通过计算方式高效率地定位对象存储位置,而非低效的查表索引方式,同时能优化数据布局。被聚合的小文件同时拥有良好的时间局部性和空间局部性,使得系统读性能显著提升。
根据对多个应用场景的统计分析,在应用的全生命周期内,小文件访问在整体上呈现出极强的规律性[13]。不仅不同用户的操作概率很不均衡,而且各操作之间也具有很强的相关性。表现为:刚刚被访问过的文件,极有可能在不久之后再次被访问到,即时间局部性[14];将被访问的下一个文件,极有可能就处于之前被访问过的某个文件的附近,即空间局部性。有的应用场景也可根据业务特征确定文件的相关性(例如,同一主题的邮件,本邮件的上一个邮件和下一个邮件,相互关联的图片文件,OTT视频文件的切片,同一文件夹的文件等等)。
所以可以利用文件的空间局部性和时间局部性特征,将小文件聚合缓冲区中的文件,分别置于邻近时间特征队列和邻近空间特征队列中,可以根据特定应用场景特征来设置新的文件关联特征队列,并可调整各特征队列的权重。
在小文件合并过程中,综合利用文件之间的空间局部性、时间局部性以及其他关联特征,尽量将可能连续访问的小文件聚合为文件组,一个文件组中各个文件的元数据和数据聚合在一个对象中连续存储,增强了小文件之间的数据局部性和聚合后存储对象内部的数据局部性。这又把磁盘上的随机I/O转换成了顺序I/O,提高了磁盘I/O效率,并为下一步的小文件数据大粒度预读提供了条件。
本算法扩展了对象存储系统中ono的定义:当ono为正数,表明该文件不是小文件,其绝对值是ino对应的文件被切片之后的顺序编号;当ono为负数,则表明该文件是小文件,其绝对值表示小文件聚合为文件组后,该小文件在文件组存储的对象内的区域编号。
本算法采用的对象条带化规则为,每个小文件在聚合后的对象中单独占用1 MB,单个对象最多可聚合的文件数量为:对象大小/小文件界限大小。其中对象大小、小文件界限大小都是可配置的。编号为ino的小文件被聚合于对象的Oid计算公式为:
Oid=((ino+ono+1)≪32)|1
(2)
该小文件在该对象的第-ono个区域中。这样,本算法可以将若干小文件聚合在同一个对象中,并通过计算获得读写位置。
如图2所示,小文件写聚合流程包括以下步骤:
(1)客户端C1发起文件写请求。
·客户端C1判断是否是小文件,是则放入小文件聚合缓存队列,否则进入正常文件处理流程。
图2 小文件写聚合流程
·按照规则根据聚合特征选取小文件组,阈值到,则客户端C1向元数据服务器MDS发出创建文件组内各小文件(B、C、D、E),(F、G、H、I)元数据的请求。
(2)MDS按规则为小文件分配ino和ono,并创建相关元数据。
·MDS按递增原则为文件组内各小文件逐一分配全局唯一编号ino,相连文件组内各小文件(B、C、D、E),(F、G、H、I)被分配的ino连续递增。
·MDS为文件组内各小文件分配ono,规则为:B为-1,C为-2,D为-3,E为-4;F为-1,G为-2,H为-3,I为-4。
·元数据服务器逐一为上述小文件创建其他元数据,如文件创建时间、访问权限等。
·元数据服务器将上述小文件的ino和ono回传给客户端C1。
(3)客户端C1计算小文件聚合后对象存储的位置,并向该OSD的小文件聚合模块发起处理请求。
·客户端C1收到元数据服务器传来的ino和ono。
·客户端C1根据式2逐个计算出小文件将写入到的对象编号oid。
·客户端C1根据对象编号计算该对象所处的OSD。OSD编号的计算公式为:
OSD_num=HASH(oid)
(3)
HASH包括但不限于:平方取中间值、模运算取余、DHT算法、CRUSH算法。
·客户端C1根据OSD_num向对象存储设备发出小文件聚合写请求。
(4)小文件聚合模块将小文件组(B、C、D、E),(F、G、H、I)分别聚合写入到相应对象中,OSD向客户端C1和MSD返回结果。
·小文件聚合模块根据ono判定是否为小文件聚合写操作,非负数则报错。
·小文件聚合模块将各文件组的小文件聚合写入同一对象中。每个小文件存放在相同大小的区域中,对象的第K个区域存放ono为-K的小文件。
·通知客户端C1写入完成,通知MDS更新上述小文件的元数据信息,如最后访问时间等。
如图3所示,读取小文件的流程包括以下步骤:
(1)客户端C2发起请求读取单个小文件或者批量读取小文件。
(2)客户端C2检查当前读取文件的数据是否存在于缓存。如果是,则在缓存中将数据返回给应用,进入步骤6;如果否,则C2向MDS发起请求获取待读取小文件的元数据。
(3)MDS将当前待读取文件的ino和ono发送给客户端C2。
·客户端C2向MDS获取待读取文件的元数据。
·MDS判断访问权限。合法访问则MDS将当前读取文件的ino和ono返回给客户端C2。
(4)客户端计算小文件聚合位置,交由小文件聚合模块处理。
·客户端C2通过式2由ino和ono计算当前待读取小文件所在的对象编号oid。
·客户端C2通过式3由oid计算该对象所存储于OSD的编号OSD_num。
·客户端C2向OSD发出读请求。
(5)小文件聚合模块将编号为oid的对象中的数据返回给客户端C2。客户端C2根据ono,将相应数据返回给上层应用。将该对象中其他区域的数据内容保存在缓存中,后续访问若在缓存命中,则省去了同步读取的时间开销。
·小文件聚合模块将编号为oid的对象中的全部数据发送给客户端C2,同时通知MDS更新该文件的元数据,如最后访问时间等。
·客户端C2收到该对象的数据。将第-ono个区域的数据从对象中取出,返回给上层应用。
·客户端C2将该对象中的其他数据保存在缓存中。
(6)客户端C2检查是否读取完毕,如果否,则读取下一个文件,进入步骤2;如果是,则结束。
综上所述,与现有技术相比,文中提出的小文件聚合方法节省了“查表索引”的开销,根据特征聚合的文件组也提高了小文件间的关联性,可显著提升小文件的读写性能。
2.2 小文件数据大粒度预读技术
在小文件数据读取访问中,由于数据读取粒度小并且不同小文件之间的数据访问空间连续性差,难以发挥磁盘的大粒度顺序访问的性能优势,导致小文件的访问性能远远低于大文件的访问性能。
预读是提升小文件读取访问性能的一个主要方法。针对数据访问时IO粒度小,磁盘吞吐量低的问题,文中采取一种客户端小文件数据大粒度预读技术。通过把将要访问的数据预先读取到客户端缓存,后续客户端访问时可以在缓存中获取数据,节省了同步从磁盘读取数据的开销。
小文件数据大粒度预读通过页面热缓存、页面温缓存、同步预读、异步预读等技术来实现。
页面热缓存:将空间连续的大粒度数据从磁盘预读到客户端缓存后,对于已经与具体要访问的文件相关联的页面直接放到页面热缓存中管理。
页面温缓存:对于暂未关联到任何文件的数据页,记为匿名页,放入页面温缓存管理,每一个匿名页记录着该数据页面在磁盘中的物理位置标识。通过双向链表的方式组织在匿名页面,磁盘中位置连续的数据页面使用同一个匿名页链表管理,并在链表中记录该链表中页面的起始、数量、使用情况等信息。当后续访问发起读盘操作前,先检查页面温缓存,如果命中这个物理位置标识,则将该匿名页直接返回,同时把该页面从页面温缓存中摘除并放入到页面热缓存。
异步预读:在访问过程中,随着匿名页面缓冲区的页面减少到一定程度,使用率达到异步预读触发点,则可认为该链表的预读页面使用情况好,访问局部性强,此时触发异步预读。异步预读技术使得数据在被使用前尽可能地准备好,大幅提升缓存命中率,减少同步IO等待的时延。
同步预读:在客户端读取单个小文件时,不仅获取该小文件所需的小粒度数据,而且还把与该小文件数据空间连续的大粒度数据从磁盘预读到缓存。当后续访问其他小文件时,如果所需数据已存在于缓存,则避免了从磁盘再次读取的开销。采用“读则预读”的原则,预读的触发点固化在单一的页面中。优点是简单易行,缺点是过于死板,没有访问到该页面即便拥有良好的访问局部性也不会触发预读。
客户端读取文件的流程如图4所示。
图4 小文件数据大粒度预读流程
先检查文件数据是否在本地页面缓存中,如果是则读取页面缓存并返回。否则检查是否在预读页面缓存中命中,如果是则将该匿名页放入到页面缓冲区,并检查匿名页使用率是否触发异步预读条件,是则触发异步预读,否则返回。如果没有在预读页面缓存中命中,则触发同步预读,从磁盘上读出文件所在对象的数据,并更新页面缓存和预读缓存。
3 实验及应用
本节将统一存储系统ZXDFS采用文中技术优化前后进行测试对比。测试环境配置为:CPU英特尔E5606 2.13 GHz双路16核/内存8 GB*7/SSD英特尔s3500 220 GB/万兆网卡,操作系统Suse11sp3 V3.0.76。采用四种典型应用场景的现网数据,如表1所示。
表1 测试应用案例
对每种类型的应用场景,在相同的测试预置条件下,对比ZXDFS在优化前和优化后的性能指标,优化后是指采用文中所述技术优化后的ZXDFS系统。采用文件读写访问的时间延迟作为性能评价指标。为保证实验结果可靠,每种类型应用场景重复实验14次,去掉最小的2个值,去掉最大的2个值,对中间的10个值取平均。
性能测试结果对比如图5所示。
图5 性能测试结果对比
在测试的四种应用场景中,场景3性能提升的效果最佳,达到51%。场景1性能提升的效果最不明显,仅为3%。其他场景性能提升比例介于22%~30%之间,与各场景的平均性能提升水平26%较接近。场景1性能提升不明显,是由于该场景下文件比较大,并且主要是顺序读访问,文中优化方案难以发挥效果。场景3性能提升较大的原因是海量小文件访问,文件之间具有较强的局部性特征,优化效果得以充分发挥。
4 结束语
在面对海量小文件场景时,传统分布式文件系统存在着“元数据结构效率低,访问频率高且开销大”和“IO粒度小、磁盘吞吐量低”的难题。业界现有的小文件聚合方法不符合分布式系统的“通过计算检索”的设计理念。因此,文中提出了一种基于对象文件系统的小文件存储优化方法,核心设计思想概括为“特征聚合、计算定位、客户端预读”,解决了元数据“查表检索”的难题,提升了磁盘I/O效率和缓存命中率。在小文件的典型应用场景中,总体性能提升50%以上。但是,该方案在使用简单对象条带化策略时,可能有存储空间浪费、删除文件操作无法立即回收存储空间的局限。对于存在大量删除和修改操作的应用场景还需进一步优化。