你好,游客 登录
背景:
阅读新闻

Atlas: Baidu分布式存储系统

[日期:2017-12-04] 来源: 分布式和存储的那些事  作者: [字体: ]

  概述

  设计目标

  高效可靠地存储海量小文件。文件大小为几KB~几MB,文件总数据量上百PB,并且高速增长,主要服务于百度云盘;

  追求高存储效率,节省成本:服务器成本、电力成本、数据存储成本等。

  手段

  硬件定制

  定制专属存储服务器:去无用组件,基于ARM CPU的存储机,2U存放6个机器, 每个机器4核、4GB内存(受限于CPU)、4个3T硬盘,2U共72TB存储, 相比普通机架服务器,存储密度提升1倍。

  软件优化

  受限于内存容量(4GB),无法使用Haystack的做法对每个对象在内存中缓存其元数据,采用LSM tree管理对象元数据;

  使用纠删码而非复制技术提高数据可靠性;

  强一致性模型;

  本文章中我们主要讨论软件优化手段,对硬件不作过多描述。

  内存使用

  受限于存储机服务器内存,无法采用Haystack设计,将所有元数据缓存在内存中。做个计算,假如对象平均大小为128KB,单个服务器存储容量为16TB,每个对象元数据占用26B(key: 16B, size: 4B, offset:4B, hash table entry: 2B),总内存消耗达到了16TB/128KB * 26B=3.25GB。

  既然无法将所有的元数据缓存在内存中,那么只能另想他法:LSM-tree。关于LSM-tree是什么请自行google,另外其实现应该是采用了google出品的levelDB。在LSM-tree中KV有序存储在内存和磁盘上。其每1MB的数据才需要20B的元数据存储在内存,总的内存消耗大大降低,只有原来的10%,消耗内存约为320MB,这就在一个可接受范围之内。

  但这种做法虽然节约了内存,却带来元数据访问时的性能下降。以前只需要在内存hash table中查找元数据,现在查找过程可能需要读磁盘。

  架构

