人物|钟昌寿:58同城分布式存储系统架构设计和优化实践
收藏

11月6日,由腾讯云主办的腾讯首届Techo开发者大会在北京举行,这是一个面向全球云计算领域开发者和技术爱好者的年度盛会。58同城存储架构师钟昌寿老师受邀出席大会,并带来精彩演讲《58同城分布式存储系统架构设计和优化实践》。

钟昌寿老师对58分布式KV存储从“架构设计、性能与优化、强一致性设计”三个方面进行了系统阐述。

本文根据此演讲实录整理而成,图文详实,欢迎阅读分享。


背景
经过几年的努力,58同城已经自研了4款分布式存储产品。分别是Key-Value、Key-List、对象存储、共享文件系统。其中分布式Key-Value存储WTable是最早开发的,在集团内使用最为广泛,甚至对象存储与共享文件系统都是用WTable来存储Meta信息。WTable的开发大致上可以分成三个阶段,2015年发布第一版,满足了业务的核心需求。第二阶段重点优化了读写性能与请求延迟,提高运维自动化与速度。第三阶段从2019年开始,分步引入NewSQL的相关技术,为业务提供更人性化与更高效的使用体验。


WTable第一阶段

在WTable之前58存储主要使用MySQL+Cache。当数据量太大时需要做分库分表,若数据增量又很大就需要定期做扩容,非常耗时费力。因此对WTable的核心需求总结为:扩容、可用性、高性能、扩展能力。为了简化架构,在设计上引入了两个外部组件:ETCD用作配置中心与多副本选主,Rocksdb作为数据节点的存储引擎。通过代理服务层对请求进行路由,存储节点以Group为单位,每个Group中通常是一主两备,主备之前通过异步实时同步来保持数据最终一致。
WTable将数据分成2048个Slot,Key哈希之后对2048取模,作为该Key所属的Slot。Proxy本地缓存着每个Slot所属的Group以及每个Group的存储节点列表。当请求到来时根据Slot将请求转发到后端的存储节点。当存储空间不够或者写性能不足时可以通过增加Group方式来扩展。
为了应对各种异常,WTable使用了多级容灾策略。首先客户端会定期从NameCenter拉取Proxy列表以感知Proxy的列表的更新。取到列表之后每2秒会检测Proxy是否正常,若多次检测异常则会将其加入黑名单。Proxy也会检测后端存储节点。如果Master角色异常则会通过ETCD自动选举新的Master,若是Slave异常自动被Proxy屏蔽。
为了尽可能提高KV使用的灵活性,WTable还提供了丰富的操作接口,如,乐观锁,自动过期等,而且对其中大多数接口都提供了批量操作支持。从2015年上线至今,线上几十个集群,存储着有百T的数据量,日请求量达到三千亿,为一千多个业务提供服务。

WTable第二阶段

第二阶段主要通过研究Rocksdb来获取性能的提升以及运维速度的提高。首先将Rocksdb版本从3.11升级到5.15,并且对Rocksdb参数进行优化,读写性能与延迟都有很大的提高。当写入量大时,底层Compaction会阶段性地产生IO峰值。在这些IO峰值处,读写延迟会变高。经过调研,Rocksdb有成熟的Comapction限速方案。通过设置AutoTune以及磁盘IO上限能够自适应Compaction与写入量的关系。

运维主要涉及换机器时的加备机,磁盘空间不够时的扩容操作。原先这两个操作速度较慢,在应对一些突发情况时比较捉急。加备机操作原先的方法是在主机上创建迭代器,把KV遍历出来依次写到新备机。瓶颈出现在KV的遍历上,因为这个操作非常耗IO,快了会影响线上服务,因此必须限速。另外由于迭代器没有及时释放可能会出现为了加备机导致主机磁盘空间告警的悲剧。经过调研,其实Rocksdb提供了Checkpoint这种非常友好的数据同步方式。得益于LSM存储结构中的SST写入后不会被修改,因此Checkpoint只需要为当前版本所有SST文件创建硬链即可,整体耗时只需要几百毫秒。创建完成之后,发送SST文件到新备机,几乎不消耗IO,瓶颈只剩下网络带宽了,对于万兆网卡的机器,速度可以轻松达到三五百兆。

