您现在的位置是:首页 > 文章详情

开源一个千万级多组Raft库 - Dragonboat

日期:2019-01-15点击:520

向大家介绍Dragonboat,一个开源的Go实现的多组Raft库,项目已Apache2协议下开源。欢迎大家试用,也请大家点star鼓励https://github.com/lni/dragonboat

通俗的讲,这是一个分布式共识协议库,应用可以用它把数据分布存储于多台机器上,只要过半数的机器在线,数据与服务便可在线。这避免了因个别机器当机或网络故障而造成数据、服务不可用,提高系统可用性。它提供称为Linearizability的强一致特性:多个副本的数据在外部看来更像使用单一副本,不会有仅提供最终一致性的系统常见且难缠的读到旧版数据的问题。

基于Raft协议的共识库已经应用于很多互联网后台系统。接触了很多用户以后,普遍反馈的当前应用障碍是缺乏一个可靠、高性能、且对共识协议本身接近全透明的开箱即用的通用实现。

优势

Dragonboat已经较好的解决所有上述应用障碍:

  • 测试最完备的开源Raft库之一,所有的实现代码、测试工具、测试结果均已开源。
  • 吞吐性能最好的开源Raft库,千万级每秒实现,平均单核即达每秒40万次以上写吞吐。
  • 功能最完备的开源Raft库,不做特殊应用假设限制,安全可靠前提下最大程度确保通用性。

同时,Dragonboat的Go实现经过大量具体性能优化打磨,在当前高性能Go系统在行业内需求持续剧增的背景下,为准备入坑的同学踩坑带路提供参考。

 

功能与使用

Dragonboat实现了Raft论文中提及的几乎所有功能,是当前最完备的Raft协议的Go实现:

  • 选主与复制
  • 快照
  • 基于ReadIndex协议的高性能强一致读
  • 主节点转移
  • 无投票权节点
  • 节点静默
  • Quorum自查
  • 对应用透明的幂等更新支持
  • 全异步的执行与快照操作

Dragonboat的使用十分方便。与etcd Raft库不同,Dragonboat无需用户参与任何Raft协议状态有关的操作,最大程度降低Raft的使用成本与人为错误概率。用户首先实现一个IStateMachine接口用以描述更新与查询请求的执行方法,该接口仅四个方法必须实现,分别用于更新、查询StateMachine,以及对StateMachine创建与恢复快照。实际项目经验发现,一个简单的内存上的Key-Value数据库,它的StateMachine几分钟就能作出一个原型。

有了上述IStateMachine实例,便可根据应用需求使用Dragonboat的应用API接口提出各类请求,系统将严格通过Raft协议规定的要求处理各用户请求,并最终提交至用户的IStateMachine实例完成状态更新与查询的执行。

Dragonboat自带的详细中文例程可以在十几分钟那让用户了解整个使用流程,近距离观察共识协议给系统所带来的fault-tolerance容错特性,并实际操作体验如发起Proposal、强一致读、Raft组成员变更、节点重启等系统功能。

设计与实现概述

Dragonboat的核心组件是分布在网络各服务器上的NodeHost,通常每台服务器一个NodeHost实例,用以分配使用计算、存储与通讯资源,并管理运行于该服务器上的来自各不同Raft组的成员节点。

NodeHost同时提供一个facade interface,用以提供所支持的各服务,用户可使用其API完成各支持的功能,如发起读写或成员变更请求,启动或停止某成员节点,请求主节点转移或查询当前组成员等等。请使用上一段提供的例程的链接,具体了解NodeHost的使用。

各Raft成员节点内含下列实例:

  • Raft协议状态
  • Raft组成员
  • 应用IStateMachine
  • 用于支持幂等更新的Session状态

其中应用IStateMachine由用户提供实现,其余皆为系统实现并对用户完全透明。

为了原生支持大量Raft组,各类batching与pipelining优化手段被仔细的落实到每个细节,如驱动各Raft组更新执行的执行引擎就是最好例子。以写(propose)为例,如下图所示,各Raft组被分配到不同的执行shard上,以提供parallelism,每个shard又是一个多级流水线,不同处理阶段不同性质(IO密集、内存访问密集等)的处理在流水线不同级间并发完成,充分利用concurrency优势将所有消息传递、执行更新等操作异步化。

Dragonboat的Log存储组件称为LogDB,默认使用RocksDB,但可方便替换为其它Key-Value store方案。默认的RocksDB适配仅350行Go代码。NodeHost间消息传输由称为Raft RPC的组件完成,系统提供了默认的TCP与gRPC两个实现,它们均支持Mutual TLS,同时也可方便地适配其它传输方案。

 

测试与正确性检查

Dragonboat经过及其严格的测试。相对于用宣传式口号称赞软件如何可靠,下列具体数字和事实相信更具有说服力:

  • 每晚千万次规模,历时一年多共百亿次规模的随机行为组合下的节点重启与网络partition恢复测试,发现并纠正了诸多包括etcd亦存在的Raft实现错误
  • 数万行全手写高覆盖测试代码,Raft协议核心3000行代码便有高达万行测试代码护航
  • 移植并通过了所有etcd raft相关测试代码,覆盖etcd累积的各类可能的小概率意外情况
  • 系统的测试方法:单元与集成测试,Jepsen测试,fuzz随机输入测试,随机组合行为测试,I/O错误注入测试,文件系统掉电测试
  • 全面的检查:linearizability检查,应用状态机状态一致、Raft组成员一致、Raft组可用、磁盘上Raft Log Entry一致

随机行为组合测试中,保存了部分Raft组的I/O历史数据,可通过Jepsen的Knossos工具进行系统的Linearizability检查,这些数据也已开源

 

性能分析

在22核2.8GHz的三组服务器间,对16字节的负载,当使用48个Raft组,Dragonboat可以持续每秒900万次的写入,或在9:1的高读写比场景下持续进行每秒1100万次的混合读写操作。跨地域高延迟场景下,高吞吐依旧被保持。

 

活跃组的数量增加会因为batching变得更困难而直接降低吞吐,但吞吐始终是百万数量级的。大量的空闲组则不会显著影响吞吐。

下表是Dragonboat的写延迟数据。在每秒800万次16字节写的情况下,P99写延迟依旧小于5毫秒。得益于ReadIndex协议无需落盘写的特性,读延迟通常情况下显著小于写延迟。

Go的GC具有所有主流语言中最低的STW停顿,这对延迟及延迟离散度敏感场景及其重要。在每秒千万请求的压力下,STW停顿为400微秒。在Go 1.12中,该延迟将继续减半。下图是120个连续GC周期的所有STW停顿时长,该测试场景下每秒平均3个GC周期。

Dragonboat为多组Raft而优化,单Raft组性能尚未经任何优化。当前版本,单Raft组场景下可持续每秒125万次的16字节的写,平均延迟为1.3毫秒,P99延迟2.6毫秒。三组服务器共占用9个2.8GHz CPU核心,平均每台服务器占用3个2.8GHz的CPU核心。

原文链接:https://my.oschina.net/u/4062427/blog/3001821
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章