Atlas系统架构

  Atlas系统主要由以下几部分组成:

  Client:读写客户端,被链接至应用程序中;

  PIS Slice:负责数据的临时存储以及数据索引的管理;

  RBS System:由RBS Master和RBS PartServer组成,对数据作纠删码编码并存储。

  Client

  Client负责代理客户执行读取、写入和删除。应用程序key和value,客户端根据key计算hash决定将其写入哪个PIS Slice或者从哪个PIS Slice读取。在Atlas中,key是根据value生成的一个特征值(128b),如SHA-1。这个特点也就决定了Atlas系统要实现多副本的强一致性就必须要将所有的读写删除请求发送到主副本。

  PIS Slice

  客户端的写入请求会被发往某个特定PIS Slice(系统的PIS Slice数目固定,每个PIS Slice是个集群,可横向扩容)。每个PIS Slice内部结构如下图所示:

  其中:

  Patch模块:负责应用程序数据的存储,小对象会被合并存储在Patch中。每个Patch最大为64MB,超过64MB会开启新的Patch写入;

  Index模块:负责追踪对象在Patch中的位置信息,其记录格式为(key, offset, size)。如前文所述,Index信息没有已hash table方式缓存在内存中,而是使用LSM-tree方式存储。另外,个人猜测,每个Patch会对应一个Index文件;

  Replication模块:负责数据在多副本之间的复制,在PIS slice内,数据依然使用多副本方式保证可靠性。对多副本的数据一致性协议,论文中未做过多描述,只是提及读写删除均由Primary Unit处理(对于强一致性需求且key由客户端生成就必须要这么做)。

  除此之外,PIS Slice没有具体描述的还有一些元数据管理服务:如进行Slice的数据迁移等。

  RBS

  RBS负责将PIS的Block数据进行EC后存储,PIS每个64MB的Block被切割成8个数据块(8MB每个小块),然后生成4个校验块,然后将这12个小数据块存储于RBS系统中。

  RBS系统由元数据服务和数据服务组成,数据服务顾名思义即存储Block被切割并计算校验块后的数据分片,而元数据服务则用来追踪PIS中的Block在RBS中的存储位置信息。

  具体来说,PIS系统调用RBSClient向RBS中写入Block数据,RBSClient处理过程:

  向RBS元数据服务申请分配BlockID以及该Block存放的数据服务器地址;

  RBS元数据服务返回可写服务器列表以及分配的BlockID;

  RBSClient向服务器列表分别写入数据切片;

  写入成功后,RBSClient向RBS元数据服务提交写入结果;

  删除PIS上Block的三副本数据。

  通过上述步骤,一个Block数据便从PIS转移到RBS上,且三副本变成了8+4。

  核心模块

  PIS Slice

  PIS Slice内部主要由Patch和Index模块组成。其中Patch主要负责数据存储,而Index主要负责元数据(文件在Patch内的存储位置等信息)存储。这里的关键是元数据到底怎么存?

  猜测实现:

  当文件被追加写入Patch Block时,同时将该文件在Patch中的元数据信息写入Patch对应的index文件中,该index文件与patch文件一一对应,且该index文件很小(每个),完全可以缓存在内存中。Patch 为64MB,文件平均大小128KB,每个文件的元数据信息20B,总的元数据约20B* (64MB/128KB)=10KB,完全可以缓存在内存中。

  当Patch Block被写入至RBS系统中后,此时文件的元数据格式也有所变化,从原来的(key, offset, length) ==> (BlockID, offset, key) (BlockID由RBS Master服务生成)。

  此时,PIS Slice系统将内存中Patch Block的元数据变换后(加上RBS分配的BlockID)写入元数据存储模块Index中,且这些元数据也会通过replication模块写入从副本。Index其实就是LSM tree的一个实现,应该是百度基于LevelDB的修改版本。

  当然,上面只是我根据论文作的合理猜测,具体实现不一定,不过感觉八九不离十。

  关键问题

  数据删除

  由于对小文件数据采取了追加存储方式,因此,对于删除无法做到实时:所有的删除记录也会被追加到Patch文件。

  如果要删除的文件位于当前active patch中,则直接将该文件的元数据记录从Patch的in memory index中删除,此时接下来对该文件的读就变得不可见了,当然,数据还存在于patch中。这些数据会在接下来的垃圾回收过程中被回收掉。

  如果要删除的文件已经被写入了RBS系统中,那么此时从LSM index中删除该文件的index。接下来就无法再读到该数据了,同样,数据会在接下来的垃圾回收过程被清理。

  垃圾回收

  因为Atlas的数据删除属于延迟删除,删除只是将其元数据删除,被删除数据占据的空间依然被使用,垃圾回收就是要回收这部分无效空间。

  Atlas的垃圾回收以Block为单位,且在一个离线系统的辅助下进行。垃圾回收需要解决以下几个关键问题:

  如何判定Block是否需要回收;

  如何回收垃圾Block。

  Block回收条件判定?

  判定一个Block是否需要被回收其实一个基本方法就是计算该Block内被删除的数据量的比例,如果超过某个阈值(如30%?),就认为该Block需要被回收。

  此时问题就转化为在现有系统中如何判断Block内被删除文件数(据量)!这个好办,直接将PIS Slise所有的index数据全部拿过来,将每一条的(key,blockID,offset,len)变成(blockID, offset, len),这样就可以统计出每个Block有效数据量,然后从RBS Master中拿到所有的Block创建时间信息。

  这样,我们就可以判断:哪些Block有效数据量低于阈值且其存活时间已经超过一定范围,我们就回收这样的Block。

  垃圾Block回收

  Atlas回收垃圾Block过程:

  从垃圾Block中读出有效文件(未被删除),并将有效文件写入Atlas中;

  垃圾Block有效数据全部写入完成后,向RBS发起删除Block请求。

  RBS删除Block处理流程:

  RBS master删除Block信息,包括Block包含的数据分片;

 

  RBS data server定期和master交互信息,发现mds已经删除了自己存储的某些Block分片,于是将自己存储的Block。

收藏 推荐 打印 | 录入:Cstor | 阅读:
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数
点评:
       
评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款
热门评论