一致性算法 - Raft协议实践
- SOFAJRaft 概述 -
领导人选举和基于优先级的半确定性领导人选举。
日志复制和恢复。
快照和日志压缩。
只读成员(learner)。
集群成员管理,添加节点,删除节点,替换节点等。
完全并发复制。
容错能力。
非对称网络分区容忍性。
当法定人数同伴都死亡的解决方法。
管道复制
线性一致读,ReadIndex/LeaseRead。
对称网络分区容忍性
重启后的转移领袖、负载均衡场景实现
更丰富的指标统计展示
通过Jepsen一致性验证测试
包含嵌入式分布式KV存储实现
- 领袖选举 -
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 来判断自己是否当选
投票源码:
预投票源码:
- 存储机制 -
SOFAJRaft 存储模块分为:
Log 存储记录 Raft 配置变更和用户提交任务日志,把日志从 Leader 复制到其他节点上面;
LogStorage 是日志存储实现,默认实现基于 RocksDB 存储,通过 LogStorage 接口扩展自定义日志存储实现;核心接口包括:
返回日志里的首/末个日志索引;
按照日志索引获取 Log Entry 及其任期;
把单个/批量 Log Entry 添加到日志存储;
从 Log 存储头部/末尾删除日志;
删除所有现有日志,重置下任日志索引。
LogManager 负责调用底层日志存储 LogStorage,针对日志存储调用进行缓存、批量提交、必要的检查和优化。
checkAndResolveConflict(entries, done)
检查Node节点,解决日志冲突。
配置管理器:缓存配置变更
LogsInMemory缓存日志Entries
offerEvent(done, type)
Disruptor队列发布other类型事件
appendToStorage(toAppend)
回调事件处理器StableClosureEventHandler存储日志
Meta 存储即元信息存储记录 Raft 实现的内部状态,比如当前 term,、投票给哪个节点等信息
RaftMetaStorage 元信息存储实现,定义 Raft 元数据的 Metadata 存储模块核心 API 接口包括:
设置/获取 Raft 元数据的当前任期 Term;
分配/查询 Raft 元信息的 PeerId 节点投票。
Snapshot 存储用于存放用户的状态机 Snapshot 及元信息,用于Node重启重建整个状态机实例。
SnapshotStorage 用于 snapshot 存储实现,定义 Raft 状态机的 Snapshot 存储模块核心接口包括:
设置 filterBeforeCopyRemote ,为 true 表示复制到远程之前过滤数据;
创建快照编写器;
打开快照阅读器;
从远程 Uri 复制数据;
启动从远程 Uri 复制数据的复制任务;
配置 SnapshotThrottle,SnapshotThrottle 用于重盘读/写场景限流的,比如磁盘读写、网络带宽。
SnapshotExecutor 用于 snapshot 实际存储、远程安装、复制的管理。
状态机快照 doSnapshot(done)
安装快照 installSnapshot(request, response, done)。
SnapshotExecutor 状态机快照和远程安装镜像实现逻辑:
- 一致性状态机 -
通过存储的设计,在引入状态机机制,就可以完成一致性状态机。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协议。
- 作者介绍 -
林淮川
毕业于西安交通大学;奈学教育《百万架构师训练营》讲师、企业级源码内源负责人,前大树金融高级架构师、技术委员会开创者、技术总监;前天阳宏业交易事业部技术主管;多年互联网金融行业(ToB)经验。
本文分享自微信公众号 - 川聊架构(gh_44ec4115d261)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
一道价值25k的腾讯递归组件面试题(Vue3 + TS 实现)
前言 小伙伴们好久不见,最近刚入职新公司,需求排的很满,平常是实在没时间写文章了,更新频率会变得比较慢。 周末在家闲着无聊,突然小弟过来紧急求助,说是面试腾讯的时候,对方给了个 Vue 的递归菜单要求实现,回来找我复盘。 正好这周是小周,没想着出去玩,就在家写写代码吧,我看了一下需求,确实是比较复杂,需要利用好递归组件,正好趁着这个机会总结一篇 Vue3 + TS 实现递归组件的文章。 需求 可以先在 Github Pages[1] 中预览一下效果。 需求是这样的,后端会返回一串可能有无限层级的菜单,格式如下: [{id:1,father_id:0,status:1,name:'生命科学竞赛',_child:[{id:2,father_id:1,status:1,name:'野外实习类',_child:[{id:3,father_id:2,status:1,name:'植物学'}],},{id:7,father_id:1,status:1,name:'科学研究类',_child:[{id:8,father_id:7,status:1,name:'植物学与植物生理学'},{id:9,fa...
- 下一篇
【Flutter 实战】动画序列、共享动画、路由动画
老孟导读:此篇文章是 Flutter 动画系列文章第四篇,本文介绍动画序列、共享动画、路由动画。 动画序列 Flutter中组合动画使用Interval,Interval继承自Curve,用法如下: Animation _sizeAnimation = Tween(begin: 100.0, end: 300.0).animate(CurvedAnimation( parent: _animationController, curve: Interval(0.5, 1.0))); 表示_sizeAnimation动画从0.5(一半)开始到结束,如果动画时长为6秒,_sizeAnimation则从第3秒开始。 Interval中begin 和end参数值的范围是0.0到1.0。 下面实现一个先执行颜色变化,在执行大小变化,代码如下: class AnimationDemo extends StatefulWidget { @override State<StatefulWidget> createState() => _AnimationDemo();}class _A...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- 2048小游戏-低调大师作品
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Red5直播服务器,属于Java语言的直播服务器
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7