Raft论文概述
介绍
Raft是一种为了管理复制日志的一致性算法。为了提升可理解性,Raft 将一致性算法分解成了几个关键模块,例如领导人选举、日志复制和安全性。同时它通过实施一个更强的一致性来减少需要考虑的状态的数量。同时,raft还提供了集群变更的应对方法。
Raft独有特性:
- 强领导者:日志条目只从领导者发送给其他的服务器
- 领导选举:Raft 算法使用一个随机计时器来选举领导者
- 关系调整:Raft 使用一种共同一致的方法来处理集群成员变换的问题
Raft一致性算法
Raft 基础
一个 Raft 集群包含若干个服务器节点;通常是 5 个,这允许整个系统容忍 2 个节点的失效。
- 领导者:领导人处理所有的客户端请求(如果一个客户端和跟随者联系,那么跟随者会把请求重定向给领导人)。
- 跟随者:他们不会发送任何请求,只是简单的响应来自领导者或者候选人的请求。
- 候选人,选举新领导人时使用
一些相关状态
状态 | 所有服务器上持久存在的 |
---|---|
currentTerm | 服务器最后一次知道的任期号(初始化为 0,持续递增) |
votedFor | 在当前获得选票的候选人的 Id |
log[] | 日志条目集;每一个条目包含一个用户状态机执行的指令,和收到时的任期号 |
状态 | 所有服务器上经常变的 |
---|---|
commitIndex | 已知的最大的已经被提交的日志条目的索引值 |
lastApplied | 最后被应用到状态机的日志条目索引值(初始化为 0,持续递增) |
状态 | 在领导人里经常改变的 (选举后重新初始化) |
---|---|
nextIndex[] | 对于每一个服务器,需要发送给他的下一个日志条目的索引值(初始化为领导人最后索引值加一) |
matchIndex[] | 对于每一个服务器,已经复制给他的日志的最高索引值 |
所有服务器需遵守的规则
所有服务器:
if(commitIndex > lastApplied){
那么就 lastApplied 加一,并把log[lastApplied]应用到状态机中;
}
if(T > currentTerm){
currentTerm 等于 T,并切换状态为跟随者
}
跟随者
- 响应来自候选人和领导者的请求;
- 如果在超过选举超时时间的情况之前都没有收到领导人的心跳,或者是候选人请求投票的,就自己变成候选人
候选人
- 在转变成候选人后就立即开始选举过程
- 自增当前的任期号(currentTerm)
- 给自己投票
- 重置选举超时计时器
- 发送请求投票的 RPC 给其他所有服务器
- 如果接收到大多数服务器的选票,那么就变成领导人
- 如果接收到来自新的领导人的附加日志 RPC,转变成跟随者
- 如果选举过程超时,再次发起一轮选举
领导人
- 一旦成为领导人:发送空的附加日志 RPC(心跳)给其他所有的服务器;在一定的空余时间之后不停的重复发送,以阻止跟随者超时
- 如果接收到来自客户端的请求:附加条目到本地日志中,在条目被应用到状态机后响应客户端
- 如果对于一个跟随者,最后日志条目的索引值大于等于nextIndex,发送从 nextIndex 开始的所有日志条目
- 如果成功:更新相应跟随者的 nextIndex 和 matchIndex
- 如果因为日志不一致而失败,减少 nextIndex 重试
领导人选举
如果跟随者一段时间没有接受到Leader的任何消息,开始超时选举。竞选者增加当前term号,向其他节点请求选票。他保持当前状态,直到以下三种情况发生。
- 赢得本次选举
- 其它服务器赢得选举
- 选举超时
请求投票 RPC
参数 | 解释 |
---|---|
term | 候选人的任期号 |
candidateId | 请求选票的候选人的 Id |
lastLogIndex | 候选人的最后日志条目的索引值 |
lastLogTerm | 候选人最后日志条目的任期号 |
返回值 | 解释 |
---|---|
term | 当前任期号,以便于候选人去更新自己的任期号 |
voteGranted | 候选人赢得了此张选票时为真 |
接收者实现:
if(term < currentTerm){
return false;
}
//先来先投票原则,并且只投票给大多数
if(voteFor为空 || 参与者就是接收者){
if(候选人的日志和自己的一样新)
return true;
}
日志复制
日志遵循一下特性:
- 如果在不同的日志中的两个条目拥有相同的索引和任期号,那么他们存储了相同的指令
- 如果在不同的日志中的两个条目拥有相同的索引和任期号,那么他们之前的所有日志条目也全部相同
第一个特性来自这样的一个事实,领导人最多在一个任期里在指定的一个日志索引位置创建一条日志条目,同时日志条目在日志中的位置也从来不会改变。第二个特性由附加日志 RPC 的一个简单的一致性检查所保证。在发送附加日志 RPC 的时候,领导人会把新的日志条目紧接着之前的条目的索引位置和任期号包含在里面。如果跟随者在它的日志中找不到包含相同索引位置和任期号的条目,那么他就会拒绝接收新的日志条目。
附加日志 RPC
由领导人负责调用来复制日志指令;也会用作heartbeat
参数 | 解释 |
---|---|
term | 领导人的任期号 |
leaderId | 领导人的 Id,以便于跟随者重定向请求 |
prevLogIndex | 新的日志条目紧随之前的索引值 |
prevLogTerm | prevLogIndex 条目的任期号 |
entries[] | 准备存储的日志条目(表示心跳时为空;一次性发送多个是为了提高效率) |
leaderCommit | 领导人已经提交的日志的索引值 |
返回值 | 解释 |
---|---|
term | 当前的任期号,用于领导人去更新自己 |
success | 跟随者包含了匹配上 prevLogIndex 和 prevLogTerm 的日志时为真 |
//接收者实现:
//Leader肯定有最大的term
if (term < currentTerm)
return false;
if(prevLogIndex位置上的term和prevLogTerm不匹配){
删除这一条之后所有的日志;
return false;
}
附加任何在已有的日志中不存在的条目;
if(leaderCommit > commitIndex){
leaderCommit = min(leaderCommit, 新日志条目索引值);
}
return true;
安全性
选举限制
Raft 使用投票的方式来阻止候选人赢得选举除非这个候选人包含了所有已经提交的日志条目。
- 如果两份日志最后的条目的任期号不同,那么任期号大的日志更加新。
- 如果两份日志最后的条目任期号相同,那么日志比较长的那个就更加新。
提交之前任期内的日志条目
主要是对commit的定义:只有它自己提交当前term号的操作才能将之前的日志看作是真正的可以提交。
一个领导人不能断定一个之前任期里的日志条目被保存到大多数服务器上的时候就一定已经提交了。
- (a) 中,S1 是领导者,部分的复制了索引位置 2 的日志条目。
- (b) 中,S1 崩溃了,然后 S5 在任期 3 里通过 S3、S4 和自己的选票赢得选举,然后从客户端接收了一条不一样的日志条目放在了索引 2 处。
- (c),S5 又崩溃了;S1 重新启动,选举成功,开始复制日志。在这时,来自任期 2 的那条日志已经被复制到了集群中的大多数机器上,但是还没有被提交。
- 如果 S1 在 (d) 中又崩溃了,S5 可以重新被选举成功(通过来自 S2,S3 和 S4 的选票),然后覆盖了他们在索引 2 处的日志。但是,在崩溃之前,如果 S1 在自己的任期里复制了日志条目到大多数机器上
- 如 (e) 中,然后这个条目就会被提交(S5 就不可能选举成功)。 在这个时候,之前的所有日志就会被正常提交处理。
图中展示了一种情况,一条已经被存储到大多数节点上的未提交的老日志条目(这不是废话吗?),也依然有可能会被未来的领导人覆盖掉。
只有它自己提交当前term的操作才能看作是真正的提交。(leader只有提交了当前term号的日志后才能将之前的日志应用到状态机)
成员组变更
成员组变更的难点
- 成员组正常Paxos日志同步服务不中断
- 任何情况下宕机都能够保证存活的多数派成员间能够选举leader
- 不会出现1个以上的多数派选出大于1个leader的情况
基本思路
- “旧朝代”的多数派成员对“旧朝代结束”这件事达成一致,达成一致后旧成员组不再投票
- “新朝代”的多数派成员对“新朝代开启”这件事达成一致,达成一致后新成员组开始投票
上面的思路可以满足难点3,但是不能满足难点1,2。比如Pa执行成功后,在Pb执行成功之前:没有成员组可以投票,服务会中断;如果集群宕机重启,新的成员组的各个成员由于还未对新成员组达成一致,而无法选出leader。
Joint-Consensus
通用成员组变更方法--Joint-Consensus
- 变更操作
- 成员变更操作前,C(old)的多数派中持久化的成员组为[[C(old)]]
- 成员变更操作由leader执行,leader收到命令后,将成员组[[C(old),C(new)]]发送给C(old)∪C(new)的所有成员,在此之后新的日志同步需要保证得到C(old)和C(new)两个多数派的确认
- leader收到C(old)和C(new)两个多数派确认后,将成员组[[C(new)]]发送给C(new)的所有成员,收到C(new)多数派确认后,表示成员变更成功,后续的日志只要得到C(new)多数派确认即可
- 投票规则
- 持有[[C(old),C(new)]]的候选人要得到C(old)和C(new)两个多数派都确认,才能当选leader
- 持有[[C(old)]]的候选人要得到C(old)多数派确认,才能当选leader
- 持有[[C(new)]]的候选人要得到C(new)多数派确认,才能当选leader
总结
- 领导者选举
- 普通附加操作
- 安全性和一致性
- 平衡旧领导者:出现网络分区,通过Term号使旧领导者变为follower
- 客户端交互:只有leader和客户端交互
- 更改配置
Raft论文概述的更多相关文章
- 【转】分布式一致性算法:Raft 算法(Raft 论文翻译)
编者按:这篇文章来自简书的一个位博主Jeffbond,读了好几遍,翻译的质量比较高,原文链接:分布式一致性算法:Raft 算法(Raft 论文翻译),版权一切归原译者. 同时,第6部分的集群成员变更读 ...
- raft 论文
raft 论文,摘自 http://www.infoq.com/cn/articles/raft-paper raft动画:https://raft.github.io/ raft说明动画:
- Raft论文《 In Search of an Understandable Consensus Algorithm (Extended Version) 》研读
Raft 论文研读 说明:本文为论文 < In Search of an Understandable Consensus Algorithm (Extended Version) > 的 ...
- Raft论文的一些问题
抛些问题出来,真正解释了这些问题才算理解了论文.:) 1. 什么是复制状态机 2. Raft vs Paxos 3. Raft的设计目标understandability,为达到设计目标在做设计时如何 ...
- Raft论文学习笔记
先附上论文链接 https://pdos.csail.mit.edu/6.824/papers/raft-extended.pdf 最近在自学MIT的6.824分布式课程,找到两个比较好的githu ...
- 从raft论文出发
介绍 Raft是一种为了管理复制日志的一致性算法.为了提升可理解性,Raft 将一致性算法分解成了几个关键模块,例如领导人选举.日志复制和安全性.同时它通过实施一个更强的一致性来减少需要考虑的状态的数 ...
- 分布式一致性算法:Raft 算法(论文翻译)
Raft 算法是可以用来替代 Paxos 算法的分布式一致性算法,而且 raft 算法比 Paxos 算法更易懂且更容易实现.本文对 raft 论文进行翻译,希望能有助于读者更方便地理解 raft 的 ...
- Raft概述
Raft 1. 概述 Raft是一种一致性(共识)算法,相比Paxos,Raft更容易理解和实现,它将分布式一致性问题分解成多个子问题,Leader选举(Leader election).日志复制(L ...
- 学习Raft算法的笔记
Raft是一种为了管理日志复制的一致性算法.它提供了和Paxos算法相同的功能和性能,但是它的算法结构和Paxos不同,使得Raft算法更加容易理解并且更容易构建实际的系统.为了提升可理解性,Raft ...
随机推荐
- 洛谷 P3647 [APIO2014]连珠线(换根 dp)
题面传送门 题意: 桌子上有 \(1\) 个珠子,你要进行 \(n-1\) 次操作,每次操作有以下两种类型: 拿出一个新珠子,并选择一个桌子上的珠子,在它们之间连一条红线 选择两个由红线相连的珠子 \ ...
- C/C++ Qt TabWidget 实现多窗体创建
在开发窗体应用时通常会伴随分页,ToolBar组件可以实现顶部工具栏菜单,每一个ToolBar组件关联到一个TabWidget组件的Tab标签内,这样我们就可以实现一个复杂的多窗体分页结构,此类结构也 ...
- 毕业设计之zabbix---自带模板监控mysql内容
自带模板是不能直接建立连接就可以用的 必须经历一下几步: 建立用户权限: [root@mysql.quan.bbs lib]$mysql -u root -p Enter password: Welc ...
- mysql优化方法陈列
高并发大多的瓶颈在后台,在存储,mysql的正常的优化方案如下: 1)代码中sql语句优化 2)数据库字段优化,索引优化 3)加缓存,redis/memcache等 4)主从,读写分离 5)分区表 6 ...
- Python3编译安装ssl模块问题
本文以Centos系统为例 1.确保linux系统中安装了ssl-devel包 2.编译安装ssl模块到Python3中 1.查看linux系统中是否安装了ssl-devel包 # 查看命令 rpm ...
- Spark基础:(四)Spark 数据读取与保存
1.文件格式 Spark对很多种文件格式的读取和保存方式都很简单. (1)文本文件 读取: 将一个文本文件读取为一个RDD时,输入的每一行都将成为RDD的一个元素. val input=sc.text ...
- entfrm-app赋能entfrm零代码开发平台 开启多平台分发
entfrm-app是基于uni-app 框架.使用 Vue.js 语法开发的移动端 App开源产品.它可以编译为 H5.IOS App.Android App.微信小程序.QQ小程序.钉钉小程序.支 ...
- SQL错误总结
ORA-00918: column ambiguously defined 异常原因: select 查询的字段在from的两张表中都存在,导致数据库无法区别需要查询的字段来自于哪张表 以下是例子 s ...
- 那些年采的python的坑
1:使用virtualenvwrapper 新建虚拟环境时出现的错误 OSError: Command D:\file\python\virtu...r\Scripts\python.exe - se ...
- 10.Vue.js 样式绑定
Vue.js 样式绑定 Vue.js class class 与 style 是 HTML 元素的属性,用于设置元素的样式,我们可以用 v-bind 来设置样式属性. Vue.js v-bind 在处 ...