BIGO 海量小文件存储实践

BIGO面临每天数十亿小文件存储挑战,现有集中式元数据架构存在瓶颈。文章探讨了分布式存储的集中式和去中心化架构,选择了Ceph的去中心化架构,但指出其在海量小文件存储中存在问题,如元数据管理、扩容和存储效率。为解决这些问题,BIGO设计了一个基于双层存储池的小文件合并优化方案,包括高性能SSD副本池和大容量存储池,实现了高性能、高效存储和快速故障恢复。
摘要由CSDN通过智能技术生成

作为欢聚集团旗下品牌,BIGO 当前的业务涵盖直播,短视频和社交,目前已经服务于全球 150 个国家 4 亿用户。BIGO 的产品业务特性决定了其对海量小文件的存储需求,如内容审核截图,用户社交沟通过程中发送的小文件,用户的头像等。目前 BIGO 每天会新增约几十亿个小文件,占用约 30TB 存储空间。对于海量小文件存储,如何在保证高性能的同时降低存储的成本,成为 BIGO 存储团队必须解决的问题。

作为欢聚集团旗下品牌,BIGO 当前的业务涵盖直播,短视频和社交,目前已经服务于全球 150 个国家 4 亿用户。BIGO 的产品业务特性决定了其对海量小文件的存储需求,如内容审核截图,用户社交沟通过程中发送的小文件,用户的头像等。目前 BIGO 每天会新增约几十亿个小文件,占用约 30TB 存储空间。对于海量小文件存储,如何在保证高性能的同时降低存储的成本,成为 BIGO 存储团队必须解决的问题。

海量小文件存储的挑战

为了解决海量小文件的存储问题,必须采用分布式存储,目前分布式存储主要采用两种架构:集中式元数据管理架构和去中心化架构。

(1)集中式元数据架构:典型的集中式元数据架构的分布式存储有 GFS,HDFS,MooseFs 等。其采用的典型架构如下图 1 所示:在这里插入图片描述此架构主要包含 3 个部分:

1)客户端:主要用于提供访问分布式存储系统的接口;

2) 元数据服务器:主要用于存放分布式存储系统的命名空间和文件的一些元数据信息。

3)存储服务器: 主要负责存储文件的具体数据。

使用集中式的元数据管理的方式,其主要优点如下:

1) 元数据的操作性能高: 存储系统的命令空间和文件的元数据都存放在元数据服务器上,元数据操作如 list directory 和 create file 等元数据的操作性能会比较高;

2) 扩容时不需要数据迁移:元数据服务器上存放有所有文件的位置信息,在集群需要扩容增加新的节点时,这些位置信息不需要变动,因此集群在扩容时不需要进行数据迁移。

其主要缺点如下:1) 元数据节点是瓶颈:客户端在访问文件数据之前通常都需要到元数据节点上查询文件的位置信息,因此元数据节点不可避免地成为了整个系统的性能瓶颈。

2) 文件的数量受限:为了提高性能,元数据节点中的数据一般都会保存到内存中,而元数据节点的内存不是无限增长的。

基于以上缺点,集中式的元数据管理方式非常不适合于海量小文件的存储。

(2) 去中心化架构:为了解决集中式元数据架构的问题,去中心化架构的分布式存储产生,典型的去中心化分布式存储有 GlusterFs,Ceph 等。其采用的典型的架构如下图 2 所示:在这里插入图片描述此架构主要包含 3 个部分:

1) 客户端: 主要用于提供访问分布式存储系统的接口。

2) 存储服务器:主要负责存储文件的具体数据和元数据。

去中心化架构没有单独的元数据节点去保存文件的命名空间和元数据,元数据依然存储在存储节点上,文件的寻址一般采用 DHT(一致性 HASH)的方式计算。此架构一般会将多个存储节点进行逻辑分组,组内复制保证数据可靠性,因此会有可选的中心端服务器保存整个集群的存储节点以及分组信息。例如 Ceph 使用 Ceph monitor 保存整个集群的成员和状态信息(不保存文件信息),而 GlusterFs 选择将这些信息存放在所有的存储节点上。

使用去中心化的的方式,其主要优点如下:

1)无单点的性能瓶颈: 没有单独的元数据节点,客户端可以直接通过 Hash 的方式寻址文件,直接到存储节点上访问。

