一个Raft开源项目的结构分析

从0-1实现简易Raft分布式共识算法 分布式体系下,共识算法是必不可少的,光看不实践就容易眼高手低,根据raft做了点改动,实现了简易KV、心跳、选举、日志同步、日志Check、间接性实现一致性读, 阅读详情

640?wx_fmt=png

Raft声称是一种易于理解的分布式一致性算法。有不少工程师们翻了它的论文,参考了很多资料,最后只好怀疑自己是不是智商有问题。

Raft一直以来是很多高级资深程序员技术上的天花板,捅破相当有难度。每次刚刚拿起时汹涌澎湃,过不了多久便偃旗息鼓了,有一种丧尸般的难受。渴望逃离技术舒适区时会经常经历有这种挫折。在分布式系统领域,Raft就是一道很高的门槛,迈过了这道坎后面技术的自由度就可以再上一个台阶。

Raft Paper的内容对于一个普通程序员来说不是太容易理解。选举模块还算比较简单,日志复制表面上也很好理解,快照模块也很形象。但是深入进去看细节,一头雾水是必然的。特别是对集群节点变更模块的理解更是艰难。

开源代码

https://github.com/wenweihu86/raft-javagithub.com

最近花了一些时间把他的代码通读了一边,发现居然都可以理解,感觉离自己造轮子更近了一步。加上之前实现过RPC框架,再撸一套Raft服务应该是可以很快变成现实了。宏观结构

640?wx_fmt=jpeg

首先我们假设有三个RaftNode,每个RaftNode都会开设一个端口,这个端口的作用就是接受客户端的(Get/Set)请求以及其它RaftNode的RPC请求。这里需要说明的是多数著名开源项目一般会选择两个端口,一个面向客户端,一个面向RPC,好处是可以选择不同的IP地址,客户端端口可以面向外网,而RPC则是安全的内网通信。作者选择了一个端口是因为只用于内网,在实现上也会简单不少。

客户端可以连接任意一个节点。如果连接的不是Leader,那么发送的请求会在服务端进行转发,从当前连接的RaftNode转发到Leader进行处理。另外一种可选的设计是所有的客户端都连接到Leader,这样就避免了转发的过程,可以提升性能。

但是服务端转发也有它的好处,那就是当客户端在数据一致性要求不好的情况下,读请求可以不用转发,直接在当前的RaftNode进行处理。所以返回的数据可能不是实时的。这可以挡住大部分客户端请求,提升整体的读性能。RaftNode的细节

640?wx_fmt=jpeg

RaftNode中包含的重要组件都在这张图上了。

首先Local Server接收到请求后,立即将请求日志附加到SegmentedLog中,这个日志会实时存到文件系统中,同时内存里也会保留一份。因为作者考虑到日志文件过大可能会影响性能和安全性(具体原因未知,Redis的aof日志咋就不需要分段呢),所以对日志做了分段处理,顺序分成多个文件,所以叫SegmentedLog。

640?wx_fmt=jpeg

日志有四个重要的索引,分别是firstLogIndex/lastLogIndex和commitIndex/applyIndex,前两个就是当前内存中日志的开始和结束索引位置,后面两个是日志的提交索引和生效索引。之所以是用firstLogIndex而不是直接用零,是因为日志文件如果无限增长会非常庞大,Raft有策略会定时清理久远的日志,所以日志的起始位置并不是零。commitIndex指的是过半节点都成功同步的日志的最大位置,这个位置之前的日志都是安全的可以应用到状态机中。Raft会将当前已经commit的日志立即应用到状态机中,这里使用applyIndex来标识当前已经成功应用到状态机的日志索引。

该项目示例提供的状态机是RocksDB。RocksDB提供了高效的键值对存储功能。实际使用时还有很多其它选择,比如使用纯内存的kv或者使用leveldb。纯内存的缺点就是数据库的内容都在内存中,Rocksdb/Leveldb的好处就是可以落盘,减轻内存的压力,性能自然也会有所折损。

