Raft分布式一致性算法

拜占庭将军

假设多位拜占庭将军中没有叛军,信使的信息可靠但有可能被暗杀的情况下,将军们如何达成是否要进攻的一致性决定?解决问题的思路是,从多位处于平等地位的将军中选举出一位大将军,所有作战指令由大将军发出。如果这位大将军被杀,那么只需要从剩下的将军中再次选举出大将军即可。这就是解决分布式共识问题的思路。如何选举、指令如何传达则是实现分布式共识的手段。下面我们尝试推演一下这个过程。

假设拜占庭有三座城池,由3位将军掌管,每位将军都在等消息,等待了一个随机时间后,如果没收到任何消息,将派出自己的信使向另外两位将军发起自己当大将军的投票。其它将军如果收到了将军的投票请求,默认会将自己的一票投给信使最先到达的将军,后到者则拒绝。所有将军都是这个做法,那么最终必定能选出一个大将军。选出后,后面的作战指令就通过信使定期向其它将军发出,如果超过预设时间没收到指令,则认为大将军已死,苍天已死,黄天当立,剩下的将军们开始新一轮拉票当大将军活动.....

基本上,分布式共识或说分布式数据一致性大体上是按上面的思路来实现的。

分布式共识

假设我们对单一的节点就某个值进行写操作,是很容易达成共识的,毕竟只有一个节点,写成功了就达成一致。但是,如果我们有多个节点,我们该如何达成共识呢?

这个就是分布式共识问题。例如mongodb副本机制,写入一个文档是需要在所有副本节点之间进行同步的,但节点间的数据如何同步,哪个节点提供读或写服务?这些都涉及到分布式共识问题,分布式共识问题可以简单理解成在一个多节点数据集群中(此集群有可能出现分区),如何对数据进行同步,使所有节点的数据达到一致的问题。

共识算法通常具备如下特性:

  • 高可用。只要集群中多数节点是可用、与客户端的通信也是正常的,那么整个系统就是正常可用的,少数节点故障并不会影响系统的运行。

  • 强一致性。数据一致性不依赖时序,最坏的情况会产生可用性问题,但不会产生一致性问题。

Raft

raft是一个用于实现分布式共识的协议。

节点状态

在一个使用Raft共识算法的集群中,集群节点会存在三个节点状态,分别是Follwer、Candidate、Leader。

  • Follwer:接受 Leader 的心跳和日志同步数据,投票给 Candidate

  • Candidate:Leader候选角色,Follwer倒计时时钟结束转化成Candidate,可发起投票参与Leader竞选

  • Leader:集群领导角色,负责发起心跳,响应客户端,创建日志,同步日志

在一个非分区集群中,只会有一个Leader(网络分区可能会造成出现多个leader的情况),剩下的都是Follwer,Candidate只会出现在集群选举过程中,成功获取多数票的Candidate节点直接成为Leader。

任期

任期是一个连续递增的数字,每一个任期的开始都是一次选举,在选举开始时,一个或多个 Candidate 会尝试成为 Leader。如果一个 Candidate 赢得了选举,它就会在该任期内担任 Leader。如果没有选出 Leader,将会开启另一个任期,并立刻开始下一次选举。

每个节点都会存储当前的 term 号,当服务器之间进行通信时会交换当前的 term 号;如果有服务器发现自己的 term 号比其他人小,那么他会更新到较大的 term 值。如果一个 Candidate 或者 Leader 发现自己的 term 过期了,他会立即退回成 Follower。如果一台服务器收到的请求的 term 号是过期的,那么它会拒绝此次请求。

日志

  • entry:每一个事件成为 entry,只有 Leader 可以创建 entry。entry 的内容为<term,index,cmd>其中 cmd 是可以应用到状态机的操作。

  • log:由 entry 构成的数组,每一个 entry 都有一个表明自己在 log 中的 index。只有 Leader 才可以改变其他节点的 log。entry 总是先被 Leader 添加到自己的 log 数组中,然后再发起共识请求,获得同意后才会被 Leader 提交给状态机。Follower 只能从 Leader 获取新日志和当前的 commitIndex,然后把对应的 entry 应用到自己的状态机中。

Leader选举过程

开始选举时,所有节点处于Follwer状态,节点会有一个随机倒计时时钟(随机时间在150ms到300ms内),这个随机时钟是为了有节点能更快的达到Candidate状态发出选举,从而成为Leader。避免可能出现的多个节点同时成为Candidate从而导致选举效率低下问题。

当某节点election timeout心跳结束,但没收到主节点的心跳信息,它就会转成Candidate 。

此时,NodeA成为Candidate并开启亲的任期,然后向B、C节点发起投票

此时如果B、C的任期小于收到的1,自身也还没成为Candidate,此时B、C将票投到A。B、C重置election timeout时钟。在 Candidate 等待选票的时候,它可能收到其他节点声明自己是 Leader 的心跳,此时有两种情况:

  • 该 Leader 的 term 号大于等于自己的 term 号,说明对方已经成为 Leader,则自己回退为 Follower。

  • 该 Leader 的 term 号小于自己的 term 号,那么会拒绝该请求并让该节点更新 term。