2) 文件的数量几乎不受限制: 没有单独的元数据节点,理论上文件的数量不受中心端节点容量的限制。

3) 读写性能更高: 读写请求不用到元数据节点上寻址而采用 Hash 计算的方式,理论上性能更高。从以上优点可以得出去中心化的架构还是比较适合海量小文件的存储。由于 GlusterFs 的存储节点采用 Linux 本地文件系统存储数据,没有对小文件的读写进行优化,而 Ceph 从 Jewel 版本开始引入 BlueStore 存储引擎,对海量小文件的读写有较大的优化,因此我们选择使用 Ceph 存储海量小文件。

Ceph 相对其他的分布式存储更适合海量小文件的存储,但还是有几个问题待解决:

1) Index 数据量太大:海量小文件会导致 bucket index 中的数据量增长过快,从而导致 bucket index 需要经常 resharding,而在 bucket index resharding 过程中会阻塞读写请求,对于大多数不需要 list bucket 的场景,此问题可以通过使用 indexless bucket 解决。对于必须 bucket index 的场景,增加了顺序分布的 bucket index 优化解决方案,此方案不在本文的讨论范围内,会在后面的文章中进行介绍。

2) 扩容时需要数据迁移:Ceph 在数据扩容的过程中,需要对文件的位置进行重新哈希,并会带来大量的数据迁移操作,数据迁移过程中会带来巨大的性能损耗。同时海量小文件的数据迁移会耗费较长的时间,如果在此过程中磁盘故障或机器故障,数据恢复的时间将不确定,会带来极大的数据安全风险。

3) 存储效率问题:Ceph 默认的最小分配单元为 64KB,而当前小文件的平均 size 为 15KB。为了提高存储效率,可以将最小分配单元调整为 4KB(读写性能会随之降低)。当使用纠删码的方式存储存储小文件,如(4+2)的纠删码,此时文件的最小分配单元变为 6 * 4KB = 24KB。为了提高存储效率而采用纠删码的方式存储小文件,反而更加浪费存储资源。

为了解决 Ceph 存储海量小文件的问题,需要设计一个满足以下目标的系统:

1) 高性能:分布式存储系统需要承载终端用户的读写需求,低延时地满足用户对数据的存取需求,是任何分布式存储系统的重要目标。

2) 扩容时避免大量的数据迁移: 避免大量的数据迁移操作增加对存储系统的负载,从而影响存储系统对终端用户的服务质量,也是该系统设计的重要目标。

3) 加快故障恢复速度: 机器故障或磁盘故障会导致数据迁移,海量小文件导致故障恢复缓慢,故障恢复的时间越长,在此期间其他机器或磁盘发生故障的概率越大,数据丢失的风险越大,因此加快故障的恢复速度也是系统设计的目标之一。

4) 提升存储效率: 海量的小文件会占用大量的存储资源,同时大量的文件经过一段时间后就会变成冷数据,如何提升存储效率降低存储成本也是系统设计的目标之一。

系统设计

目前业界解决海量小文件存储主要有以下的解决几种优化方式:

1) 硬件优化: 海量小文件的读写请求,瓶颈一般在机械硬盘上。硬件优化主要是采用支持随机读写的 SSD 硬盘代替机械硬盘,可以显著提高海量小文件的读写性能。但是考虑到成本因素,在数据量很大的情况下 SSD 硬盘一般只会在系统做作为 Cache 存在。

2) 文件元数据管理优化:分布式存储系统中文件的元数据包含文件的位置信息,文件的 size,创建时间等。在读写小文件之前,都需要先得到文件的元数据信息,例如需要得到文件的位置信息才能到对应的存储节点上读写文件数据,只有拿到文件的 size 才能知道需要读取数据的长度。为了减小访问元数据的开销,应该尽量减少元数据的数量,元数据的数量越少,cache 命中率越高,性能越高。

3) 小文件合并成大文件: 通过将大量的小文件合并成一个大文件,可以显著减少文件的数量,也就减少了元数据的数量,元数据的查询会更快。对于大文件机械硬盘可以做到顺序读写,可以显著降低硬盘的负载。

本系统结合以上的方式设计了一种基于双层存储池的小文件合并优化方案解决 Ceph 海量小文件存储的问题,其系统设计如下图 3 所示:在这里插入图片描述系统分为两级存储池,分别是高性能 SSD 副本存储池和大容量(副本/EC)存储池。可以配置不同的存储策略,将不同 bucket 或不同 size 的文件写到不同的存储池上。对于海量小文件优先写到高性能存储池中,这样可以保证小文件读写的高性能。

