丰富的线上&线下活动,深入探索云世界
做任务,得社区积分和周边
最真实的开发者用云体验
让每位学生受益于普惠算力
让创作激发创新
资深技术专家手把手带教
遇见技术追梦人
技术交流,直击现场
海量开发者使用工具、手册,免费下载
极速、全面、稳定、安全的开源镜像
开发手册、白皮书、案例集等实战精华
为开发者定制的Chrome浏览器插件
随着人工智能,IoT等技术的推广普及,智能监控,智能制造等新兴领域蓬勃发展,涌现出了越来越多的海量非结构化数据存储需求。举例来说,服务于公安机关的智能监控程序,不仅需要存储视频,而且还需要存储因使用人脸识别技术而产生的人脸截图等文件。这一类的小图像通常只有几个KiB到几十个KiB大小,但是数目巨大,动辄十亿甚至百亿规模。
这类业务,并不需要文件系统提供的复杂语义。相反,只需要存取(PUT/GET)的简单操作模式,使得这类业务非常适合使用对象存储。虽然对象存储相比文件存储更擅长处理数目巨大的非结构化数据,但对于十亿甚至百亿的规模,依然会对现有的系统(如软件定义存储中最常用的Ceph)造成严重的性能和可用性的冲击。本文将介绍如何通过引入adCache、PhxKV等自研组件,成功支持百亿级别的海量小对象存储。
基于Ceph方案处理海量小对象的问题
在上图的例子中,OP2在处理过程中,从OSD2发生离线故障,这时,由于从OSD2仍然被认为在线,导致OP2被挂起,直到monitor更新从OSD2的状态,OP2才可以被返回。当OSD2从离线状态重新上线时,会执行修复操作,同步自己和主OSD的状态。
为了修复复制组中离线的OSD,重新上线的OSD会比对自身和主OSD中的oplog,定位出离线期间发生修改的R-obj,并从主OSD中复制这些R-obj的副本。注意,RADOS中oplog的作用只为定位发生改变的R-obj,并不能通过replayoplog的方式进行数据恢复。所以,发生变化的R-obj都需要进行全量修复。即使bucketindexR-obj只是在从OSD2离线时插入了一条omap,修复bucketindexR-obj的过程中,依然需要复制整个bucketindexR-obj的omap列表,且修复过程也会阻塞业务I/O。
讲到此处,我们已经不难看出RGW处理海量小对象时,元数据处理带来的问题:1.OSD短暂离线,造成bucketindexR-obj无法访问时,会阻塞业务I/O。
使用PhxKV承载海量小对象
我们已经说明了RADOS的一致性协议和修复机制在海量小对象场景中带来的问题,接下来,我们将说明深信服企业级分布式存储EDS是如何通过自研的分布式KV——PhxKV来支撑海量小对象的元数据存储。我们首先介绍区分于RADOS一致性协议的RAFT协议,之后介绍我们如何以RAFT协议为基础,构建了PhxKV分布式KV系统。
RAFT一致性协议
RAFT协议有三个重要组成部分:Log,状态机,和一致性模块。一个RAFT组中有多个peer,其中一个为leader,其他为followers。
如上图所示,客户端将op发送至leader的一致性模块,之后leader请求所有的peer将该opappend至Log中,当大部分(例如,三个peer中的两个)append成功时,就可以认为op已经commit,这时,leader更新状态机,并返回请求。至于followers,leader会在后续的op中指示其将已经commit的oplog执行,更新状态机。
当leader发生故障,或者leader所在分片中的peer数少于大部分peer数导致leader
下台时,RAFT协议通过各peer间心跳的超时来触发选主流程,从而进行视图的变更。
RAFT协议的具体细节和故障处理方面比较复杂,我们就不在此赘述,有兴趣的读者可以移步去阅读论文InSearchofanUnderstandableConsensusAlgorithm。我们在此归纳RAFT协议的以下特点:
1.RAFT协议中,一个op成功的条件更容易被满足:当复制组中大部分节点返回成功时,一个op即被认为处理成功,这一特征,使得某些节点网络不稳定或者主机重启时,I/O能够不被阻塞;
4.承接第一点和第三点,peer修复的过程对上层透明,并不会阻塞业务I/O。
PhxKV架构
接下来,我们介绍如何基于RAFT协议构建PhxKV系统。
PhxKV的架构如上图所示,PhxKV提供和本地KV引擎类似的增删改查和批量操作的同步异步接口。PhxKV的key空间被一致性哈希映射到若干个region中,各region管理的key没有重合,每个region对应一个RAFT复制组,通过RAFT协议维护一致性。PhxKV采用RocksDB作为底层引擎,提供本地的KV接口。
PhxKV的主要组件和角色如下所述:
1.KVagent是PhxKV的服务端进程,管理存储在相同物理介质上的regions。出于对故障域的考虑,不同KVagent管理的物理空间处在不同的SSD上。相同region的不同副本存储在不同KVagent上,并通过RAFT协议进行同步。
2.Metadataserver管理元数据。通过KVagent定时的心跳上报收集KVagent和region的健康状况,及时通过心跳回复下达负载均衡和修复操作。出于容错考虑,metadataserver也有多个进程运行在不同主机上,并通过RAFT协议进行同步。
3.客户端执行I/O操作。客户端通过被动定时心跳和主动心跳从metadataserver拉取各Region的路由信息,之后,根据路由从对应的KVAgent中执行对应的增删改查操作。
PhxKV针对业务特征,还进行了一系列深度优化:
1.RocksDB为了提供高性能和高可靠性的写入操作,在写操作时,oplog先顺序写入WAL(write-aheadlog)进行持久化,数据部分则只是在内存中更新memtable,后续才以大块I/O的形式刷入底层SST文件。
事实上,RAFT协议中的Log可以作为状态机的WAL使用。我们通过RocksDB的disableWAL配置项关闭了状态机的WAL,这样,状态机的更新只需操作内存,减少了一半的落盘操作,大大降低了时延。不过作为代价,在掉电的情况下重启,状态机会发生数据丢失,我们首先需要利用RAFTLog来扮演WAL,将状态机恢复至重启前的状态。
2.PhxKV在进行修复和扩容时,需要将Region内的全部数据进行复制和迁移。逐条复制性能较差,我们使用RockDB提供的sst_file_writer和IngestExternalFiles功能,进行整Region的批量插入,降低了逐条插入的锁操作对性能的影响,并消除了一致性隐患。3.RocksDB的删除操作是异步操作,并不能快速回收空间。当某个KVagent容量告急,迁移出region时,可能很久之后才会见效,影响负载均衡效果。我们深度订制了RocksDB,通过改变数据组织形式,使得Region的删除操作可以同步快速回收空间。
PhxKV在EDS海量小对象中的角色
除去RADOS一致性和修复带来的问题,元数据规模过大,底层数据的碎片化也是RGW面对小对象合并时的棘手问题。EDS使用另一组件,分布式缓存(adCache)和PhxKV双剑合璧,一起打造了海量小对象的解决方案。AdCache将数据暂时缓存在SSD盘上,后续再批量回刷至RADOS,大幅降低了写请求的访问时延。
上图表示了小对象合并架构中的各组件关系。在Ceph的原始实现中,RGW将对象的数据和元数据都直接存储在RADOS中,其中元数据以键值的形式存储在R-obj的omap中。RGW使用librados和RADOS进行交互。
为了实现上述改造逻辑,我们劫持了RGW对数据部分和元数据部分的操作。其中,元数据部分被重定向至PhxKV中。此外,数据操作被重定向至adCache,adCache用异步合并回刷的原则,后续对存储的小对象被进一步聚合后,回刷至底层引擎RADOS中。同时,adCache会生成二级索引,使得可以定位到小对象在合并后存储的位置和偏移,在数据回刷至RADOS时,二级索引也会作为元数据被批量写入到PhxKV中。
结论
海量小对象场景,是对象存储的新机会,也为现有架构提出了新的挑战。深信服EDS基于现有的架构,取长补短,合理引用新组件解决关键核心问题,并能够让老组件RADOS继续发挥特长,为海量小对象的存储打开了新思路。
作者介绍:
Eddison,从事分布式KV数据库PhxKV的研发工作。香港中文大学博士,研究大数据存储系统的性能和可靠性,在USENIXFAST,USENIXATC等顶级会议发表多篇学术论文。从业以来,专注分布式一致性,KV引擎,纠删码等领域,2018年加入深信服科技。