集群的扩容涉及到数据的迁移,WTable的扩容以Slot为单位进行。当增加一个Group之后,通过Manager服务会计算好每个Group需要承载的Slot个数,然后制定迁移计划,按照Slot进行迁移。每完成一个Slot迁移相应更新ETCD中的路由配置信息。但是这种方式有一个瓶颈就是在迁移的过程中,前面迁移的Slot已经提供线上服务。新的Slot迁移会有大量数据写入,会影响线上服务。例如:总共有8个Slot需要迁移,当迁移第5个Slot时前面四个Slot已经提供线上服务。

为了避免这种影响,不再以Slot为单位进行数据迁移,而是将所有待迁移的Slot作为一个整体进行。接上例:先对这8个Slot做全量同步,然后对这8个Slot做增量同步,最后修改ETCD中的路由信息。数据扩容完成之后需要从原Group中删除,以释放空间。原删除是遍历出Key,然后依次删除,非常消耗IO,而且速度很慢。现在优化成先通过DeleteFileInRange接口把完全处于待删除Key范围的SST文件直接删除,然后通过CompactRange+CompactFilter组合把剩余的数据删除。整体耗时非常短,IO消耗非常低,达到及时释放存储空间的目的。



WTable第三阶段

第三阶段,目的是引入NewSQL相关技术提高WTable的使用效率。第一步就是提供强一致性版本。为了实现强一致,需要使用一致性协议。最初计划是使用ETCD中的Raft实现,将其修改成MultiRaft。后来发现有一个DragonBoat开源库,其有非常高的测试覆盖率以及读写性能。经过实际测试,在有足够并发时其整体吞吐量相对于异步复制高,但是每个请求延迟也相对较高,因为需要走一遍Raft协议流程。

在强一致性版本中尽量保持了原先的设计,依然保持2048个Slot,每个Slot的数据通过一个RaftGroup来实现同步。而这个Slot多副本的分布则在整个集群内自动均衡。原先的固定主备关系已经不存在,Leader的选举也不再需要ETCD,因为每个RaftGroup自动会选举Leader。在Proxy中依然缓存着路由信息,并通过ETCD来实时更新。

扩容时只需要增加机器即可,WTable会自动计算每台机器应该承载的Slot个数,并做数据迁移。扩容过程首先将节点以Observer方式加入到RaftGroup中开始做数据同步。当数据同步完成之后将该节点提升为Follower,并更新ETCD中的路由信息,接着去所有Proxy确认信息已经更新。然后把一个老节点从ETCD的路由信息中移除,再去Proxy确认。最后才将该节点真正从RaftGroup中移除。通过这两次确认可以保证路由信息的准确。

目前强一致性版本的WTable已经开发完成,后面计划开发分布式事务。对于KV类的存储,分布式事务的支持能够很好地提高业务数据的逻辑一致性。最后在WTable基础上支持常用的SQL语法,这些都已完成,实际上可以算是一个简化版的NewSQL了。


总结

每个系统在设计阶段会有很多变量,需要充分考虑业务核心需求与痛点以及当前可用资源后做出权衡,最终得到一个业务可接受、资源消耗可控的设计。WTable的迭代过程,就是平衡各方面因素的结果。第一阶段重点解决容灾、高性能等核心需求,但是在集群运维方面有很多不足,第二阶段重点解决了这些问题,第三阶段考虑如何提供更好的用户体验。一个好的系统总是慢慢进化而来,相信WTable未来会更好用,更高效。

谢大家!

钟昌寿



现任58同城架构师,TEG存储服务部负责人


负责58同城分布式KV存储WTable、分布式KList存储WList、对象存储WOS等分布式存储系统的架构设计及性能优化,对高并发、高性能、高可用等系统的设计及调优有着多年丰富的经验





钟昌寿老师邀请你参与在线互动,有什么想对钟老师说的赶紧下方留言吧~

    公众号
    关注公众号订阅更多技术干货!