收到选票的A获得集群大多数票(N/2+1),成功转成Leader,并向集群其它节点定期发送心跳(heartbeat timeout)以保住自己的Leader地位。

其他节点收到心跳(Append Entries)后响应主节点然后再次重置election timeout时钟。这个选举任期将持续到Follwer心跳time_out而成为Candidate。

主节点下线后,集群就会出现重选举,新选出的Leader的任期递增。正常情况下,获取多数票的节点成为主节点,但如果出现偶数节点时,可能会出现两个节点获取了相同票数的情况。

比如上面的情况,A、C加上自身的票数,都是2票,此时这个任期是选不出Leader的。只能重新发起一轮选举。如此反复,最终选出一个Leader。

可见,Raft协议下,节点无论是奇数还是偶数都是能正常选举出Leader的,但是偶数节点容易出现选票僵持的情况,从性能上考虑,使用奇数节点去部署集群是较好的选择。

日志复制

在上面的描述中,当集群选举出节点后,主节点会通过广播心跳到其它节点以保住自己的Leader地位,在这个过程,Leader的心跳包会携带Append Entries,这个Append Entries通常只是作心跳保持使用,但当主节点出现数据变化时,主节点在下一次的心跳中,将数据变化写到Append Entries,其它节点收到后先写到节点日志中,但数据处于uncommit状态,当然,此时主节点的数据也是uncommit,直到收到所有节点的响应,主节点的数据直接转成commit状态。

下一次主节点心跳会告诉其它节点,此数据已处于commit状态,那么其它节点也会将数据设置成commit状态。引时整个集群的数据处于一致性状态,后续再加2走同样的流程,最终集群的某个值都被设置成了7。

网络分区

当一个集群中出现了网络分区,可能会导致整个集群出现多个leader的情况,此时集群的数据一致性如何保证?

假设此时两个客户端分别通过主节点B设置x=3,主节点E设置x=8,那么集群最终x将等于8。因为在网络分区中,占少数节点的主节点因在设置值的时候未能得到大多数节点的回复(集群总节点数在集群设置完毕后就是明确的),因此x=3只是保持一个uncommit状态,并不会真的提交。

当网络恢复时,节点B、A会看到任期更高的主节点,于是将自身设置为Foller,回滚uncommit的数据并去同步主节点的数据。

此时整个集群又回到了一致性的状态。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/132526.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

伪造referer [极客大挑战 2019]Http1

打开题目 没有发现什么&#xff0c;我们查看源代码 在这里我们发现了提示 访问一下页面得到 提示说不能来自于https://Sycsecret.buuoj.cn&#xff0c;我们尝试访问一下这个url 发现访问不了 我们bp抓包一下 伪造个referer头 referer:https://Sycsecret.buuoj.cn 发包过去…

经典的测试开发面试题

1、你在测试中发现了一个bug&#xff0c;但是开发经理认为这不是一个bug&#xff0c;你应该怎样解决&#xff1f; 首先&#xff0c;将问题提交到缺陷管理库进行备案。 然后&#xff0c;要获取判断的依据和标准&#xff1a; 根绝需求说明书&#xff0c;产品说明、设计文档等&…

邻接表储存图实现广度优先遍历(C++)

目录 基本要求&#xff1a; 邻接表的结构体&#xff1a; 图的邻接表创建&#xff1a; 图的广度优先遍历&#xff08;BFS&#xff09;&#xff1a; 邻接表的打印输出&#xff1a; 完整代码&#xff1a; 测试数据&#xff1a; 结果运行&#xff1a; 通过给出的图的顶点和…

Jmeter之Bean shell使用详解

一、什么是Bean Shell BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法; BeanShell是一种松散类型的脚本语言(这点和JS类似); BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性,非常精…

Android---内存泄漏的优化

内存泄漏是一个隐形炸弹&#xff0c;其本身并不会造成程序异常&#xff0c;但是随着量的增长会导致其他各种并发症&#xff1a;OOM&#xff0c;UI 卡顿等。 为什么要将 Activity 单独做预防&#xff1f; 因为 Activity 承担了与用户交互的职责&#xff0c;因此内部需要持有大…

JAVA基础语法编程详解

1 类型转换 描述&#xff1a; 设计一个方法&#xff0c;将一个小于2147483647的double类型变量以截断取整方式转化为int类型输入描述&#xff1a; 随机double类型变量输出描述&#xff1a; 转化后的int类型变量示例 输入&#xff1a;123.45 输出&#xff1a; 123 题解思路&…

吴恩达《机器学习》8-1->8-2:非线性假设、神经元和大脑

一、非线性假设 在之前学到的线性回归和逻辑回归中&#xff0c;存在一个缺点&#xff0c;即当特征数量很多时&#xff0c;计算的负荷会变得非常大。考虑一个例子&#xff0c;假设我们使用 &#x1d465;₁, &#x1d465;₂ 的多项式进行预测&#xff0c;这时我们可以很好地应…

