分布式一致性算法
sschrodinger
2019/07/17
一个分布式系统 不可能同时满足 一致性( C:Consistency ),可用性( A: Availability )和分区容错性( P:Partition tolerance )这三个基本需求, 最多只能同时满足其中的 2 个 。
如下:
base 是 Basically Available (基本可用) ,Soft state (软状态),和 Eventually consistent (最终一致性)三个短语的缩写。
既是无法做到 强一致性 ( Strong consistency ),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到 最终一致性 ( Eventual consistency )
基本可用
允许出现响应时间损失或者功能损失。
软状态
允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即 允许系统在多个不同节点的数据副本存在数据延时 。
最终一致性
系统能够保证 在没有其他新的更新操作 的情况下,数据最终一定能够达到一致的状态,因此所有客户端对系统的数据访问 最终都能够获取到最新的值 。
在分布式系统中,会有多个机器节点,因此需要一个 “ 协调者 ” ,而各个节点就是 “ 参与者 ”,协调者统一调度所有分布式节点的执行逻辑,这些被调度的分布式节点就是 “参与者”。
阶段一
阶段一主要是询问参与者是否可以进行提交。
阶段二
阶段二会根据阶段一的投票结果执行两种操作: 执行事务提交 , 回滚事务 。
执行事务提交步骤如下:
中断事务步骤如下:
优点
原理简单,实现方便
缺点
同步阻塞,单点问题,数据不一致,过于保守
2PC (两阶段提交协议)
三阶段提交协议在协调者和参与者中都引入 超时机制 ,并且把两阶段提交协议的***个阶段拆分成了两步:询问,然后再锁资源,最后真正提交。
协调流程如下:
阶段一: CanCommit
阶段二:preCommit
协调者在得到所有参与者的响应之后,会根据结果执行2种操作:执行 事务预提交 ,或者 中断事务 。
执行事务预提交分为 3 个步骤:
中断事务也分为2个步骤:
阶段三:doCommit
该阶段做真正的提交,同样也会出现两种情况:
执行提交
中断事务
假设有任何参与者反馈了 no 响应,或者超时了,就中断事务。
优点
缺点
如果参与者收到了 preCommit 消息后,出现了网络分区,那么参与者等待超时后,都会进行事务的提交,这必然会出现事务不一致的问题
3PC(三阶段提交协议)
paxos 算法保证了一致性 。
在一个分布式系统中,有一组的 process,每个 process 都可以提出一个 value,consensus 算法就是用来从这些 values 里选定一个最终 value。如果没有 value 被提出来,那么就没有 value 被选中;如果有1个 value 被选中,那么所有的 process 都应该被通知到。
在 2PC 或者 3PC 中,如果协调者宕机了,整个系统就宕机了,这个时候就需要引用多个协调者,paxos 就是用来协调协调者的协议。
首先将议员的角色分为 proposers , acceptors ,和 learners (允许身兼数职)。 proposers 提出提案,提案信息包括提案编号和提议的 value ; acceptor 收到提案后可以接受( accept )提案,若提案获得多数派( majority )的 acceptors 的接受,则称该提案被批准( chosen ); learners 只能“学习”被批准的提案。划分角色后,就可以更精确的定义问题:
通过不断加强上述3个约束(主要是第二个)获得了 Paxos 算法。
批准 value 的过程中,首先 proposers 将 value 发送给 acceptors ,之后 acceptors 对 value 进行接受( accept )。为了满足只批准一个 value 的约束,要求经“多数派( majority )”接受的 value 成为正式的决议(称为“批准”决议)。这是因为无论是按照人数还是按照权重划分,两组“多数派”至少有一个公共的 acceptor ,如果每个 acceptor 只能接受一个 value ,约束 2 就能保证。
于是产生了一个显而易见的新约束:
注意 P1 是不完备的。 如果恰好一半 acceptor 接受的提案具有 value A ,另一半接受的提案具有 value B ,那么就无法形成多数派 ,无法批准任何一个 value 。
约束 2 并不要求只批准一个提案 ,暗示可能存在多个提案。 只要提案的 value 是一样的,批准多个提案不违背约束 2 。于是可以产生约束 P2:
如果 P1 和 P2 都能够保证,那么约束 2 就能够保证。
批准一个 value 意味着多个 acceptor 接受( accept )了该 value 。因此,可以对 P2 进行加强:
由于通信是异步的,P2a 和 P1 会发生冲突。如果一个 value 被批准后,一个 proposer 和一个 acceptor 从休眠中苏醒,前者提出一个具有新的 value 的提案。根据 P1,后者应当接受,根据 P2a,则不应当接受,这种场景下 P2a 和 P1 有矛盾。于是需要换个思路,转而对 proposer 的行为进行约束:
由于 acceptor 能接受的提案都必须由 proposer 提出,所以 P2b 蕴涵了 P2a,是一个更强的约束。
但是根据 P2b 难以提出实现手段。因此需要进一步加强 P2b。
假设一个编号为 m 的 value v 已经获得批准( chosen ),来看看在什么情况下对任何编号为 n ( n m )的提案都含有 value v 。因为 m 已经获得批准( chosen ),显然存在一个 acceptors 的多数派 C ,他们都接受( accept )了 v 。考虑到任何多数派都和 C 具有至少一个公共成员,可以找到一个蕴涵 P2b 的约束 P2c:
如果一个没有 chose 过任何 proposer 提案的 acceptor 在 prepare 过程中接受了一个 proposer 针对提案 n 的问题,但是在开始对 n 进行投票前,又接受( accept )了编号小于n的另一个提案(例如 n-1 ),如果 n-1 和 n 具有不同的 value ,这个投票就会违背 P2c。因此在 prepare 过程中, acceptor 进行的回答同时也应包含承诺:不会再接受( accept )编号小于 n 的提案。这是对 P1 的加强:
通过一个决议分为两个阶段:
prepare 阶段
proposer 选择一个提案编号 n 并将 prepare 请求发送给 acceptors 中的一个多数派;
acceptor 收到 prepare 消息后,如果提案的编号大于它已经回复的所有 prepare 消息(回复消息表示接受 accept ),则 acceptor 将自己上次接受的提案回复给 proposer ,并承诺不再回复小于 n 的提案;
批准阶段
当一个 proposer 收到了多数 acceptors 对 prepare 的回复后,就进入批准阶段。 它要向回复 prepare 请求的 acceptors 发送 accept 请求,包括编号 n 和根据 P2c 决定的 value (如果根据 P2c 没有已经接受的 value ,那么它可以自由决定 value ) 。
在不违背自己向其他 proposer 的承诺的前提下, acceptor 收到 accept 请求后即批准这个请求。
这个过程在任何时候中断都可以保证正确性。例如如果一个 proposer 发现已经有其他 proposers 提出了编号更高的提案,则有必要中断这个过程。因此为了优化,在上述 prepare 过程中,如果一个 acceptor 发现存在一个更高编号的提案,则需要通知 proposer ,提醒其中断这次提案。
一个实例如下:
在这之后,提议者还需要做一件事,就是告知D,E,被决定的决议已经是什么了。即可。
这个过程叫 Learn 。 D , E 被称为 Learner .
Paxos VS Zab
wiki 百科
维基百科-paxos
对于 paxos 来说,每一个议案都要经过不同节点的提出,并且讨论,在提出一个议案的阶段,另外的提议会被否决,导致了性能的低下。
ZAB 协议是为分布式协调服务 Zookeeper 专门设计的一种支持 崩溃恢复 和 原子广播 协议。
基于该协议, Zookeeper 实现了一种 主备模式 的系统架构来保持集群中各个副本之间数据一致性。具体如下图所示:
即只有一个 proposal 可以提出提议,其他的进程都只能复制决议。
所有客户端写入数据都是写入到 主进程(称为 Leader )中,然后,由 Leader 复制到备份进程(称为 Follower )中。从而保证数据一致性。
ZAB 协议的消息广播过程使用的是一个原子广播协议,类似一个 二阶段提交过程 。但是只需要 Follower 有一半以上返回 Ack 信息就可以执行提交,大大减小了同步阻塞。也提高了可用性。
对于客户端发送的写请求,全部由 Leader 接收, Leader 将请求封装成一个事务 Proposal ,将其发送给所有 Follwer ,然后,根据所有 Follwer 的反馈,如果超过半数成功响应,则执行 commit 操作(先提交自己,再发送 commit 给所有 Follwer )。
流程如下:
Leader 挂了之后, ZAB 协议就自动进入崩溃恢复模式,选举出新的 Leader ,并完成数据同步,然后退出崩溃恢复模式进入消息广播模式。
可能 Leader 遇到如下异常情况:
***种情况 主要是当 leader 收到合法数量 follower 的 ACKs 后,就向各个 follower 广播 COMMIT 命令,同时也会在本地执行 COMMIT 并向连接的客户端返回「成功」。 但是如果在各个 follower 在收到 COMMIT 命令前 leader 就挂了,导致剩下的服务器并没有执行都这条消息。
为了实现已经被处理的消息不能丢这个目的,Zab 的恢复模式使用了以下的策略:
第二种情况 主要是当 leader 接收到消息请求生成 proposal 后就挂了,其他 follower 并没有收到此 proposal ,因此经过恢复模式重新选了 leader 后,这条消息是被跳过的( 其他机器日志中没有这一条记录,但是他的日志中有这一条记录 )。 此时,之前挂了的 leader 重新启动并注册成了 follower ,他保留了被跳过消息的 proposal 状态,与整个系统的状态是不一致的, 需要将其删除 。
Zab 通过巧妙的设计 zxid 来实现这一目的。一个 zxid 是 64 位,高 32 是纪元( epoch )编号,每经过一次 leader 选举产生一个新的 leader ,新 leader 会将 epoch + 1 。低 32 位是消息计数器,每接到一个消息,则 $lo^{32} + 1$ ,新 leader 选举后这个值重置为 0。这样设计的好处是旧的 leader 挂了后重启,它不会被选举为 leader ,因为此时它的 zxid 肯定小于当前的新 leader 。当旧的 leader 作为 follower 接入新的 leader 后,新的 leader 会让它将所有的拥有旧的 epoch 未被 COMMIT 的 proposal 清除。
Zookeeper系列(5)--ZAB协议,消息广播,崩溃恢复,数据同步
Raft是用于管理复制日志的一致性算法,raft 协议也是一个 主备模型 ,有一个唯一的 leader 控制任务的提交。
如下是一个 raft 协议中每一个节点可能存在的状态,主要分为 领袖 、 群众 和 候选人 。
raft 最关键的一个概念是任期,每一个 leader 都有自己的任期,必须在任期内发送心跳信息给 follower 来延长自己的任期。
Raft 协议强依赖 Leader 节点的可用性来确保集群数据的一致性 。 数据的流向只能从 Leader 节点向 Follower 节点转移 。当 Client 向集群 Leader 节点提交数据后, Leader 节点接收到的数据处于 未提交状态( Uncommitted ) ,接着 Leader 节点会 并发向所有 Follower 节点复制数据 并等待接收响应,确保 至少集群中超过半数节点 已接收到数据后再向 Client 确认数据已接收。一旦向 Client 发出数据接收 Ack 响应后,表明此时数据状态进入已提交( Committed ), Leader 节点再向 Follower 节点发通知告知该数据状态已提交。
在数据同步阶段,可能出现七种情况:
动画演示 raft 算法
动画演示 raft 算法 - 2
Raft Vs zab
NWR 是一种在分布式存储系统中用于控制一致性级别的一种策略。在 Amazon 的 Dynamo 云存储系统中,就应用 NWR 来控制一致性。
让我们先来看看这三个字母的含义:
在分布式系统中, 数据的单点是不允许存在的 。即线上正常存在的 Replica 数量是 1 的情况是非常危险的,因为一旦这个 Replica 再次错误,就 可能发生数据的永久性错误。假如我们把 N 设置成为 2,那么,只要有一个存储节点发生损坏,就会有单点的存在。所以 N 必须大于 2。N约高,系统的维护和整体 成本就越高。工业界通常把 N 设置为3。
当 W 是 2、R 是 2 的时候, W+RN ,这种情况对于客户端就是强一致性的。
在具体实现系统时,仅仅依靠 NWR 协议还不能完成一致性保证,因为在上述过程中,当读取到多个备份数据时,需要判断哪些数据是最新的,如何判断数据的新旧?这需要向量时钟来配合,所以对于 Dynamo 来说,是通过NWR协议结合向量时钟来共同完成一致性保证的。
详解分布式共识(一致性)算法Raft
所谓分布式共识(consensus),与 CAP理论 中的一致性(consistency)其实是异曲同工,就是在分布式系统中,所有节点对同一份数据的认知能够达成一致。保证集群共识的算法就叫共识算法,它与一致性协议这个词也经常互相通用。
当今最著名的共识算法就是Paxos算法。它由Leslie Lamport在1990年提出,很长时间以来都是一致性的事实标准。但是它有两个不小的缺点:难以理解和证明,难以在实际工程中实现。Google Chu***y的工程师就曾有以下的评论:
于是2014年,来自斯坦福的两位大佬Diego Ongaro与John Ousterhout通过论文 《In Search of an Understandable Consensus Algorithm》 提出了一个新的共识算法Raft。从题目就可以看出,Raft的特点就是容易理解,在此基础上也容易实现,因此在real world中,它的应用也比Paxos要广泛,比较有名的如etcd、Kudu等。
Raft为了达到易懂易用的目标,主要做了两件事:一是分解问题(decomposition),即将复杂的分布式共识问题拆分为 领导选举 (leader election)、 日志复制 (log replication)和 安全性 (safety)三个子问题,并分别解决;二是压缩状态空间(state space reduction),相对于Paxos算法而言施加了更合理的限制,减少因为系统状态过多而产生的不确定性。
下面先简要介绍共识算法的基础——复制状态机,然后就来按顺序研究Raft是如何解决三个子问题的。
在共识算法中,所有服务器节点都会包含一个有限状态自动机,名为复制状态机(replicated state machine)。每个节点都维护着一个复制日志(replicated logs)的队列,复制状态机会按序输入并执行该队列中的请求,执行状态转换并输出结果。可见,如果能保证各个节点中日志的一致性,那么所有节点状态机的状态转换和输出也就都一致。共识算法就是为了保障这种一致性的,下图示出简单的复制状态机及其相关架构。
根据分布式系统的 Quorum机制 与NRW算法,集群中半数以上节点可用时,就能正确处理分布式事务,因此Raft集群几乎都使用奇数节点,可以防止脑裂并避免浪费资源。采用ZAB协议的ZooKeeper集群也是如此。
在Raft集群中,任意节点同一时刻只能处于领导者(leader)、跟随者(follower)、候选者(candidate)三种状态之一。下图示出节点状态的转移规则。
可见,集群建立时所有节点都是跟随节点。如果在一定时间过后发现没有领导节点,就会切换到候选状态,发起选举。得到多数票的候选者就会成为领导节点。如果候选节点或当前领导节点发现了更新的领导者,就会主动退回跟随状态。
领导节点全权负责管理复制日志,也就是从客户端接收请求,复制到跟随节点,并告诉跟随节点何时可以处理这些请求。如果领导节点故障或断开连接,就会重新进行选举。可见,领导节点的存在大大简化了共识算法的设计。
在上面的图中出现了任期(term)这个词。领导者并不是一直“在位”的,工作一段时间之后,就会选举出新的领导者来接替它。
由上图可见,蓝色表示选举时间段,绿色表示选举出的领导者在位的时间段,这两者合起来即称作一个任期,其计数值是自增的。任期的值就可以在逻辑上充当时间戳,每个节点都会保存一份自己所见的最新任期值,称为currentTerm。另外,如果因为票数相同,没能选出领导,就会立即再发起新的选举。
如果一个或多个跟随节点在选举超时(election timeout)内没有收到领导节点的心跳(一个名为AppendEntries的RPC消息,本意是做日志复制用途,但此时不携带日志数据),就会发起选举流程:
根据其他节点回复的消息,会出现如下三种结果:
获得多数票的节点只要当选,就会立即给其他所有节点发送AppendEntries,避免再次选举。另外,在同一任期内,每个节点只能投一票,并且先到先得(first-come-first-served),也就是会把票投给RequestVote消息***个到达的那个节点。
至于上面的第三种情况,也就是所谓“split vote”现象,容易在很多跟随者变成候选者时出现,因为没有节点能得到多数票,选举有可能无限继续下去。所以,Raft设置的选举超时并不是完全一样的,而是有些许随机性,来尽量使得投票能够集中到那些较“快”的节点上。
领导节点选举出来后,集群就可以开始处理客户端请求了。前面已经说过,每个节点都维护着一个复制日志的队列,它们的格式如下图所示。
可见,日志由一个个按序排列的entry组成。每个entry内包含有请求的数据,还有该entry产生时的领导任期值。在论文中,每个节点上的日志队列用一个数组log[]表示。
当客户端发来请求时,领导节点首先将其加入自己的日志队列,再并行地发送AppendEntries RPC消息给所有跟随节点。领导节点收到来自多数跟随者的回复之后,就认为该请求可以提交了(见图中的commited entries)。然后,领导节点将请求应用(apply)到复制状态机,并通知跟随节点也这样做。这两步做完后,就不会再回滚。
这种从提交到应用的方式与最基础的一致性协议——两阶段提交(2PC)有些相似,但Raft只需要多数节点的确认,并不需要全部节点都可用。
注意在上图中,领导节点和4个跟随节点的日志并不完全相同,这可能是由于跟随节点反应慢、网络状况差等原因。领导节点会不断地重试发送AppendEntries,直到所有节点上的日志达到最终一致,而不实现强一致性。这就是CAP理论中在保证P的情况下,C与A无法兼得的体现。
日志复制的过程仍然遗留了一个问题:如果领导或者跟随节点发生异常情况而崩溃,如何保证日志的最终一致性?它属于下面的安全性问题中的一部分,稍后会解答它。
安全性是施加在领导选举、日志复制两个解决方案上的约束,用于保证在异常情况下Raft算法仍然有效,不能破坏一致性,也不能返回错误的结果。所有分布式算法都应保障安全性,在其基础上再保证活性(liveness)。
Raft协议的安全性保障有5种,分别是:选举安全性(election safety)、领导者只追加(leader append-only)、日志匹配(log matching)、领导者完全性(leader completeness)、状态机安全性(state machine safety) 。下面分别来看。
选举安全性是指每个任期内只允许选出最多一个领导。如果集群中有多于一个领导,就发生了脑裂(split brain)。根据“领导选举”一节中的描述,Raft能够保证选举安全,因为:
在讲解日志复制时,我们可以明显地看出,客户端发出的请求都是插入领导者日志队列的尾部,没有修改或删除的操作。这样可以使领导者的行为尽量简单化,使之没有任何不确定的行为,同时也作为下一节要说的日志匹配的基础。
日志匹配的具体描述如下。
如果两个节点的日志队列中,两个entry具有相同的下标和任期值,那么:
***点自然由上一节的“领导者只追加”特性来保证,而第二点则由AppendEntries RPC消息的一个简单机制来保证:每条AppendEntries都会包含最新entry之前那个entry的下标与任期值,如果跟随节点在对应下标找不到对应任期的日志,就会拒绝接受并告知领导节点。
有了日志匹配特性,就可以解决日志复制中那个遗留问题了。假设由于节点崩溃,跟随节点的日志出现了多种异常情况,如下图。
注意图中不是6个跟随节点,而是6种可能的情况。比如a和b是丢失了entry,c和d是有多余的未提交entry,e和f则是既有丢失又有冗余。这时领导节点就会找到两个日志队列中最近一条匹配的日志点,将该点之后跟随节点的所有日志都删除,然后将自己的这部分日志复制给它。例如对于上图中的情况e来说,最近一条匹配的日志下标为5,那么5之后的所有entry都会被删除,被替换成领导者的日志。
领导者完全性是指,如果有一条日志在某个任期被提交了,那么它一定会出现在所有任期更大的领导者日志里。这也是由两点来决定的:
根据这两个描述,每次选举出的领导节点一定包含有最新的日志,因此只存在跟随节点从领导节点更新日志的情况,而不会反过来,这也使得一致性逻辑更加简化,并且为下面的状态机安全性提供保证。
状态机安全性是说,如果一个节点已经向其复制状态机应用了一条日志中的请求,那么对于其他节点的同一下标的日志,不能应用不同的请求。这句话就很拗口了,因此我们来看一种意外的情况。
这里就有问题了,在时刻c的日志与新领导者的日志发生了冲突,此时状态机是不安全的。
为了解决该问题,Raft不允许领导者在当选后提交“前任”的日志,而是通过日志匹配原则,在处理“现任”日志时将之前的日志一同提交。具体方法是:在领导者任期开始时,立刻提交一条空的日志,所以上图中时刻c的情况不会发生,而是像时刻e一样先提交任期4的日志,连带提交任期2的日志。就算此时S1再崩溃,S5也不会重新被选举了。
如果想要更直观地理解Raft,建议参考 这里 ,是一个用动画来描述该算法的网页,形象生动。
k8s etcd 与持久化存储
1、是什么
2、etcd架构及工作原理
(1) 数据流程
一个用户的请求发送过来,会经过HTTP Server转发给store进行具体事务处理,如果涉及到节点的修改,则需要交给raft模块进行状态的变更,日志的记录,然后再同步给别的etcd节点确认数据提交,最后进行数据提交,再次同步
(2)工作原理
Etcd使用 Raft协议 来维护集群内各个节点状态的 一致性 。简单说,ETCD集群是一个分布式系统,由多个节点相互通信构成整体对外服务, 每个节点都存储了完整的数据 ,并且通过Raft协议保证每个节点维护的数据是一致的
(3) 主要组成部分
(4)etcd集群中的术语
3、k8s中的etcd
(1)etcd在k8s中的作用: etcd在kubernetes集群是用来存放数据并通知变动的
(2)为什么k8s选择etcd:
PV 目前支持的类型包括:gcePersistentDisk 、AWSElasticBlockStore 、AzureFile 、AzureDisk 、FC ( Fibre Channel ) 、Flocker、NFS 、iSCSI 、RBD (Rados Block Device )、CephFS 、Cinder、GlusterFS 、V sphere Volume 、Quobyte Volumes 、VMware Photon 、Portwonc
Volumes 、ScaleIO Volumes 和HostPath (仅供单机测试)。
如果某个Pod 想申请某种类型的PY ,则首先需要定义一个PersistentVolurneClaim ( PVC )对象,然后,在Pod 的Volume 定义中引用上述PVC 即可:
协议里筏作时间是什么意思
落款时间。协议里筏作时间是落款时间,合同订立日期和生效日期都是一个时间,就是双方签字、盖章之日生效。raft是工程上使用较为广泛的强一致性、去中心化、高可用的分布式协议,在这里强调了是在工程上,因为在学术理论界,最耀眼的还是大名鼎鼎的Paxos。
ratis - 整体概念
ratis是raft协议java版本的开源实现项目,位于Apache项目下。项目git地址:。raft协议是基于日志的强领导模型的共识算法。leader选举、集群数据同步都离不离开日志。ratis最终目的是为了实现分布式系统的高可用性,对于具体的应用程序,ratis使用状态机(StateMachineUpdater)对具体的应用程序抽象隔离,保证ratis实现raft协议的纯粹性和可移植性。
客户端向raftServerImpl提交请求,请求最终由 RaftLog、LogAppender、LeaderState、StateMachineUpdater、StateMachine共同完成。具体步骤如下:
1、客户端向RaftServerImpl发送请求
2、RaftServerImpl将请求发送给RaftLog,构建日志并写入日志文件。
3、RaftServerImpl将请求提交给LeaderState(返回一个CompelableFuture),等待请求处理完成。
4、LogAppender检测到新增日志,复制日志到对应的Follower节点,并等待节点的响应。
5、LogAppender接收到Follower节点日志提交成功响应后,将日志发送给LeaderState提交。
6、LeaderState检测到大所属节点都已经同步成功后,提交日志,并通知StateMachineUpdater服务
7、StateMachineUpdater服务检测到新提交的日志,读取日志并发送给StateMachine(应用程序通过该步骤接收到客户请求)并处理日志。
8、StateMachine处理完成提交的日志,将对应日志在LeaderState中的CompletableFuture状态更新为完成。
9、RaftServerImpl通过CompletableFuture接收到处理结果,并返回给客户端。
ratis启动可以分解成三个部分:1、初始化;2、leader选举;3、启动leader;
初始化部分是指Ratis正常工作的必要模块的初始化和启动。其中就包括:1、RaftServerImpl的初始化;2、LifeCycle生命周期管理器初始化;3、StateMachineUpdater应用日志服务器的初始化和启动,以及作为初始角色Follower对应的服务FollowerState的初始化和启动。其中RaftServerImpl、LifeCycle、StateMachineUpdater不论节点属于什么角色,这三个服务都是必要服务。
启动顺序为:
1、有代理服务初始化LifeCycle生命周期控制器
2、构建RaftServerImpl服务实例,调用start方法启动该服务(这里的star并不是启动一个单独线程)
3、由RaftServerImpl初始节点角色管理服务,并将Follower作为初始角色启动(设置角色为:follower,启动角色对应的后台服务FoloowerState)。
4、设置集群为运行状态(更新LifeCycle的状态)
ratis的leader选举是由Follower后台服务FollowerState触发,在指定的超时时间范围内没有接收到Leader心跳请求,就触发节点角色的变更(由Follower角色变更为 Candidate角色,并启动Candidate角色对应的后台服务LeaderElection),开启Raft 候选人的leader选举流程。
如1.2图:
第10步:指Follower角色对应的后台服务FollowerState在指定时间内没有接收到Leader的心跳信息,于是触发角色变更。
第11步:FollowerState - RaftServerImpl#changeToCandidate指FollowerState通过Raft顶层服务RaftServerImpl变更节点角色,并结束当前服务(结束FollowerState服务)
第12步:RaftServerImpl - RoleInfo#startLeaderElection指RaftServerImpl通知RoleInfo将节点角色变更为:Candidate
第13步:并启动leader选举(也就是Candidate角色对应的后台服务 - LeaderElection服务)
LeaderElection服务启动后,就开始向配置文件中配置的其它节点发送投票请求。正常清情况下投票请求分为两个阶段:
1、预选阶段 - Phase.PRE_VOTE
预选阶段抓哟是检查当前集群是否存在合法的leader,该步骤可以通过配置:raft.server.leaderelection.pre-vote 关闭该步骤。
2、竞选阶段 - Phase.ELECTION
竞选阶段就是正式leader竞选,candidate向各节点开始拉票,并在指定节时间内统计得到的投票情况。
leader的启动由LeaderElection选举通过触发。如图1.2时序图所示:
第14步:由LeaderElection调用RaftServerImpl#changeToLeader,开启leader上位。
第15步:RaftServerImpl调用RoleInfo#shutDownElection,关闭LeaderElection后台服务。
第17步:RaftServerImpl调用RoleInfo#becomeLeader,将节点的角色设置为:leader,并初始化启动LeaderStateImpl。
第18步:LeaderState初始化并启动LogAppender,开启leader日志同步后台服务。
至此,Ratis服务leader上位就结束,可以开启正常的服务请求处理了。
关于raft协议和raft协议选举的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。