近年来,58集团旗下各种业务发展迅猛,众多业务场景产生了大量的文档,音频,视频等非结构化数据,尤其是随着移动互联网的发展,手机短视频作为更加直观的展示手段,深受用户青睐,像安居客房源视频,转转二手商品视频,赶集网视频简历等。大量的文件如何存储的问题应运而生,传统的存储服务器价格昂贵,公有云存储定制化不足,后期运维沟通成本较高,在这样的背景下,WOS横空出世。WOS是58集团基础架构部自研的对象存储系统,提供了高扩展性,低成本,安全可靠,强一致的分布式存储服务。

WOS的成长是伴随着业务的接入和增长而逐步发展的过程,本文将从WOS的基础架构以及几个核心功能设计方案的角度来和大家进行分享。

一. 站在巨人的肩膀上——WOS整体架构方案

方案设计之初,我们重点思考的一个问题就是我们到底需要一个什么样的存储系统,根据58业务需求的特点,我们概括为以下几点:

  1. 适合存储KB级别的小文件,同样适合存储短视频等几十MB级别的文件;

  2. 写入很多,读取相对多,很少修改,很少删除

  3. 安全可靠,易扩展,易维护;

WOS的架构设计参考了facebook的经典论文《Finding a needle in Haystack:Facebook’s photo storage》,论文提供了海量图片存储的解决方案,它的基本思路是将海量的小文件合并为大文件进行存储,而文件的元数据及分布信息单独进行存储。在此基础上,WOS增加了短视频类文件存储的支持。WOS整体架构如下:

Proxy模块

Proxy是WOS最前端的模块,对外接收http请求,无状态,易于横向扩展。每个集群有自己的域名,域名解析系统将请求负载均衡的打到不同的proxy进行处理。 Proxy解析出文件元信息后交给directory模块进行存储,并取回文件数据的存储位置,之后将文件数据交给相应的store模块进行存储。WOS对外提供不同接口以处理不同大小的文件:

  1. 小于4M的文件:WOS提供upload接口,对文件整体进行存储,将数据合并到大文件中;

  2. 大于4M的文件:WOS采用分片上传的策略,提供3个接口进行处理。init接口对文件进行初始化,将元信息进行储存;sliceupload接口上传每个分片,并将每个分片合并到大文件中进行存储;commit接口标识文件上传结束,提交确认。

Store模块

Store模块是WOS的实际存储模块,整体的设计思路参照了haystack论文,不同的是,WOS的store中负责存储的needle可能是一个完整的小文件也可能是一个大文件的一个分片,以needle为单位合并到磁盘上的一个大文件中,这个大文件我们称之为volume。每个store管理多个不同的volume 。WOS将store用group进行分组,每个group下包含多个互为备份的store,实际部署时通常为3备份,每个store部署不同机器的一个独立的磁盘空间,便于管理和维护,具体逻辑关系如下图所示:

Directory模块

Directory是wos的中枢模块,负责文件元信息的存储以及数据的智能调度功能。Directory同样无状态,易于横向扩展,文件元信息存储在58自研的分布式kv存储系统wtable中。写请求到来时,Directory为该请求通过调度算法分配数据将要存入的store和volume,同时,将调度信息以及文件元信息存入wtable;读请求到来时,directory根据文件查找数据存入的store及volume并交给proxy进行后续处理。

调度算法的设计是分布式存储系统的关键,它涉及到数据的分布策略,后期运维成本等。在设计WOS的调度算法时,我们调研业界流行的分布式存储系统的调度算法, 一致性hash算法是常用的数据分布算法,这种技术对比传统hash算法,虽然可以减少设备增减时移动数据的量,但还是需要进行相应的数据移动;而且这些算法通常不能将机器的当前状况作为调度参考因素。我们希望能够将机器的磁盘容量,写入延时等信息作为算法的参考,同时在增减机器时不要引起原有数据的迁移,在这种情况下,我们重新设计了WOS的调度算法,以volume为单位进行分配,根据store以及volume的实时状态计算出每个volume的权重,根据权重大小进行调度,具体的调度算法我们参考了nginx的平滑加权轮询算法实现,防止新加入的Volume被立刻调度到大量请求而导致负载瞬间增大。

Detector模块

Detector模块用于探测集群内所有store以及store下所有volume的状态,这些状态包括store是否可以读写,volume是否可读写, store下所有volume的剩余容量,写入次数以及写延时等信息,detector将这些信息写入到etcd的相关目录,是directory模块调度算法的数据来源。

二. 让数据飞——WOS”秒传”功能设计

由于某些业务的应用场景,会存在以下情况:

  1. 上传的文件在内容上有很多都是相同的;

  2. 文件上传过程由于网络等原因中断后需要重新上传。

针对以上情况,我们设计了WOS”秒传”功能,给客户端提供的sdk中增加precheck接口,同时在服务端增加引用计数功能,具体方案如下:

客户端实现

Precheck接口在提供给客户的sdk中实现,封装在上传接口中,对用户透明,对于不同文件,有如下具体实现:

  1. 小于4M的文件: 先调用precheck接口,上传该文件的sha1值,服务端查看该sha1值是否已存在,如果存在,则返回客户端上传成功,如果不存在,则客户端调用upload接口,进行上传。

  2. 大于4M的文件: 先调用precheck接口,上传该文件的所有分片的sha1值,服务端查看所有的sha1值是否存在,如果全部存在,则返回上传成功,否则,返回没有存在的sha1值,客户端对于没有存在的分片继续调用sliceupload接口上传,最后调用commit结束上传。

