向你们介绍Dragonboat,一个开源的Go实现的多组Raft库,项目已Apache2协议下开源。欢迎你们试用,也请你们点star鼓励:https://github.com/lni/dragonboatgit
通俗的讲,这是一个分布式共识协议库,应用能够用它把数据分布存储于多台机器上,只要过半数的机器在线,数据与服务即可在线。这避免了因个别机器当机或网络故障而形成数据、服务不可用,提升系统可用性。它提供称为Linearizability的强一致特性:多个副本的数据在外部看来更像使用单一副本,不会有仅提供最终一致性的系统常见且难缠的读到旧版数据的问题。github
基于Raft协议的共识库已经应用于不少互联网后台系统。接触了不少用户之后,广泛反馈的当前应用障碍是缺少一个可靠、高性能、且对共识协议自己接近全透明的开箱即用的通用实现。数据库
优点安全
Dragonboat已经较好的解决全部上述应用障碍:性能优化
同时,Dragonboat的Go实现通过大量具体性能优化打磨,在当前高性能Go系统在行业内需求持续剧增的背景下,为准备入坑的同窗踩坑带路提供参考。服务器
功能与使用网络
Dragonboat实现了Raft论文中说起的几乎全部功能,是当前最完备的Raft协议的Go实现:并发
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成员节点内含下列实例:
其中应用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通过及其严格的测试。相对于用宣传式口号称赞软件如何可靠,下列具体数字和事实相信更具备说服力:
随机行为组合测试中,保存了部分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核心。