如果服务器设置了本地落盘即可返回(isAsyncWrite),那么Local Server将日志塞进SegmentedLog之后就会立即向客户端返回请求成功消息。但是这可能会导致数据安全问题。因为Raft协议要求必须等待过半服务器成功响应后才可以认为数据是安全的,才可以告知客户端请求成功。之所以提供了这样一个配置项,纯粹是为了性能考虑。分布式数据库Kafka同样也有类似的选项。是通过牺牲数据一致性来提高性能的折中方法。

正常情况下,Local Server通过一个Condition变量的await操作悬挂住当前的请求不予返回。

640?wx_fmt=jpeg

对于每个RPCClient,它也要维护日志的两个索引,一个是matchIndex表示对方节点已经成功同步的位置,可以理解为局部的commitIndex。而nextIndex就是下一个要同步的日志索引位置。随着Leader和Follower之间的消息同步,matchIndex会努力追平nextIndex。同样随着客户端的请求的连续到来,nextIndex也会持续前进。

Local Server在悬挂住用户的请求后,会立即发出一次异步日志同步操作。它会通过RPC Client向其它节点发送一个AppendEntries消息(也是心跳消息),包含当前尚未同步的所有日志数据(从commitIndex到lastLogIndex)。然后等待对方实时反馈。如果反馈成功,就可以前进当前的日志同步位置matchIndex。

matchIndex是每个RPCClient局部的位置,当有过半RPCClient的matchIndex都前进了,那么全局的commitIndex也就可以随之前进,取过半节点的matchIndex最小值即可。

commitIndex一旦前进,意味着前面的日志都已经成功提交了,那么悬挂的客户端也可以继续下去了。所以立即通过Condition变量的signalAll操作唤醒所有正在悬挂住的请求,通知它们马上给客户端响应。

注意日志同步时还得看节点日志是否落后太多,如果落后太多,通过AppendEntries这种方式同步是比较慢的,这时就是要考虑走另一条路线来同步日志,那就是snapshot快照同步。

快照同步就是Leader将最新的快照文件发送到Follower节点,Follower安装快照后成功后,Leader继续同步SegmentedLog,力图让Follower追平自己。RaftNode启动流程选举流程

640?wx_fmt=jpeg

RaftNode初始是处于Follower状态,启动后立即开启一个startNewElection定时器,在这个定时器到点之前如果没有收到来自Leader的心跳消息或者其它Candidate的请求投票消息,就立即变身成为Candidate,发起新一轮选举过程。当选Leader的条件日志同步集群成员变化

640?wx_fmt=jpeg

分布式系统的一个非常头疼的问题就是同样的动作发生的时间却不一样。比如上图的集群从3个变成5个,集群的配置从OldConfig变成NewConfig,这些节点配置转变的时间并不完全一样,存在一定的偏差,于是就形成了新旧配置的叠加态。

在图中红色剪头的时间点,旧配置的集群下Server[1,2]可以选举Server1为Leader,Server3不同意没关系,过半就行。而同样的时间,新配置的集群下Server[3,4,5]则可以选举出Server5为另外一个Leader。这时候就存在多Leader并存问题。

为了避免这个问题,Raft使用单节点变更算法。一次只允许变动一个节点,并且要按顺序变更,不允许并行交叉,否则会出现混乱。如果你想从3个节点变成5个节点,那就先变成4节点,再变成5节点。变更单节点的好处是集群不会分裂,不会同时存在两个Leader。

640?wx_fmt=jpeg

如图所示,蓝色圈圈代表旧配置的大多数(majority),红色圈圈代码新配置的带多数。新旧配置下两个集群的大多数必然会重叠(旧配置节点数2k的大多数是k+1,新配置节点数2k+1的大多数是k+1,两个集群的大多数之和是2k+2大于集群的节点数2k+1)。这两个集群的term肯定不一样,而同一个节点不可能有两个term。所以这个重叠的节点只会属于一个大多数,最终也就只会存在一个集群,也就只有一个Leader。

集群变更操作日志不同于普通日志。普通日志要等到commit之后才可以apply到状态机,而集群变更日志在leader将日志追加持久化后,就可以立即apply。为什么要这么做,可以参考知乎孙建良的这篇文章 zhuanlan.zhihu.com/p/29,这里面精细描述了commit & reply集群变更日志带来的集群不可用的场景。最后

关注公众号「码洞」,加入我们一起来进阶Raft算法。

小白对Raft的理解 小白对Raft的理解 1. Raft简介 1.1 Raft的前世今生 Raft算法它实际上是一种共识算法,脱胎于Paxos算法。因为Paxos算法不好理解,而且实现起来非常复杂,所以Raft算法就此诞生。 1.2 Raft应用场景 Raft在工程领域的应用特别多,比如Redis的哨兵选举机制、InfluxDB的leader选举、Dragonboat、腾讯云的消息队列CMQ等等。经常被用作CP原则的一致性算法。 2.Raft基础 2.1 Raft中的名词概念 在一个Raft集群中,它有n个服务器构成,其 阅读详情

相关推荐

开源项目ARIES解析:从命名推测到Rust分布式系统仿真实践

在软件工程领域,开源项目是技术学习与实践的重要载体。理解一个项目的核心,往往始于对其命名、结构与技术栈的解构分析。项目命名常隐含其技术愿景,如ARIES可能指向算法库或执行系统,这需要开发者通过代码结构、依赖文件等技术线索进行逆向工程。其原理在于通过模块化设计与清晰的技术选型,实现特定领域问题的解决方案,例如使用Rust语言构建高性能、内存安全的系统工具。在技术价值上,这类项目通常体现了工程实践中的依赖管理、测试驱动开发和性能优化等核心方法论。应用场景广泛覆盖算法实现、运行时引擎、研究框架及实用工具开发。本

weixin_33743703的博客 538

科普: 中间件底层实现的分布式协议之Raft

正式介绍 Raft 协议之前,我们先来举一个例子????进行展开。 方式一: 在一个技术团队内假设角色都是均等的,会导致什么情况呢?产品提出一个需求,就可以随便去找团队中的任意一个人去发起需求。如果这个人因为请假走了,但是他没有把需求及时同步给团队其他人,因此会导致该需求存在很大的延迟。 方式二: 在技术团队中选举一个Leader 角色,产品提出的需求必须优先提给 Leader,找 Lead...

dayformyjob 729

【路由交换】思科5506防火墙三区域互通

思科 5506 inside outside dmz 互通

baidu_22774701的博客 6207

实际项目集成分布式一致性协议 Raft

只要理解了共识算法,其实集成 raft 很简单,由于共识算法优秀文章已经很多了,本章就不做过多赘述了;这里我们重点是讨论如何在我们的实际工程中集成 raft 协议,来实现分布式一致性;前面我们只会简单的介绍分布式共识算法以及学习 Nacos 如何来集成分布式算法,重点在第4小节;看完本章,大家可以根据自己项目的实际情况来决定是否需要集成 raft 协议来实现分布式一致性。

谢文峰的博客 1291

基于SHIS凝视型短波红外高光谱相机(900-1700nm)区分不同宝石的差异性和可分性(宝石分选)

SHIS系列凝视型高光谱相机基于液晶可调谐滤波器(LCTF),通过电控LCTF进行连续细分窄波段分光,对每个波段进行高分辨率的二维面阵成像,进行图像处理后,获得完整的高光谱高清图像序列。具有低功耗、小型化、使用方便和易于扩展的优势。其工作波段覆盖400nm至1000nm,能够捕捉宝石在不同波长下的光谱特征,为宝石鉴定提供了新的工具。

wayho的博客 711

UFS 功能描述:UFS boot

UFS 启动过程介绍:启动配置,启动代码下载过程和安全性

m0_51720747的博客 1605

别再怀疑自己的智商了,Raft协议本来就不好理解

Raft声称是一种易于理解的分布式一致性算法。有不少工程师们翻了它的论文,参考了很多资料,最后只好怀疑自己是不是智商有问题。 Raft一直以来是很多高级资深程序员技术上的天花板,捅破相当有难度。每次刚刚拿起时汹涌澎湃,过不了多久便偃旗息鼓了,有一种丧尸般的难受。渴望逃离技术舒适区时会经常经历有这种挫折。在分布式系统领域,Raft就是一道很高的门槛,迈过了这道坎后面技术的自由度就可以再上一个台阶。 ...

weixin_34218579的博客 447

自动驾驶开发者必看:nuscenes数据集23类物体标注全解析(附避坑指南)

本文深入解析nuscenes数据集的23类物体标注系统,为自动驾驶开发者提供全面的标注规范解读和实战避坑指南。涵盖多模态数据组织、类别细分规则、属性系统应用技巧以及标注质量验证方法,帮助开发者高效利用这一标杆数据集提升模型性能。

weixin_29041767的博客 258

RAFT-Stereo 开源项目教程

RAFT-Stereo 是一个基于深度学习的立体匹配算法,由普林斯顿大学的研究团队开发。该项目是基于 RAFT(Recurrent All-Pairs Field Transforms)光流网络的扩展,专门用于处理立体图像对的视差估计。RAFT-Stereo 通过多级循环场变换有效地提高了立体匹配的准确性和泛化能力,尤其在跨数据集的表现上优于现有方法。 ## 2、项目快速启动 ### 环境配置

gitblog_00108的博客 1129

因果强化学习:优化决策策略的因果方法

1. 背景介绍 1.1 传统强化学习的局限性 强化学习(Reinforcement Learning, RL)是一种通过与环境交互来学习最优决策策略的方法。然而,传统强化学习方法在面对复杂、动态和不确定的现实世界问题时,往往存在以下局限性: 数据效率低:传统强化学习方法

AI天才研究院 659

iqoo11如何获取root权限?

🏆本文收录于专栏,主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家!持续更新中,up!up!up!!

**My Coding Family** 5849

RAFT 开源项目教程

RAFT 是一个由普林斯顿视觉实验室(Princeton Vision & Learning Lab)开发的开源计算机视觉项目,专注于光流估计(Optical Flow Estimation)。光流是描述图像序列中像素运动的技术,广泛应用于视频分析、增强现实、自动驾驶等领域。RAFT 项目通过深度学习模型提供了一种高效且准确的光流估计方法。 ## 项目快速启动 ### 环境配置 首先,确保你...

gitblog_00973的博客 725

C++设计模式之观察者模式

观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。这种模式通常用于实现分布式事件处理系统,当一个对象(称为“主题”或“发布者”)改变状态时,所有注册的观察者都会收到通知。

每天进步一点点。 601

SEA-RAFT:一种先进的光流估计工具

**SEA-RAFT** 是一个基于 PyTorch 的开源项目,由普林斯顿视觉实验室开发。该项目旨在提供一个高效的光流估计解决方案,通过结合SEA(Sparsity Enforcing Aggregation)机制和RAFT(Recurrent All Pairs Field Transforms)框架,它能够处理复杂的场景变化,从而在保持计算效率的同时提升光流预测的准确性。此项目对于视频分析、

gitblog_00371的博客 1393

Xilinx DDR3 MIG IP核设计--汇总导航

快速上手Xilinx DDR3 IP核----汇总篇

孤独的单刀 2万+

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

推荐开源项目:jgroups-raft —— 基于JGroups的高效Raft共识算法实现

推荐开源项目:jgroups-raft —— 基于JGroups的高效Raft共识算法实现 jgroups-raftImplementation of the RAFT consensus protocol in JGroups项目地址:https://gitcode.com/gh_mirrors/jg/jgroups-raft 项目介绍 jgroups-raft 是一个强大的库,它在 JGro...

gitblog_00036的博客 716

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Raft-Java 开源项目教程

此`raft-java`项目主要包含以下几个核心目录: ### `raft-java-admin` 这个目录包含了管理相关的代码,可能包括集群管理和监控工具。 ### `raft-java-core` 这是项目的核心组件,实现了Raft一致性算法的Java库。 ### `raft-java-example` 示例目录,提供了如何在本地快速搭建一个简单的3节点Raft集群的示例。 ### `...

gitblog_00419的博客 397

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Raft 开源项目使用教程

Raft 开源项目使用教程 1. 项目的目录结构及介绍 raft/ ├── README.md ├── bin/ │ └── raft ├── config/ │ └── config.yaml ├── src/ │ ├── main.go │ ├── node.go │ └── log.go ├── test/ │ └── integration_test.go └── ...

gitblog_00654的博客 461

Akka-Raft 开源项目教程

Akka-Raft 开源项目教程 项目介绍 Akka-Raft 是一个基于 Akka Cluster 实现的 Raft 共识算法项目。Raft 是一种用于管理复制日志的共识算法,旨在比 Paxos 更易于理解,同时提供相同的功能保证。Akka-Raft 项目通过 Akka 的 actor 模型来实现 Raft 算法,使得分布式系统中的节点能够达成一致的状态。 项目快速启动 环境准备 Java 8...

gitblog_01173的博客 729

RAFT 项目安装和配置指南

### 项目基础介绍 RAFT 是一个用于光流估计的开源项目,由普林斯顿大学的视觉实验室开发。该项目基于论文《RAFT: Recurrent All Pairs Field Transforms for Optical Flow》,发表于 ECCV 2020。RAFT 算法通过递归计算所有点对之间的场变换来估计光流,具有较高的准确性和效率。 ### 主要编程语言 RAFT 项目主要使用 Pyth...

gitblog_07890的博客 1500

你也可以用Java来实现RAFT协议

基于 Java 实现的轻量级 RAFT 底层框架 ——Airy-raft,它以高负载、低延迟、丰富接口和清晰逻辑,为分布式应用开发提供强力支撑,助力开发者快速构建可靠的分布式系统.

qq_22928269的博客 786

c-raft 开源项目教程

c-raft 开源项目教程 1. 项目的目录结构及介绍 c-raft 项目的目录结构如下: c-raft/ ├── bin/ ├── conf/ ├── docs/ ├── src/ │ ├── client/ │ ├── common/ │ ├── server/ │ └── main.go ├── tests/ └── README.md 目录结构介绍 bin/: 存放编译...

gitblog_00588的博客 348

掌握分布式共识:async-raft 开源项目详解

在这个高度互联的世界中,构建可扩展的、高可用性的分布式系统至关重要。为此,我们需要坚实的技术基石,其中之一就是分布式一致性协议。现在,让我们一起探索一个基于Rust的优秀开源实现——[async-raft](https://github.com/async-raft/async-raft),它是一个利用Tokio框架实现的高效异步Raft共识算法库。 ## 项目简介 async-raft 是一...

gitblog_00067的博客 497

Little Raft 开源项目教程

Little Raft 开源项目教程 项目介绍 Little Raft 是一个基于 Raft 共识算法的分布式一致性协议实现。Raft 是一种为了管理复制日志的一致性算法,它提供一种在计算系统集群中实现容错的方式,其设计目标包括可理解性、简单性和实用性。Little Raft 项目旨在提供一个轻量级、易于理解和使用的 Raft 实现,适用于学习和开发分布式系统。 项目快速启动 环境准备 Rust...

gitblog_00186的博客 582
上一篇: 各大主流语言web框架代码行数对比
下一篇: Raft协议精解
码洞
博客等级 码龄10年 41粉丝 137原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值