服务端实现

服务端增加了引用计数功能,通过维护以下三个wtable表实现:

  1. 上传文件或分片的id与其sha1值的对应表;

  2. sha1值被引用次数的表;

  3. sha1值对应的分片所属文件信息及偏移信息的对应表。

写请求时,服务端根据sha1值查找b表,如果sha1的引用计数不为0,则增加引用计数,同时设置c表,并设置文件元信息,如果为0,则同时设置a,b,c三个表,b的引用次数为1。删除请求时,服务端根据要删除的分片信息,查找a表,找到对应的sha1,然后查找b表并减少引用计数,同时删除c表中的对应信息,此时如果b表该sha1值的引用计数为0,则对该数据在volume中进行删除。实际设计和开发过程中,为了防止并发操作引起数据不一致,我们做了大量措施,这里不再一一赘述。

通过以上设计可以看出,小文件如果内容相同或者大文件存在相同内容的分片,我们实际上传和存储都只有了一次,从而实现了相同内容的”秒传”功能;同时,在大文件上传中断的情况下,再次调用上传接口,通过预检,会从中断的分片实际上传,从而实现了”断点续传”,而这一切对用户是完全透明的。

三. 机器就是金钱——WOS纠删码方案设计

随着接入业务数量的逐步增加,存储的数据量迅猛增长,之前的三备份模式占用的机器资源数量不断增加,存储成本不断增长。这种情况下,我们开始调研节约存储成本的方法。首先,我们调研的是压缩存储,由于大量的视频文件压缩后释放的空间不足1%,我们放弃了这个方向。纠删码方案可以很好的满足我们的需求,但是如何在现有架构基础上很好的支持纠删码,成为摆在眼前的一大难题。最后,我们给出了以下纠删码解决方案:

纠删码存储结构

我们保持原有的存储结构,还是用group来管理store,三备份下一个group管理3个store,每个store中存放一份needle的副本,纠删码情况下,我们以4+2编码为例,一个group下管理6个store,同时这6个store管理的volume标识为EC类型,每个store存放原needle的一个分片和2个新产生的编码分片,6个分片分别放到每个store的同样编号的volume中,在分片的头部字段标识身份。这样,我们将存储空间从3倍缩减到1.5倍,整体存储结构如下图所示:

纠删码编码时机

编码时机的选择有事中编码和事后编码,tfs的纠删码方案采用的是事后编码,ceph等采用的都是事中编码,我们针对WOS的实际情况,对两种编码方案进行了对比:

事后编码:数据先写3备份,当某个Volume写完之后,通过编码模块读取数原volume的数据,解析needle并进行编码,然后写入到纠删码group中,编码之后删除原三备份volume。这种方案不影响数据在线读写效率,但是当集群数据量增长很快时,对编码效率要求很高,编码模块读取原数据和写入新数据会占用大量带宽资源。

事中编码:needle写入时进行编码,编码后的数据并发写入store。这种情况下不需要编码模块进行事后编码引起额外的网络传输,而且流程相对简单,但会影响写入性能,我们通过对使用的编码库进行测试发现,编码耗时所占请求总耗时的比例很低。

通过方案对比和测试,我们最终采用了事中编码方案。

纠删码具体实现

事中编码方案很好地解决了新建集群的存储成本问题,但是由于历史存量原因,已有集群所占空间仍然十分巨大,我们需要将这部分数据逐步转换为纠删码模式存储,而且已有集群的三副本模式在升级为纠删码模式的过程中需要兼容老数据的读取。这种情况下,我们在原有代码的基础上增加了纠删码的支持,同时增加了编码模块对存量数据进行编码后存储,以最小的改动量实现了一套代码既可以支持新的纠删码集群又可以实现老的三备份集群向纠删码集群平滑过渡,具体实现如下图所示:

  1. proxy模块:增加了纠删码类型volume读写的接口,从directory获取数据读写的volume的同时,获取该volume的类型,根据类型调用不同的读写接口和store进行交互。

  2. directory模块:创建volume时增加volume的类型字段,和volume一同返回给proxy,作为proxy调用不同数据读写接口的依据。同时对调度算法进行了升级,可指定将数据调度到三备份还是纠删码的volume中,还可以配置两者分配比例,控制调度到两种类型volume存储数据的量。

  3. store模块:增加了和encodeserver模块交互的接口,以needle为单位将数据传输到edcodeserver进行编码。同时,增加了数据恢复功能的支持。

  4. encodeserver模块:编码模块,对存量数据进行纠删编码后存储。通过和store交互获取需要编码的needle,编码后通过调度算法存入纠删码类型的volume,同时修改wtable中needle所属的volume信息并删除原有的三备份volume。

总结** **

WOS是58集团基础架构部在非结构化数据存储上的探索和实践。伴随着业务的不断接入和持续增长,WOS也将会在挑战中不断成长和完善,更好的为业务增长提供强有力的后盾,为提升用户体验做出自己的贡献。WOS的技术点还有很多,这里我们选取了一部分和大家进行了分享,欢迎对分布式存储技术感兴趣的同学进一步交流。

Source

0 回复
需要 登录 后方可回复, 如果你还没有账号你可以 注册 一个帐号。