EasyRaft是Raft(共识算法)的Java实现,主要目的在于提供一种高性能的分布式一致性协议。
覆盖Jraft实现的功能
分布式一致性 (distributed consensus) 是分布式系统中最基本的问题,用来保证一个分布式系统的可靠性以及容灾能力。简单的来讲,就是如何在多个机器间对某一个值达成一致, 并且当达成一致之后,无论之后这些机器间发生怎样的故障,这个值能保持不变。 抽象定义上, 一个分布式系统里的所有进程要确定一个值 v,如果这个系统满足如下几个性质, 就可以认为它解决了分布式一致性问题, 分别是:
RAFT 是一种新型易于理解的分布式一致性复制协议,由斯坦福大学的 Diego Ongaro 和 John Ousterhout 提出,作为 RAMCloud 项目中的中心协调组件。Raft 是一种 Leader-Based 的 Multi-Paxos 变种,相比 Paxos、Zab、View Stamped Replication 等协议提供了更完整更清晰的协议描述,并提供了清晰的节点增删描述。 Raft 作为复制状态机,是分布式系统中最核心最基础的组件,提供命令在多个节点之间有序复制和执行,当多个节点初始状态一致的时候,保证节点之间状态一致。系统只要多数节点存活就可以正常处理,它允许消息的延迟、丢弃和乱序,但是不允许消息的篡改(非拜占庭场景)。
Raft 可以解决分布式理论中的 CP,即一致性和分区容忍性,并不能解决 Available 的问题。其中包含分布式系统中一些通常的功能:
通过 RAFT 提供的一致性状态机,可以解决复制、修复、节点管理等问题,极大的简化当前分布式系统的设计与实现,让开发者只关注于业务逻辑,将其抽象实现成对应的状态机即可。基于这套框架,可以构建很多分布式应用:
同时RAFT贴近业务的抽象设计,方便适配业务;
一个纯 Java 的 Raft 算法实现库, 基于百度 braft 实现而来, 使用 Java 重写了所有功能, 支持:
Leader election and priority-based semi-deterministic leader election.
Replication and recovery.
Snapshot and log compaction.
Read-only member (learner).
Membership management.
Fully concurrent replication.
Fault tolerance.
Asymmetric network partition tolerance.
Workaround when quorate peers are dead.
Replication pipeline optimistic
Linearizable read, ReadIndex/LeaseRead.
在EasyRAFT中的自主特殊实现,而没使用通用组件库:
单一节点会在三种角色中流转状态,采用了状态模式控制行为,如Leader在包含特殊的行为:
包括Meta存储与Log存储,自主研发的实现:
RPC 模块用于节点之间的网络通讯,基于原生NIO、Selector的RPC网络架构,自主研发实现:
整体模块图
RAFT DB是专门适配Raft协议的储存库,是LSM类型数据库但没有WAL,同时在日志压缩上做了更匹配RAFT的方案。
高性能性能基础原理:
此外在并发控制上:
而在数据结构上:
Rocks是一个日志式(LSM)K-V数据库,由FaceBook开发旨在提供高速的数据持久化和读写能力,适用于需要快速存储和检索大量数据的应用程序。使用RocksDB的项目包括Flink、TiKV等;
在此基准测试运行开始时,数据库为空,并逐渐填满。数据加载过程中未读取任何数据。
数据库类型 | 版本 | 平均吞吐量 | 标准差 | 最小 | 最大 | 波动程度 | 置信率 | 同比差率 |
---|---|---|---|---|---|---|---|---|
RaftDB | 1.0 | 390592.650 | 3469.357 ops/s | 384407.308 | 395535.143 | 1865.434 | 99.9% | 100% |
RocksDB | 8.3 | 298498.660 | 2671.176 ops/s | 293204.765 | 302760.628 | 2498.620 | 99.9% | 76.4% |
测量性能以随机读取现有数据(1000w数据为基础)。
数据库类型 | 版本 | 缓存 | 平均吞吐量 | 标准差 | 最小 | 最大 | 波动程度 | 置信率 | 同比差率 |
---|---|---|---|---|---|---|---|---|---|
RaftDB | 1.0 | 关闭 | 102574.692 | 1030.314 ops/s | 100099.588 | 103989.586 | 963.757 | 99.9% | 88.1% |
RocksDB | 8.3 | 关闭 | 116429.139 | 3580.538 ops/s | 108565.503 | 119586.128 | 3349.237 | 99.9% | 100% |
此外还有更多的测试用例,不一一展示了
RPC Net是基于JDK NIO实现的RPC架构,设计核心是高并发、可控。
根据Selector模型的事件抽象出,建立连接与读写操作分离的模型。
整体是一个非阻塞的模型,所以不需要很多的线程(读取后投递队列,不处理业务),合适的线程配置是1:4,即一个线程负责接收连接,4个线程负责接收与写入数据等
四个队列实现非阻塞的操作,所以该模型可以用少量的线程完成高并发的运转
网络框架 | 版本 | 平均吞吐量 | 同比差率 |
---|---|---|---|
RPC Net | 1.0 | 349083.983 | 100% |
Netty | 4.1 | 319393.519 | 91.4% |
项目中有大量的并发风险控制、延迟任务,定制适合场景的多线程工具,精化场景,以下是类图:
本节主要介绍 Easy RAFT 的配置和辅助工具相关接口和类。核心包括:
Endpoint 表示一个服务地址。
PeerId 表示一个 raft 参与节点。
Configuration 表示一个 raft group 配置,也就是节点列表。
SERVICE_LOCAL_NODES表示一个服务地址,包括 IP 和端口, 并设置了比重,该比重影响优先选举权,如下例:
Properties properties = new Properties();
properties.put(ConfigConstants.SERVICE_ID, "id");
//本地节点&优先选举比重
properties.put(ConfigConstants.SERVICE_LOCAL_NODES, "1,localhost:9094,[node_weight:500]");
//集群节点
properties.put(ConfigConstants.SERVICE_NODES, "2,localhost:9091;3,localhost:9092;3,localhost:9093;");
ServerConfig serverConfig = new ServerConfig(properties);
其中包括但不限于以下配置:
SERVICE_ROOT_DIR //根目录
SERVICE_QUORUM_RATE //quorum比例
SERVICE_RECORDING_LEVEL//监控等级
SEGMENT_MAX_SIZE//单个Segment大小
SEGMENT_OFFSET_INDEX_MAX_SIZE//Segment稀疏索引大小
SEGMENT_OFFSET_INTERVAL//稀疏索引间隔(默认4k)
LOG_TYPE//日志类型
LOG_CLEAN_OPEN//压缩日志服务
LOG_CLEAN_ALGORITHM//压缩hash算法
......
下图中节点在不同角色流转的核心条件,其中Leader的详细条件包括:
此优化在独立日志水位后,异步执行同步任务,可预期的结果能够提升并发。
相比于JDK-ScheduledThreadPoolExecutor的时间复杂度为O(nlogn),采用此方法时间复杂度能够达到O(1)。
https://gitee.com/weKie/easy-raft.git