【自定义类型:结构体】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 1. 结构体类型的声明 1.1 结构体的概念 1.2 结构的声明 ​编辑 1.3 特殊的声明 1.4 结构的自引用 2. 结构体变量的创建和初始化 3. 结构成员访问操作符 4. 结构体内…

数据库01-慢查询优化

目录 MySQL优化 慢查询 如何定位慢查询&#xff1f; 如何分析慢查询&#xff1f; MySQL优化 MySQL 优化是数据库管理和应用性能调优的一个重要方面。以下是一些常规性的 MySQL 优化经验和适用场景&#xff1a; 索引优化&#xff1a; 确保表的字段上有适当的索引&#xff0…

如何选择一个可靠的爬虫代理服务商?技术人员都需要知道

我身边从事大数据相关行业的朋友最近告诉我&#xff0c;自己新招的小伙伴工作效率很低&#xff0c;很多最基础的工具都不会选择&#xff0c;经常因为代理IP不可靠导致工作出错。 听完这些我才意识到&#xff0c;在这个大数据时代&#xff0c;还是有很多新手在进行网络爬取任务…

threejs(11)-精通着色器编程(难点)2

一、shader着色器编写高级图案 小日本国旗 precision lowp float; varying vec2 vUv; float strength step(0.5,distance(vUv,vec2(0.5))0.25) ; gl_FragColor vec4(strength,strength,strength,strength);绘制圆 precision lowp float; varying vec2 vUv; float strength 1…

Java中Enum枚举类型在项目中应用

1、什么是枚举类型&#xff1f; 1、枚举的本质就是穷举法&#xff0c;将可能会出现的情况&#xff0c;都列举出来&#xff0c;然后在列举的情况中调用。 2、枚举与class类似&#xff0c;也可以定义属性&#xff0c;构造方法&#xff0c;有getter和setter方法。 3、枚举类型对…

改进YOLOv8:结合ICCV2023|动态蛇形卷积,构建不规则目标识别网络

🔥🔥🔥 提升多尺度、不规则目标检测,创新提升 🔥🔥🔥 🔥🔥🔥 捕捉图像特征和处理复杂图像特征 🔥🔥🔥 👉👉👉: 本专栏包含大量的新设计的创新想法,包含详细的代码和说明,具备有效的创新组合,可以有效应用到改进创新当中 👉👉👉: �…

基于FPGA的PS端的Si5340的控制

1、功能 Si5340/41-D可以输出任意频率&#xff0c;当然有范围&#xff0c;100Hz1GHz。外部输入为24M或者4854M的XTAL&#xff0c;VCO在13500~14256Mhz之间&#xff0c;控制接口采用IIC或者SPI。 芯片架构图 2、IIC控制方式 3、直接上控制代码 使用米联客ZU3EG&#xff0c;将…

spider-node-初识

spider-node spider想解决的问题1&#xff1a;业务架构层面2&#xff1a;代码层面3&#xff1a;业务&#xff0c;产品&#xff0c;研发&#xff0c;测试之间4: 系统迭代成本高 spider-node 配置讲解spider-node启动 spider想解决的问题 1&#xff1a;业务架构层面 帮助研发团队…

C++学习笔记(一):安装VisualStudio和Vcpkg

VisualStudio安装 error C4996: ‘scanf’: This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. #include <stdio.h>int main() {printf("hello"…

如何使用pngPackerGUI_V2.0,将png图片打包成plist的工具

pngPackerGUI_V2.0&#xff0c;此软件是在pngpacker_V1.1软件基础之后&#xff0c;开发的界面化操作软件&#xff0c;方便不太懂命令行的小白快捷上手使用。 具体的使用步骤如下&#xff1a; 1.下载并解压缩软件&#xff0c;得到如下目录&#xff0c;双击打开 pngPackerGUI.e…

iPhone或在2024开放第三方应用商店。

iPhone或开放第三方应用商店&#xff0c;可以说这是一个老生常谈的话题。对于像是iOS这样封闭的系统来说&#xff0c;此前传出苹果可能开放侧载消息的时候&#xff0c;又有谁能信&#xff0c;谁会信&#xff1f; 如果是按照苹果自身的意愿&#xff0c;这种事情自然是不可能发生…

Windows下Python及Anaconda的安装与设置、代码执行之保姆指南

学习Python编程需要安装基本的开发环境。 &#xff08;1&#xff09;python ——编译器&#xff1b;这个是任何语言都需要的&#xff1b;必需&#xff01; &#xff08;2&#xff09;Anaconda ——主要的辅助工具&#xff0c;号称是 Python‘OS&#xff1b;必需&#xff01; …

LeetCode | 234. 回文链表

LeetCode | 234. 回文链表 O链接 这里的解法是先找到中间结点然后再将中间节点后面的节点逆序一下然后再从头开始和从中间开始挨个比较如果中间开始的指针到走最后都相等&#xff0c;就返回true&#xff0c;否则返回false 代码如下&#xff1a; struct ListNode* reverseLis…