温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何进行Raft协议实践中的SOFAJRaft剖析

发布时间:2021-12-28 14:00:40 来源:亿速云 阅读:200 作者:柒染 栏目:大数据

今天就跟大家聊聊有关如何进行Raft协议实践中的SOFAJRaft剖析,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

-     SOFAJRaft 概述    -

从通过SOFAJRaft 框架的核心流程剖析加深对Raft协议的理解。SOFAJRaft 是一个纯 Java 的 Raft 算法实现库, 基于百度 braft 实现而来, 使用 Java 重写了所有功能, 支持:

  • 领导人选举和基于优先级的半确定性领导人选举。

  • 日志复制和恢复。

  • 快照和日志压缩。

  • 只读成员(learner)。

  • 集群成员管理,添加节点,删除节点,替换节点等。

  • 完全并发复制。

  • 容错能力。

  • 非对称网络分区容忍性。

  • 当法定人数同伴都死亡的解决方法。

  • 管道复制

  • 线性一致读,ReadIndex/LeaseRead。

额外扩展了一些功能:

  • 对称网络分区容忍性

  • 重启后的转移领袖、负载均衡场景实现

  • 更丰富的指标统计展示

  • 通过Jepsen一致性验证测试

  • 包含嵌入式分布式KV存储实现

整体项目如下:

如何进行Raft协议实践中的SOFAJRaft剖析

如何进行Raft协议实践中的SOFAJRaft剖析

-     领袖选举    -

SOFAJRaft 的选举主要通过判单两个属性:LogIndex 和 Term;Term 即任期,LogIndex即提交到 raft group 中的任务都将序列化为一条日志存储下来,每条日志一个编号,在整个 raft group 内单调递增并复制到每个 raft 节点。可以理解为事务id。投票处理的逻辑主要在 com.alipay.sofa.jraft.core.NodeImpl中,主要有四个函数:

  • 处理处理预投票请求

    Message handlePreVoteRequest(request)

  • 预投票

    void preVote()

  • 处理投票请求

    Message handleRequestVoteRequest(request)

  • 投票

    electSelf()

整体流程如下:

  • Candidate(候选人) 被 Election timeout触发

  • Candidate 开始尝试发起 pre-vote 预投票

  • Follower(追随者) 判断是否认可该 pre-vote request

  • Candidate 根据 pre-vote response 来决定是否发起 RequestVoteRequest

  • Follower 判断是否认可该 RequestVoteRequest

  • Candidate 根据 response 来判断自己是否当选

如何进行Raft协议实践中的SOFAJRaft剖析

使用预投票可以防止网络抖动等特殊原因引起的瞬时失联节点无故捣乱:候选者在发起投票之前,先发起预投票,如果没有得到半数以上节点的反馈,则候选者就会识趣的放弃参选,也就不会抬升全局的 Term。

投票源码:

如何进行Raft协议实践中的SOFAJRaft剖析

预投票源码:

如何进行Raft协议实践中的SOFAJRaft剖析

-     存储机制    -

SOFAJRaft 存储模块分为:

  • Log 存储记录 Raft 配置变更和用户提交任务日志,把日志从 Leader 复制到其他节点上面;

    • checkAndResolveConflict(entries, done)

    • offerEvent(done, type)

      Disruptor队列发布other类型事件

    • appendToStorage(toAppend)

      回调事件处理器StableClosureEventHandler存储日志

    • 返回日志里的首/末个日志索引;

    • 按照日志索引获取 Log Entry 及其任期;

    • 把单个/批量 Log Entry 添加到日志存储;

    • 从 Log 存储头部/末尾删除日志;

    • 删除所有现有日志,重置下任日志索引。

    • LogStorage 是日志存储实现,默认实现基于 RocksDB 存储,通过 LogStorage 接口扩展自定义日志存储实现;核心接口包括:

    • LogManager 负责调用底层日志存储 LogStorage,针对日志存储调用进行缓存、批量提交、必要的检查和优化。

    1. 检查Node节点,解决日志冲突。

    2. 配置管理器:缓存配置变更

    3. LogsInMemory缓存日志Entries

  • Meta 存储即元信息存储记录 Raft 实现的内部状态,比如当前 term,、投票给哪个节点等信息

    • 设置/获取 Raft 元数据的当前任期 Term;

    • 分配/查询 Raft 元信息的 PeerId 节点投票。

    • RaftMetaStorage 元信息存储实现,定义 Raft 元数据的 Metadata 存储模块核心 API 接口包括:

  • Snapshot 存储用于存放用户的状态机 Snapshot 及元信息,用于Node重启重建整个状态机实例。

    • 状态机快照 doSnapshot(done)

    • 安装快照 installSnapshot(request, response, done)。

    • 设置 filterBeforeCopyRemote ,为 true 表示复制到远程之前过滤数据;

    • 创建快照编写器;

    • 打开快照阅读器;

    • 从远程 Uri 复制数据;

    • 启动从远程 Uri 复制数据的复制任务;

    • 配置 SnapshotThrottle,SnapshotThrottle 用于重盘读/写场景限流的,比如磁盘读写、网络带宽。

    • SnapshotStorage 用于 snapshot 存储实现,定义 Raft 状态机的 Snapshot 存储模块核心接口包括:

    • SnapshotExecutor 用于 snapshot 实际存储、远程安装、复制的管理。

如何进行Raft协议实践中的SOFAJRaft剖析

LogManager 调用日志存储 LogStorage 实现逻辑:

如何进行Raft协议实践中的SOFAJRaft剖析

SnapshotExecutor 状态机快照和远程安装镜像实现逻辑:

如何进行Raft协议实践中的SOFAJRaft剖析

-     一致性状态机    -

通过存储的设计,在引入状态机机制,就可以完成一致性状态机。SOFAJRaft状态机组成有:

  • StateMachine:业务逻辑实现的主要接口,状态机运行在每个 raft 节点上,提交的 task 如果成功,最终都会复制应用到每个节点的状态机上。,核心是 onApply(Iterator) 方法,应用通过 Node#apply(task) 提交的日志到业务状态机。

  • FSMCaller:封装对业务 StateMachine 的状态转换的调用以及日志的写入等,一个有限状态机的实现,做必要的检查、请求合并提交和并发处理等。

SOFAJRaft Node节点利用日志复制完成数据同步,主要组成有:

  • Replicator:用于 leader 向 follower 复制日志,也就是 raft 中的 appendEntries 调用,包括心跳存活检查等。

  • ReplicatorGroup: 用于单个 RAFT Group 管理所有的 replicator,必要的权限检查和派发。

下面通过简单介绍了下SOFAJRaft的选举实现、存储机制、状态机和日志复制四个方面。基本上完成了Raft实现的核心实现。但SOFAJRaft还有更多核心及优化,因为篇幅原因没有进入细细剖析。如果咱们自实现Raft协议,基本上也是实现这几个主流程即可完成简版Raft了。关于Raft协议暂时先告一段路,接下去准备开写ZAB协议。

看完上述内容,你们对如何进行Raft协议实践中的SOFAJRaft剖析有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI