共识算法:Raft
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了共识算法:Raft相关的知识,希望对你有一定的参考价值。
参考技术A上篇讲到了「拜占庭将军问题」:多个拜占庭将军要如何在可能有叛徒、信使可能被策反或者暗杀的情况下达成是否要进攻的一致性决定?还不了解的先看看上一篇 《拜占庭将军问题》 。这篇主要是介绍简化版拜占庭将军问题的解决方案:Raft 共识算法。
所以将拜占庭将军问题根据常见的工作上的问题进行简化: 假设将军中没有叛军,信使的信息可靠但有可能被暗杀的情况下,将军们如何达成一致性决定?
对于这个简化后的问题,有许多解决方案,第一个被证明的共识算法是 Paxos,由拜占庭将军问题的作者 Leslie Lamport 在1990年提出,最初以论文难懂而出名,后来这哥们在2001重新发了一篇简单版的论文 Paxos Made Simple ,然而还是挺难懂的。
因为 Paxos 难懂,难实现,所以斯坦福大学的教授在2014年发表了新的分布式协议 Raft。与 Paxos 相比,Raft 有着基本相同运行效率,但是更容易理解,也更容易被用在系统开发上。
我们还是用拜占庭将军的例子来帮助理解 Raft。
Raft 的解决方案大概可以理解成 先在所有将军中选出一个大将军,所有的决定由大将军来做。 选举环节 :比如说现在一共有3个将军 A, B, C,每个将军都有一个 随机时间 的倒计时器,倒计时一结束,这个将军就会把自己当成大将军候选人,然后派信使去问其他几个将军,能不能选我为总将军?假设现在将军A倒计时结束了,他派信使传递选举投票的信息给将军B和C,如果将军B和C还没把自己当成候选人(倒计时还没有结束),并且没有把选举票投给其他,他们把票投给将军A,信使在回到将军A时,将军A知道自己收到了足够的票数,成为了大将军。在这之后,是否要进攻就由大将军决定,然后派信使去通知另外两个将军,如果在一段时间后还没有收到回复(可能信使被暗杀),那就再重派一个信使,直到收到回复。
故事先讲到这里,希望不做技术方面的朋友可以大概能理解 Raft 的原理,下面从比较技术的角度讲讲 Raft 的原理。
从拜占庭将军的故事映射到分布式系统上,每个将军相当于一个分布式网络节点,每个节点有 三种状态:Follower,Candidate,Leader ,状态之间是互相转换的,可以参考下图,具体的后面说。
每个节点上都有一个倒计时器 (Election Timeout),时间随机在 150ms 到 300ms 之间。有几种情况会重设 Timeout:
在 Raft 运行过程中,最主要进行两个活动:
假设现在有如图5个节点,5个节点一开始的状态都是 Follower。
在一个节点倒计时结束 (Timeout) 后,这个节点的状态变成 Candidate 开始选举,它给其他几个节点发送选举请求 (RequestVote)
其他四个节点都返回成功,这个节点的状态由 Candidate 变成了 Leader,并在每个一小段时间后,就给所有的 Follower 发送一个 Heartbeat 以保持所有节点的状态,Follower 收到 Leader 的 Heartbeat 后重设 Timeout。
这是最简单的选主情况, 只要有超过一半的节点投支持票了,Candidate 才会被选举为 Leader ,5个节点的情况下,3个节点 (包括 Candidate 本身) 投了支持就行。
一开始已经有一个 Leader,所有节点正常运行。
Leader 出故障挂掉了,其他四个 Follower 将进行重新选主。
4个节点的选主过程和5个节点的类似,在选出一个新的 Leader 后,原来的 Leader 恢复了又重新加入了,这个时候怎么处理?在 Raft 里,第几轮选举是有记录的,重新加入的 Leader 是第一轮选举 (Term 1) 选出来的,而现在的 Leader 则是 Term 2,所有原来的 Leader 会自觉降级为 Follower
假设一开始有4个节点,都还是 Follower。
有两个 Follower 同时 Timeout,都变成了 Candidate 开始选举,分别给一个 Follower 发送了投票请求。
两个 Follower 分别返回了ok,这时两个 Candidate 都只有2票,要3票才能被选成 Leader。
两个 Candidate 会分别给另外一个还没有给自己投票的 Follower 发送投票请求。
但是因为 Follower 在这一轮选举中,都已经投完票了,所以都拒绝了他们的请求。所以在 Term 2 没有 Leader 被选出来。
这时,两个节点的状态是 Candidate,两个是 Follower,但是他们的倒计时器仍然在运行,最先 Timeout 的那个节点会进行发起新一轮 Term 3 的投票。
两个 Follower 在 Term 3 还没投过票,所以返回 OK,这时 Candidate 一共有三票,被选为了 Leader。
如果 Leader Heartbeat 的时间晚于另外一个 Candidate timeout 的时间,另外一个 Candidate 仍然会发送选举请求。
两个 Follower 已经投完票了,拒绝了这个 Candidate 的投票请求。
Leader 进行 Heartbeat, Candidate 收到后状态自动转为 Follower,完成选主。
以上是 Raft 最重要活动之一选主的介绍,以及在不同情况下如何进行选主。
总结:
1.每个节点一直有一个timeout,timeout结束就开始选自己为主节点;
2.主节点会轮询从节点,从节点更新timeout;
3.选举等级机制;
Raft 在实际应用场景中的一致性更多的是体现在不同节点之间的数据一致性,客户端发送请求到任何一个节点都能收到一致的返回,当一个节点出故障后,其他节点仍然能以已有的数据正常进行。在选主之后的复制日志就是为了达到这个目的。
一开始,Leader 和 两个 Follower 都没有任何数据。
客户端发送请求给 Leader,储存数据 “sally”,Leader 先将数据写在本地日志,这时候数据还是 Uncommitted (还没最终确认,红色表示)
Leader 给两个 Follower 发送 AppendEntries 请求,数据在 Follower 上没有冲突,则将数据暂时写在本地日志,Follower 的数据也还是 Uncommitted。
Follower 将数据写到本地后,返回 OK。Leader 收到后成功返回, 只要收到的成功的返回数量超过半数 (包含Leader) ,Leader 将数据 “sally” 的状态改成 Committed。( 这个时候 Leader 就可以返回给客户端了)
Leader 再次给 Follower 发送 AppendEntries 请求,收到请求后,Follower 将本地日志里 Uncommitted 数据改成 Committed。这样就完成了一整个复制日志的过程,三个节点的数据是一致的,
在 Network Partition 的情况下,部分节点之间没办法互相通信,Raft 也能保证在这种情况下数据的一致性。
一开始有 5 个节点处于同一网络状态下。
Network Partition 将节点分成两边,一边有两个节点,一边三个节点。
两个节点这边已经有 Leader 了,来自客户端的数据 “bob” 通过 Leader 同步到 Follower。
因为只有两个节点,少于3个节点,所以 “bob” 的状态仍是 Uncommitted。所以在这里, 服务器会返回错误给客户端
另外一个 Partition 有三个节点,进行重新选主。客户端数据 “tom” 发到新的 Leader,通过和上节网络状态下相似的过程,同步到另外两个 Follower。
因为这个 Partition 有3个节点,超过半数,所以数据 “tom” 都 Commit 了。
网络状态恢复,5个节点再次处于同一个网络状态下。但是这里出现了数据冲突 “bob" 和 “tom"
三个节点的 Leader 广播 AppendEntries
两个节点 Partition 的 Leader 自动降级为 Follower,因为这个 Partition 的数据 “bob” 没有 Commit,返回给客户端的是错误,客户端知道请求没有成功,所以 Follower 在收到 AppendEntries 请求时,可以把 “bob“ 删除,然后同步 ”tom”,通过这么一个过程,就完成了在 Network Partition 情况下的复制日志,保证了数据的一致性。
Raft 是能够实现分布式系统强一致性的算法,每个系统节点有三种状态 Follower,Candidate,Leader。实现 Raft 算法两个最重要的事是:选主和复制日志
参考链接:
Raft 官网: https://raft.github.io/
Raft 原理动画 (推荐看看): http://thesecretlivesofdata.com/raft/
分布式共识算法——Raft算法(图解)
文章目录
Raft 算法
Raft 算法概念
Raft 是一种分布式一致性算法。Raft 出现之前,Paxos 一直是分布式一致性算法的标准。
Paxos 难以理解,更难以实现。Raft 的设计目标是简化 Paxos,使得算法既容易理解,也容易实现。
Paxos 和 Raft 都是分布式一致性算法,这个过程如同投票选举领袖(Leader),参选者(Candidate)需要说服大多数投票者(Follower)投票给他,一旦选举出领袖,就由领袖发号施令。Paxos 和 Raft 的区别在于选举的具体过程不同。
Paxos 和 Raft 都是分布式一致性算法,这个过程如同投票选举领袖(Leader),参选者(Candidate)需要说服大多数投票者(Follower)投票给他,一旦选举出领袖,就由领袖发号施令。Paxos 和 Raft 的区别在于选举的具体过程不同。
Raft 可以解决分布式 CAP 理论中的 CP,即 一致性(C:Consistency) 和 分区容忍性(P:Partition Tolerance),并不能解决 可用性(A:Availability) 的问题。
Raft 角色
一个 Raft 集群包含若干节点,Raft 把这些节点分为三种状态:Leader、 Follower、Candidate,每种状态负责的任务也是不一样的。正常情况下,集群中的节点只存在 Leader 与 Follower 两种状态。
- Leader(领导者) :负责日志的同步管理,处理来自客户端的请求,与Follower保持heartBeat的联系;
- Follower(追随者) :响应 Leader 的日志同步请求,响应Candidate的邀票请求,以及把客户端请求到Follower的事务转发(重定向)给Leader;
- Candidate(候选者) :Leader选举过程中的临时角色。负责选举投票,集群刚启动或者Leader宕机时,状态为Follower的节点将转为Candidate并发起选举,选举胜出(获得超过半数节点的投票)后,从Candidate转为Leader状态。
Raft 算法流程
通常,Raft 集群中只有一个 Leader,其它节点都是 Follower。Follower 都是被动的,不会发送任何请求,只是简单地响应来自 Leader 或者 Candidate 的请求。Leader 负责处理所有的客户端请求(如果一个客户端和 Follower 联系,那么 Follower 会把请求重定向给 Leader)。
针对以上分析,可以将整个 Raft 算法分解为三部分:
Leader 选举:当 Leader 宕机或者集群初创时,一个新的 Leader 需要被选举出来;
Leader 选举要点如下:
-
只有一个 Server 能作为 Leader
-
一旦此 Server 崩溃,选举新 Leader
执行操作(日志复制):Leader 接收来自客户端的请求并将其以日志条目的形式复制到集群中的其它节点,并且强制要求其它节点的日志和自己保持一致;
日志复制要点如下:
-
由 Leader 执行自己的日志记录
-
将日志复制到其它 Server,会覆盖掉不一致的部分
-
多数派记录日志成功,Leader 才能执行命令,向客户端返回结果
确保安全:如果有任何的服务器节点已经应用了一个确定的日志条目到它的状态机中,那么其它服务器节点不能在同一个日志索引位置应用一个不同的指令。
确保安全要点如下:
-
保证日志记录的一致性
-
拥有最新日志的 Server 才能成为 Leader
Raft 算法原理
角色关系
Follower 只响应来自其他服务器的请求。在一定时限内,如果 Follower 接收不到消息,就会转变成 Candidate,并发起选举。
Candidate 向 Follower 发起投票请求,如果获得集群中半数以上的选票,就会转变为 Leader。
在一个 Term(任期,下面讲) 内,Leader 始终保持不变,直到下线了。Leader 需要周期性向所有 Follower 发送心跳消息,以阻止 Follower 转变为 Candidate。
任期原理
Raft 把时间分割成任意长度的 任期(Term),任期用连续的整数标记。每一段任期从一次选举开始。Raft 保证了在一个给定的任期内,最多只有一个领导者。
任期(Term)与领导者(Leader)选举过程中会出现两种情况:
-
如果选举成功,Leader 会管理整个集群直到任期结束。
-
如果选举失败,那么这个任期就会因为没有 Leader 而结束。
例如下图,存在没有Leader和有Leader两种强开
并且不同服务器节点观察到的任期转换状态可能不一样:
-
服务器节点可能观察到多次的任期转换。
-
服务器节点也可能观察不到任何一次任期转换。
任期在 Raft 算法中充当逻辑时钟的作用,使得服务器节点可以查明一些过期的信息(比如过期的 Leader)。每个服务器节点都会存储一个当前任期号,这一编号在整个时期内单调的增长。当服务器之间通信的时候会交换当前任期号。
- 如果一个服务器的当前任期号比其他人小,那么他会更新自己的编号到较大的编号值。
- 如果一个 Candidate 或者 Leader 发现自己的任期号过期了,那么他会立即恢复成跟随者状态。
- 如果一个节点接收到一个包含过期的任期号的请求,那么他会直接拒绝这个请求。
数据可视化的应用场景越来越广泛,数据可以呈现为更多丰富的可视化形式,使用户能够更加轻易、便捷的获取并理解数据传达的信息。
通信原理
Raft 算法中服务器节点之间的通信使用 远程过程调用(RPC)。
基本的一致性算法只需要两种RPC:
- RequestVote RPC - 请求投票 RPC,由 Candidate 在选举期间发起。
- AppendEntries RPC - 附加条目 RPC,由 Leader 发起,用来复制日志和提供一种心跳机制。
图解算法流程
图解学习网站:https://raft.github.io/raftscope/index.html
选举过程
-
Leader 会不断向选民发送 AppendEntries 请求,证明自己活着
-
选民收到 Leader AppendEntries 请求后会重置自己的 timeout 时间
- 选民收不到 AppendEntries 请求超时后,转换角色为候选者,并将任期加1,发送 RequestVote 请求,推选自己
- 选民收到第一个 RequestVote,会向该候选者投一票,这样即使有多个候选者,必定会选出一个 Leader,选票过半即当选,如果落选会变回选民
-
每一任期最多有一个 Leader,但也可能没有(选票都不过半的情况,需要再进行一轮投票,timeout 在 T~2T 间随机)
-
任期由各个 server 自己维护即可,无需全局维护,在超时后加1,在接收到任意消息时更新为更新的任期,遇到更旧的任期,视为错误
执行操作过程(日志复制)
- 客户端发送命令至 Leader
- Leader 将命令写入日志(S1虚框),并向所有选民发送 AppendEntries 请求
- 多数派通过后,执行命令(即提交,S1虚框变实),此时就可以向客户端返回结果
- 在后续的 AppendEntries 请求中通知选民,选民执行命令(即提交,S2,S3,S4,S5虚框变实)
- 如果选民挂了,则 Leader 会不断尝试,待到选民重启,会将其缺失的日志陆续补齐
确保安全
Leader 日志的完整性
- Leader 被认为拥有最完整的日志
- 一旦 Leader 完成了某条命令提交,那么未来的 Leader 也必须存有该条命令提交信息
- 投票时,会将候选者最新的
<Term,Index>
随 RequestVote 请求发送,如果候选者的日志还没选民的新,则投否决票
- 图中 S2 如果超时,发起选举请求,其它服务器只会对它投否决票,因为它的 Index 比其它人都旧
- 图中 S5 如果超时,发起选举请求,其它服务器也不会选它,因为他的 Term 太旧
选民日志的一致性
-
以 Leader 为准,对选民的日志进行补充或覆盖
-
AppendEntries 请求发送时会携带最新的
<Term,Index,Command>
以及上一个的<Term,Index>
-
如果选民发现上一个的
<Term,Index>
能够对应上则成功,否则失败,继续携带更早的信息进行比对
- 图中 Leader 发送了
<3,4,Command>
和<2,3>
给 follower,follower 发现<2,3>
能够与当前最新日志对应,这时直接执行<3,4,Command>
即可
- 图中 Leader 发送了
<3,4,Command>
和<2,3>
给 follower,follower 发现<2,3>
不能与当前最新日志对应,会央求 Leader 发送更早日志
- Leader 这次发送了
<3,4,Command>
,<2,3,Command>
,<1,2>
给 follower,follower 发现<1,2>
能够与当前最新日志对应,这时补全<3,4,Command>
,<2,3,Command>
即可
以上是关于共识算法:Raft的主要内容,如果未能解决你的问题,请参考以下文章