然后通过配置策略,开启合并功能将高性能存储池中的小文件合并成大文件存储到大容量存储池中。当大容量存储池中的空闲空间不足时,增加新的存储节点创建新的大容量存储池,而不是对已有的存储池进行扩容,这样可以避免大量的数据迁移操作对终端用户的读写请求产生影响。

对于大容量存储池,可以通过 EC 方式存储,提升已合并的文件的存储效率。由于存储的是大文件,最小分配单元可以调整的比较大,如:128KB,这样可以减小 BlueStore 中的元数据的数量,提升性能。

关键问题

对于以上的系统设计,在具体实现上主要包含以下几个关键问题。

3.1 小文件的合并方式将大文件看做一个 Volume,每个小文件占其中的一个部分空间,如下图 4 所示:在这里插入图片描述

将小文件顺序的追加到 Volume 中,每个小文件在 Volume 中分成 3 个部分:

1) Header: 保存文件的一些元数据信息,如文件名,文件 size,文件的校验信息,在 Volume 中的 offset。

2) Data: 小文件的实际数据内容。

3) Footer: 保存固定的 magic,做校验用。

3.2 数据从高性能存储池迁移到大容量存储池将数据从高性能存储池迁移到大容量存储的具体方式,如下图 5 所示:在这里插入图片描述

存储网关的操作日志会记录当前存储网关上的操作,操作日志按照 bucket 和时间存放,迁移工具可以按照不同的 bucket 策略(如延迟迁移的时间间隔)去读取当前 bucket 的操作日志文件。具体的迁移流程可分成 4 个步骤:

1) 读取操作日志: 根据 bucket 的迁移策略,读取操作日志文件并解析每个操作,得到文件的名称和一些操作信息。为了支持并行的迁移,可以将文件名通过 hash 方式放到多个队列中。

2) 读取文件内容: 从队列中的得到待处理的文件名,从高性能存储池中读取文件的数据。

3) 小文件数据写到大容量存储池: 从大容量存储池中申请一个 Volume,将当前的小文件追加到 Volume 中,按照 Header,Data,Footer 的顺序迁移文件。

4) 删除高性能存储池中的文件数据: 删除高性能存储池中的文件数据,只是将数据清空,保留文件的元数据信息,并在元数据中添加当前小文件在 Volume 中的位置信息,方便后面读取数据时的检索。

3.3 文件读取在文件的数据被迁移到大容量存储池后,存储网关读取数据的流程也会随之变化,如下图 6 所示:在这里插入图片描述

此时文件的数据内容存储在大容量存储池中,文件的元数据和文件内容的位置信息存放在高性能存储池中,因此在读取数据内容之前,存储网关要先到高性能存储池中读取文件的位置信息。从读取流程上看,相对于直接在大容量存储池中存储小文件增加了一次网络往返的开销,但是该方案有以下几个优点:

1) 大量的热数据已经在高性能存储池中完成了读取操作,迁移到大容量存储中的一般是冷数据,读取的请求会少很多。

2) 文件元数据的读取还是在高性能存储池中进行的,性能相对直接在大容量存储池中好很多。

3) 该方案大容量存储池 BlueStore 的分配单元较大,BlueStore 的元数 3.4 文件的删除和空间回收文件的删除需要删除文件的数据内容和文件的元数据两个部分,文件的元数据在高性能存储池中存放可以直接删除,而文件的数据内容只是大容量存储池中 Volume 的一部分,不能直接删除回收存储空间,因此将文件的删除和空间回收分开进行。

在服务终端用户的删除请求时,在 Volume 中找到对应的文件 Header,并写入一个删除标记,表示文件已经删除不能访问,并修改当前 Volume 的有效 size 信息(实际存在的文件的 size 总和),后续作为开始空间回收的判断依据。如下图 7 所示:在这里插入图片描述

假设红色的 Header 表示当前的文件已经被标记为删除。根据空间回收策略,如有效空间相对 Volume 存储空间的占比小于 50%,表明已经删除的空间占比超过 50%,此时需要对 Volume 进行 Compaction 操作,方法如下:

1) 扫描整个 Volume 里面的每个文件,如果已经删除直接跳过这个文件。

2) 如果是没有被删除的文件,将文件的内容追加到新的 Volume 中,并修改高性能存储池中文件的元数据,修改位置信息重新指向新 Volume 中的位置。

3) 整个 Volume 扫描完成,有效文件迁移完毕后,删除当前的 Volume 大文件。除了文件删除操作,文件修改操作也需要回收老的数据内容占用的空间,采用类似的方法。在处理修改的操作日志时,将旧数据内容的 Header 标记为删除,在后续 Compaction 操作时回收这部分数据空间。

评价

为了验证此设计方案的优化效果,在相同的网络环境上搭建了两套分布式存储系统:

优化前系统:

1) 3 台服务器,每台部署 5 个机械硬盘存储节点,最小分配单元 4KB。

2) 在 15 个存储节点上创建一个大容量 3 副本存储池。

优化后系统:1) 3 台服务器,每台部署 5 个机械硬盘存储节点和一个 SATA SSD 存储节点,最小分配单元 64KB。

2) 在 15 个存储节点上创建一个大容量 3 副本存储池,在 3 个 SATA SSD 存储节点上创建一个高性能 3 副本存储池。

3) 设置高性能存储池中的小文件在写入 2 小时后,自动迁移到大容量存储池中,大容量存储池中的 volume size 默认为 4MB。

可以从以下几个方面评价该设计方案的优化效果:

4.1 热数据的读写性能在海量小文件数据还没有迁移到大容量存储池之前的性能比较。

(1) 写入性能:如下图 8 所示,分别在多种不同并发情况下写入 1000 万 20KB 文件的性能测试结果:在这里插入图片描述由于高性能存储池采用的存储硬件是 SATA SSD,虽然高性能存储池只有 3 个存储节点,大容量存储池有 15 个存储节点,优化后系统的写入 QPS 依然达到优化前的 3 倍。

(2) 读取性能:如下图 9 所示,分别在多种不同并发情况下读取 1000 万 20KB 文件的性能测试结果:在这里插入图片描述可以看到优化后系统的读取 QPS 相对优化前提高 20%~30%,没有达到写入的优化效果主要是存储节点缓存的作用。

4.2 冷数据的读取性能数据在高性能存储池中写入后,按照策略数据变冷会迁移到大容量存储池中,优化前和优化后(小文件合并之后)的读取性能对比结果如下图 10 所示:在这里插入图片描述由于小文件合并之后,文件的读取需要先到高性能存储池中读取元数据,然后到大容量存储池中读取文件的数据,实际上多经过了一次网络 RTT,因此会导致一定的读取性能下降,从结果看读取 QPS 下降了约 12%。后续系统会采用性能更好的 NVME SSD 搭建高性能存储池进行测试。

4.3 存储效率提升在优化后的系统中,在小文件合并前与合并后,存储资源的使用情况如下图 11 所示:在这里插入图片描述合并前最小存储单元是 64KB,因此一个 20KB 的文件也需要占用 64KB 的存储空间,而且是 3 副本,因此不算元数据需要的存储空间是:64KB * 3 * 10000000 = 1831GB。

合并之后的 Volume size 是 4MB,1 个 20KB 的文件,只需要占据 20KB 的数据存储空间加上少量元数据的存储空间,因此不算元数据需要的存储空间是:20KB * 3 * 10000000 = 572GB。

因此合并之后的存储效率是合并之前存储效率的 3 倍多。

4.4 故障恢复速度同样的 1000 万文件,下线 1 个存储节点,此时会导致数据迁移恢复数据,完全采用默认的配置,优化前和优化后耗费的数据恢复时间如下图 12 所示:在这里插入图片描述由于优化后大容量存储池中只存放大文件,因此其恢复速度比较快,从结果看优化后的故障恢复速度是优化前的 16 倍。

结论

本文分析了使用 Ceph 存储海量小文件的挑战和一些问题,并从硬件优化,元数据管理优化和小文件合并优化几个层面考虑并设计实现了一套基于双层存储池的小文件合并优化分案,通过比较可以发现新方案在读写性能,存储效率以及故障恢复速度上都有较大的提升。

阅读全文: http://gitbook.cn/gitchat/activity/5f1795c51c21f530a19e194e

您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。

FtooAtPSkEJwnW-9xkCLqSTRpBKX

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值