zk基础—1.一致性原理和算法二

大纲

1.分布式系统特点

2.分布式系统的理论

3.两阶段提交Two-Phase Commit(2PC)

4.三阶段提交Three-Phase Commit(3PC)

5.Paxos岛的故事来对应ZooKeeper

6.Paxos算法推导过程

7.Paxos协议的核心思想

8.ZAB算法简述

6.Paxos算法推导过程

(1)Paxos的概念

(2)问题描述

(3)推导过程

(4)Proposer生成提案

(5)Acceptor批准提案

(6)Paxos算法描述

(7)Learner学习被选定的value

(8)如何保证Paxos算法的活性

(1)Paxos的概念

一.Paxos的角色

二.Paxos的提案

三.Paxos角色对数据达成一致的情况

一.Paxos的角色

在Paxos算法中,有三种角色:Proposer、Acceptor、Learner。在具体的实现中,一个进程可能同时充当多种角色。比如一个进程可能既是Proposer又是Acceptor又是Learner。

还有一个重要概念叫提案(Proposal),最终要达成一致的value就在提案里。

假如只有一个角色,那么其实就是分布式节点自己。各自认为自己的表达是正确的,这时候是无法达成一致的。所以需要引入多一个角色来处理各个节点的表达,最后还要引入一个角色将达成一致的结果同步给各分布式节点。

二.Paxos的提案

暂且认为提案(Proposal)只包含value,但在接下来的推导过程中会发现如果提案(Proposal)只包含value会有问题。

暂且认为Proposer可以直接提出提案,在接下来的推导过程中会发现:如果Proposer直接提出提案也会有问题,需要增加一个学习提案的过程。

Proposer可以提出(propose)提案,Acceptor可以批准(accept)提案。如果某个提案被选定(chosen),那么该提案里的value就被选定了。

注意:批准和选定是不一样的,批准未必就代表选定。根据后面所述,多数Acceptor批准了某提案,才能认为该提案被选定了。

三.Paxos角色对数据达成一致的情况

对某个数据的值达成一致,指的是:Proposer、Acceptor、Learner都认为同一个value被选定(chosen)。

Proposer、Acceptor、Learner分别在什么情况才认为某个value被选定:

情况一:Proposer

只要Proposer发出的提案被Acceptor批准,那么Proposer就认为该提案里的value被选定了。

情况二:Acceptor

只要Acceptor批准了某个提案,那么Acceptor就认为该提案里的value被选定了。

情况三:Learner

Acceptor告诉Learner哪个value被选定,Learner就认为那个value被选定。

上面只有一个节点时是没问题的,但多个节点时批准就不能等于选定了。

(2)问题描述

一.该一致性算法的基本实现目标

二.该一致性算法满足的安全性

三.推导该一致性算法的默认条件

四.提案被选定的规定

一.该一致性算法的基本实现目标

假设有一组可以提出(propose)value的进程集合(value在提案Proposal里),那么一个一致性算法需要做出如下保证。

保证一:在提出的这么多value中,只有一个value会被选定(chosen)

保证二:如果没有value被提出,那么就不应该有value被选定

保证三:如果一个value被选定,那么所有进程都应该能学习(learn)或者获取到这个被选定的value

二.该一致性算法满足的安全性

一个分布式算法有两个最重要的属性:安全性(Safety)和活性(Liveness)。安全性是指那些需要保证永远都不会发生的事情,活性是指那些最终一定会发生的事情。

对于一致性算法,安全性要求如下:

要求一:只有被提出的value才能被选定

要求二:只有一个value能被选定

要求三:如果某进程认为某value被选定,则该value必须是真的被选定

在对Paxos算法的介绍中,我们不去精确定义其活性需求,只需要确保:Paxos算法的目标是保证最终有一个提出的value被选定,当一个value被选定后,进程最终也能学习或者获取到这个value。

三.推导该一致性算法的默认条件

假设三个角色间可通过发送消息来进行通信,那么默认以下两个情况:

情况一:每个角色以任意的速度执行,可能因出错而停止,也可能会重启。同时即使一个value被选定后,所有的角色也可能失败然后重启。除非失败后重启的角色能记录某些信息,否则重启后无法确定被选定的值。

情况二:消息在传递过程中可能任意延迟、可能会重复、也可能丢失。但是消息不会被损坏,即消息内容不会被篡改,也就是无拜占庭将军问题。即各将军管理的军队被地理分割开,只能依靠通讯员传递信息,而通信员可能存在叛徒篡改信息欺骗将军。

四.提案被选定的规定

下面规定在存在多个Acceptor的情况下,如何判断选定一个提案。

规定:Proposer会向一个Acceptor集合发送提案。同样,集合中的每个Acceptor都可能会批准(Accept)该提案。当有足够多的Acceptor批准这个提案时,我们就认为该提案被选定了。

所以,批准和选定是不一样的,批准未必就代表选定。多数Acceptor批准了某提案,才能认为该提案被选定了。

足够多指的是:我们假定足够多的Acceptor其实是整个Acceptor集合的一个子集,并且让这个集合大得可以包含Acceptor集合中的大多数成员,因为任意两个包含大多数Acceptor的子集至少有一个公共成员。

(3)推导过程

一.要选定一个唯一提案的最简单方案——只允许一个Acceptor存在

二.多个Acceptor和多个Proposer——如何使得只有一个value被选定

三.提案变成了一个由编号和value组成的组合体:[编号, value]

四.如何证明P2b

五.如何根据P2c去证明P2b

约束P1:一个Acceptor必须批准它收到的第一个提案。
规定R1:一个Proposer的提案能够发送给多个Acceptor(Acceptor集合)。
规定R2:一个提案(value)被选定需要被半数以上的Acceptor批准。
规定R3:每一个Acceptor必须能够批准不止一个提案(value)。约束P2:如果提案[M0, V0]被选定了:
那么所有比编号M0更高的且被选定的提案,其value值必须也是V0。约束P2a:如果提案[M0, V0]被选定了:
那么所有比编号M0更高的且被Acceptor批准的提案,其value值必须也是V0。约束P2b:如果提案[M0, V0]被选定了:
那么之后任何Proposer产生的编号更高的提案,其value值必须也是V0。约束P2c:对于任意的Mn和Vn,如果提案[Mn, Vn]被提出:
那么肯定存在一个半数以上的Acceptor组成的集合S,满足以下条件中的任意一个:条件一:S中每个Acceptor都没有批准过编号小于Mn的提案。
条件二:S中Acceptor批准过的编号小于Mn的且编号最大的提案的value为Vn。

一.要选定一个唯一提案的最简单方案——只允许一个Acceptor存在

要使得只有一个value被选定,最简单的方式莫过于只有一个Acceptor,当然可以有多个Proposer,这样Proposer只能发送提案给该Acceptor。

此时,Acceptor就可以选择它收到的第一个提案作为被选定的提案,这样就能够保证只有一个value会被选定。

但是,如果这个唯一的Acceptor宕机了,那么整个系统就无法工作。因此,必须要有多个Acceptor来避免Acceptor的单点问题。

图片

二.多个Acceptor和多个Proposer——如何使得只有一个value被选定

如果希望即使只有一个Proposer提出一个value,该value也能被选定。那么,就得到下面的约束:

约束P1:一个Acceptor必须要批准它收到的第一个提案。

但是,这又会引出另一个问题:如果每个Proposer分别提出不同的value,发给不同的Acceptor。根据约束P1,每个Acceptor分别批准自己收到的第一个value,这就会导致不同的value被选定,出现value不一致。于是满足不了只有一个value会被选定的要求,如下图示:

图片

图片

上面是由于:"一个提案只要被一个Acceptor批准,则该提案的value就被选定了",以及"Acceptor和Proposer存在多个",才导致value不一致问题。因此问题转化为:在存在多个Acceptor和多个Proposer情况下,如何进行提案的选定?

最简单的情况:如果一个Proposer的提案只发送给一个Acceptor,由上图可知必然会导致value不一致问题。因此,可以有以下规定:

规定R1:一个Proposer的提案能够发送给多个Acceptor(Acceptor集合)。

既然一个Proposer的提案能够发送给多个Acceptor,当Proposer可以向Acceptor集合发送提案时,集合中的每个Acceptor都可能会批准该提案。当有足够多的Acceptor批准这个提案时,我们才可认为该提案被选定了。那么什么才是足够多呢?

我们假定足够多的Acceptor是整个Acceptor集合的一个子集,并且让该子集大得可以包含Acceptor集合中的大多数成员,因为任意两个包含大多数Acceptor的子集至少有一个公共成员。因此,有了如下规定:

规定R2:一个提案(value)被选定需要被半数以上的Acceptor批准。

在约束P1(一个Acceptor必须要批准它收到的第一个提案)的基础上,再加上规定R2(一个提案(value)被选定需要被半数以上的Acceptor批准),假如每个Acceptor最多只能批准一个提案,那么又回到了下图的问题:

图片

因此,有了如下规定:

规定R3:每一个Acceptor必须能够批准不止一个提案(value)。

既然一个Proposer的提案能够发送给多个Acceptor,那么一个Acceptor就会收到多个提案。

考虑情形1:当多个Proposer将其提案发送给多个Acceptor后,突然大部分Acceptor挂了,只剩一个Acceptor存活,如何进行提案的批准。该存活的Acceptor收到多个提案,由规定R3,它可以批准多份提案,那么如何保证最后只有一个提案被选定保证value一致。

考虑情形2:有5个Acceptor,其中2个批准了提案v1,另外3个批准了提案v2。此时如果批准v2的3个Acceptor中有一个挂了,那么v1和v2的批准者都变成了2个,此时就没法选定最终的提案。

图片

因此,可以引入全局唯一编号来唯一标识每一个被Acceptor批准的提案:当一个具有某value值的提案被半数以上的Acceptor批准后,我们就认为该value被选定了,也就是该提案被选定了。唯一编号的作用其实就是用来辅助:当出现多个value都被同一半数批准时,可以选定唯一的value,比如选择唯一编号最大的value。

三.提案变成了一个由编号和value组成的组合体:[编号, value]

由上可知,选定其实认的只是value值。当提案[value]变成[编号, value]后,是允许多个提案[编号, value]被选定的。根据规定R2(一个提案被选定需要半数以上的Acceptor批准),存在多个提案被半数以上的Acceptor批准,此时就有多个提案被选定。那么就必须保证所有被选定的提案[编号, value]都具有相同的value值。否则,如果被选定的多个提案[编号, value]其value不同,又会出现不一致。因此,可以得到如下约束:

约束P2:如果提案[M0, V0]被选定了,那么所有比编号M0更高的且被选定的提案,它的value值也必须是V0。

编号可理解为提案被提出的时间,比编号M0更高可理解为晚提出。所以提案[M0,V0]被选定后,所有比该提案晚提出的提案被选定时。为了value一致,那么这些晚提出的被选定的提案的value也要是V0。而所有比该提案早提出的提案,可以忽视它不进行选定即可。

一个提案[编号, value]只有被Acceptor批准才可能被选定,因此我们可以把约束P2改写成对"Acceptor批准的提案"的约束P2a:

约束P2a:如果提案[M0, V0]被选定了,那么所有比编号M0更高的且被批准的提案,它的value值也必须是V0。

所以提案[M0,V0]被选定后,所有比该提案晚提出的提案被批准时。为了value一致,那么这些晚提出的被批准的提案的value也要是V0。而所有比该提案早提出的提案,可以忽视它不进行批准即可。因此只要满足了P2a,就能满足P2。

由于通信是异步的,一个提案可能会在某个Acceptor还未收到任何提案时就被选定了。假设有5个Acceptor和2个提案,在Acceptor1没收到任何提案情况下,其他4个Acceptor已经批准了来自Proposer2的提案。而此时Proposer1产生了一个具有其他value值的且编号更高的提案,并发送给了Acceptor1。那么根据P1,Acceptor1要批准该提案,但这与约束P2a矛盾。

因此,如果要同时满足P1和P2a,需要对P2a进行强化。因为P2a只是说晚提出的提案被Acceptor批准时value才为V0,需要对P2a强化为晚提出的提案不管是否被批准其value都是V0。

约束P2b:如果提案[M0, V0]被选定了,那么之后任何Proposer产生的编号更高的提案,其value值必须也是V0。

否则一个提案得到多数批准被选定后,再提出一个值不同的新提案,这个提案会作为第一个提案发到某个Acceptor然后被批准,与P2a矛盾。

因为一个提案必须在被Proposer提出后才能被Acceptor批准,所以P2b可以推出P2a,P2a可以推出P2。

P2:提案[M,V]被选定后,晚提出的提案如果被选定,那么其value也是V;(否则会出现选定多个value了)
P2a:提案[M,V]被选定后,晚提出的提案如果被批准,那么其value也是V;(P2a可以推出P2)
P2b:提案[M,V]被选定后,晚提出的提案不管是否被批准,那么其value也是V;(否则根据P1可能会出现与P2a矛盾的情况)
而对于比提案[M,V]早提出的提案,可以采取忽略无视处理;(P2b可以推出P2a)P1:一个Acceptor必须批准它收到的第一个提案;(否则只有一个提案被提出时就无法选定一个value了)
R1:一个Proposer的提案能够发送给多个Acceptor(Acceptor集合);(否则根据P1, 就会出现选定多个value了)
R2:一个提案(value)被选定需要被半数以上的Acceptor批准;(选定提案时对足够多的规定)
R3:每一个Acceptor必须能够批准不止一个提案(value);(否则一个提案就没法做到被半数以上的Acceptor批准了)

四.如何证明P2b

即提案[M0,V0]被选定后,Proposer提出的编号更高的提案的value都为V0。如果要证明P2b成立,则具体是要证明:假设提案[M0,V0]已被选定,则编号大于M0的提案Mn,其value值都是V0。

通过对Mn使用第二数学归纳法来证明,也就是说需要证明结论:假设编号在M0到Mn-1之间的提案,其value值都是V0,那么编号为Mn的提案的value值也为V0。

第二数学归纳法:
要证明n时的value值为v,则先假设0~n-1时的value值都为v;
然后再推导出n时的value值为v;

证明:

根据第二数学归纳法,当提案[M0,V0]被选定时,要证明编号大于M0的提案Mn,其value值都是V0。也就是假设编号M0到Mn-1的提案的value值都是V0时,证明Mn的value值为V0。

因为编号为M0的提案已经被选定了,这意味着存在一个由半数以上的Acceptor组成的集合C,C中的每个Acceptor都批准了编号为M0的提案。

根据归纳假设,编号为M0的提案被选定意味着:C中的每个Acceptor都批准了一个编号在M0到Mn-1范围内的提案,并且每个编号在M0到Mn-1范围内的被Acceptor批准的提案,其value为V0。

根据归纳假设,因为编号M0到Mn-1的提案的value值都是V0,所以C中的Acceptor1可以批准M0提案,Acceptor2可以批准M0 + M1提案,Acceptor3可以批准M0 + M1 + M2 + M3提案......也就是C中每个Acceptor批准的一个M0到Mn-1范围内的提案的value都是V0。

因为任何包含半数以上Acceptor的集合S都至少包含C中的一个成员,所以S中必然存在一个Acceptor,它批准的M0到Mn-1提案的value都是V0。这是根据归纳假设得出的结论,因此可以根据此而进一步加强到P2c。

因此只要满足如下P2c,就能让编号为Mn的提案的value值也为V0,也就是只要满足P2c,就可以证明P2b。只要满足如下P2c约束 + 上述归纳假设得出的结论,就能证明Mn也为V0。

约束P2c:对于任意的Mn和Vn,如果提案[Mn, Vn]被提出,则存在一个半数以上的Acceptor组成的集合S,满足以下条件中的任一个。

条件一:S中每个Acceptor都没有批准过编号小于Mn的提案

条件二:S中Acceptor批准过的编号小于Mn且编号最大的提案的value为Vn

五.如何根据P2c去证明P2b

从P1到P2c的过程其实是对一系列条件的逐步加强。如果需要证明这些条件可以保证一致性,那么就要反向推导:P2c => P2b => P2a => P2,然后通过P1和P2来保证一致性。

实际上,P2c规定了每个Propeser应该如何产生一个提案(P2c规定的提案生成规则)。对于产生的每个提案[Mn, Vn],需要满足:存在一个由超过半数的Acceptor组成的集合S满足以条件的任意一个:

条件一:要么S中没有Acceptor批准过编号小于Mn的任何提案

条件二:要么S中所有Acceptor批准的所有编号小于Mn的提案中,编号最大的那个提案的value值为Vn

当每个Proposer都按照这个规则来产生提案时,就可以保证满足P2b了。

下面在P2c的生成规则下证明P2b:

首先假设提案[M0,V0]被选定了,设比该提案编号M0大的提案为[Mn,Vn],那么在P2c的生成提案规则前提下,证明Vn = V0;

数学归纳法第一步:验证某个初始值成立

当Mn = M0 + 1时,如果有这样一个编号为Mn的提案,根据P2c的提案生成规则可知,一定存在一个超半数Acceptor的子集S,由于提案[M0, V0]已被选定,所以S中必然有Acceptor批准过编号小于Mn的提案,也就是M0提案,即此时P2c的提案生成规则的条件一不成立,进入条件二来生成Vn。

所以,由于S中有Acceptor已经批准了编号小于Mn的提案(即M0提案)。于是,Vn只能是多数集S中编号小于Mn但为最大编号的那个提案的值。而此时因为Mn = M0 + 1,因此理论上编号小于Mn但为最大编号的那个提案肯定是[M0, V0],同时由于S和选定[M0, V0]的Acceptor集合都是多数集,故两者肯定有交集,也就是说由于两者都是多数集,所以S中必然存在一个Acceptor批准了M0。根据Mn = M0 + 1,M0其实就是编号小于Mn但是编号是最大的。这样Proposer在确定Vn取值的时候,就一定会选择V0(根据Vn只能是多数集S中编号小于Mn但为最大编号的那个提案的值)。

数学归纳法第二步:假设编号在M0 + 1到Mn - 1内成立,推导编号Mn也成立

根据假设,编号在M0 + 1到Mn - 1区间内的所有提案的value值为V0,需要证明的是编号为Mn的提案的value值也为V0。

由于编号在M0 + 1到Mn - 1区间内的所有提案都是按P2c的规则生成的,所以一定存在一个超半数Accepter的子集S,而且S中有Acceptor已经批准了编号小于Mn的提案(P2c条件一不成立)。于是,Vn只能是多数集S中编号小于Mn但为最大编号的那个提案的值。如果这个最大编号落在M0 + 1到Mn - 1区间内,那么Vn肯定是V0。如果不落在M0 + 1到Mn - 1区间内,则它的编号不可能比M0小,肯定是M0。这时因为S肯定会与批准[M0, V0]这个提案的Acceptor集合S'有交集,也就是说S中肯定存在一个Acceptor是批准了[M0, V0]的。又由于此时S中编号最大的提案其编号就是M0,根据上述,Vn只能是多数集S中编号小于Mn但为最大编号的那个提案的值。从而可知,此时Vn也是V0,因此得证。

(4)Proposer生成提案

在P2c的基础上,如何进行提案的生成?

对于一个Proposer来说,获取那些已经被通过的提案远比预测未来可能会被通过的提案简单。所以Proposer产生一个编号为M的提案时,必须要知道:当前某个已被半数以上Acceptor批准的编号小于M但为最大编号的提案,必须要求:所有的Acceptor都不要再批准任何编号小于M的提案。于是就引出了如下Proposer生成提案的算法:

步骤一:Proposer选择一个新的编号M向某Acceptor集合的成员发送请求,即编号为M的提案的Prepare请求,要求集合中的Acceptor做出两个回应。回应一是:向Proposer承诺,保证不再批准任何编号小于M的提案。回应二是:如果Acceptor已经批准过任何提案,那么就向Proposer反馈当前其已批准的、编号小于M但为最大编号的提案。

步骤二:如果Proposer收到了来自半数以上的Acceptor的响应结果,那么就可产生提案[M, V],这里V取收到响应的编号最大的提案的value值。当然还存在另外一种情况,就是半数以上的Acceptor都没有批准任何提案。也就是响应中不包含任何提案,那么此时V就可以由Proposer任意选择。Proposer确定好生成的提案[M, V]后,会将该提案再次发送给某个Acceptor集合,并期望获得它们的批准,此请求称为编号为M的提案的Accept请求。

注意:此时接收Accept请求的Acceptor集合,不一定是之前响应Prepare请求的Acceptor集合。

(5)Acceptor批准提案

根据Proposer生成提案的算法,一个Acceptor可能会收到来自Proposer的两种请求:编号为M的提案的Prepare请求和编号为M的提案的Accept请求。一个Acceptor会对Prepare请求做出响应的条件是:Acceptor可以在任何时候响应一个Prepare请求。一个Acceptor会对Accept请求做出响应的条件是:在不违背Acceptor现有承诺前提下,可响应任意Accept请求。

Acceptor可以忽略任何请求而不用担心破坏算法的安全性。因此,我们这里要讨论什么时候Acceptor可以响应一个请求。我们对Acceptor批准提案给出如下约束:

约束P1a:一个Acceptor只要尚未响应过任何编号大于M的Prepare请求,那么它就可以批准这个编号为M的提案。

可见,P1a包含了P1(一个Acceptor必须批准它收到的第一个提案)。

假设一个Acceptor收到一个编号为M的Prepare请求,在此之前它已经响应过编号大于M的Prepare请求。根据P1a,该Acceptor不可能再批准任何新的编号为M的提案,Acceptor也就没有必有对这个Prepare请求做出响应。因此,该Acceptor可以忽略编号为M的Prepare请求。

因此,每个Acceptor只需记住:它已批准提案的最大编号 + 它已响应Prepare请求的最大编号。这样即便Acceptor出现故障或者重启,也能保证满足P2c生成提案的规则。

而对于Proposer来说,只要它可以保证不会产生具有相同编号的提案,那么就可以丢弃任意的提案以及它所有的运行时状态信息。

图片

(6)Paxos算法描述

结合Proposer和Acceptor对提案的处理逻辑;可以得出类似于两阶段提交的算法执行过程。

阶段一:(Prepare请求)

一.Proposer选择一个提案编号M,然后向半数以上的Acceptor发送编号为M的Prepare请求。

二.如果一个Acceptor收到一个编号为M的Prepare请求,且M大于该Acceptor已经响应过的所有Prepare请求的编号,那么它就会将它已经批准过的编号最大的提案作为响应反馈给Proposer,同时该Acceptor承诺不再批准任何编号小于M的提案。

阶段二:(Accept请求)

一.如果Proposer收到半数以上Acceptor,对其发出的编号为M的Prepare请求的响应,那么它就会发送一个针对[M, V]提案的Accept请求给半数以上的Acceptor。注意:V就是收到的响应中编号最大的提案的value。如果响应中不包含任何提案,那么V就由Proposer自己决定。

二.如果Acceptor收到一个针对[M, V]提案的Accept请求,只要该Acceptor没有对编号大于M的Prepare请求做出过响应,它就批准该提案。

图片

(7)Learner学习被选定的value

Learner获取提案,有三种方案:

图片

(8)如何保证Paxos算法的活性

一个极端的活锁场景:

图片

(9)总结

二阶段提交协议解决了分布式事务的原子性问题,保证了分布式事务的多个参与者要么都执行成功,要么都执行失败。但是在二阶段解决部分分布式事务问题的同时,依然存在一些难以解决的诸如同步阻塞、无限期等待和脑裂等问题。

三阶段提交协议则是在二阶段提交协议的基础上,添加了PreCommit过程,从而避免了二阶段提交协议中的无限期等待问题。

Paxos算法引入过半的理念,也就是少数服从多数的原则。Paxos算法支持分布式节点角色之间的轮换,极大避免了分布式单点故障。因此Paxos算法既解决了无限期等待问题,也解决了脑裂问题。

整个Paxos算法就是想说明:每个Proposer生成的提案都去争取大多数Acceptor的批准。一旦有某个Proposer生成的提案[M0, V0]被大多数批准了,即便后面发现还有更多其他Proposer生成的提案[Mn, Vn]也被大多数Acceptor批准,那么这些提案的value值其实都是一样的,都为V0。因此就可以让每个Proposer都统一为一个value值为V0的提案,从而保证一致性。

7.Paxos协议的核心思想

(1)Paxos协议的核心思想

(2)Paxos协议的基本概念

(3)Paxos协议过程

(4)Paxos协议最终解决什么问题

(5)Paxos协议证明

(6)为什么要被多数派接受

(7)为什么需要做一个承诺

(8)为什么第二阶段A要从返回的提议中选择一个编号最大的

(9)Paxos协议的学习过程

(1)Paxos协议的核心思想

"与其预测未来,不如限制未来",这应该是Paxos协议的核心思想。Paxos协议本身是比较简单的,如何将Paxos协议工程化才是真正的难题。

(2)Paxos协议的基本概念

Proposal Value:提议的值

Proposal Number:提议编号,编号不能冲突

Proposal:提议 = 提议的值 + 提议编号

Proposer:提议发起者

Acceptor:提议接受者

Learner:提议学习者

说明一:协议中的Proposer有两个行为,一个是向Acceptor发Prepare请求,另一个是向Acceptor发Accept请求。

说明二:协议中的Acceptor则会根据协议规则,对Proposer的请求作出应答。

说明三:最后Learner可以根据Acceptor的状态,学习最终被确定的值。

为方便讨论,记[n, v]为提议编号为n、提议值为v的提议,记(m, [n, v])为承诺了Prepare(m)请求编号不再比m小,并接受过提议[n, v]。

(3)Paxos协议过程

一.第一阶段A

Proposer选择一个提议编号n,向所有的Acceptor广播Prepare(n)请求。

图片

二.第一阶段B

Acceptor接收到Prepare(n)请求,若提议编号n比之前接收的Prepare请求都要大,则返回承诺将不会接收提议编号比n小的提议,并且带上之前Accept的提议中编号小于n的最大的提议,否则不予理会。

图片

三.第二阶段A

Proposer得到了多数Acceptor的承诺后,如果没有发现有一个Acceptor接受过一个值,那么向所有的Acceptor发起自己的值和提议编号n。否则,从所有接受过的值中选择对应的提议编号最大的,作为提议的值,此时提议编号仍然为n。

图片

四.第二阶段B

Acceptor接收到提议后,如果该提议编号不违反自己做过的承诺,则接受该提议。

图片

需要注意的是,Proposer发出Prepare(n)请求后,得到多数派的应答。然后可以随便再选择一个多数派广播Accept请求,这时不一定要将Accept请求发给有应答的Acceptor。

五.协议过程总结

上面的图例中:首先P1广播了Prepare请求,但是给A3的Prepare请求丢失了。不过A1、A2成功返回了,即该Prepare请求得到多数派的应答。然后P1可以广播Accept请求,但是给A1的Accept请求丢失了。不过A2、A3成功接受了这个提议,因为这个提议被多数派(A2、A3形成多数派)接受,所以我们称被多数派接受的提议对应的值被Chosen。

情况一:如果三个Acceptor之前都没有接受过提议(即Accept请求),那么在第一阶段B中,就不用返回接受过的提议。

情况二:如果三个Acceptor之前接受过提议(即Accept请求),那么就需要在第一阶段B中,带上之前Accept的提议中编号小于n的最大的提议值,进行返回。

如下图示:Proposer广播Prepare请求之后,收到了A1和A2的应答,应答中携带了它们之前接受过的[n1, v1]和[n2, v2]。Proposer则根据n1、n2的大小关系,选择较大的那个提议对应的值。比如n1 > n2,那么就选择v1作为提议值,最后向Acceptor广播提议[n, v1]。

图片

(4)Paxos协议最终解决什么问题

当一个提议被多数派接受后,这个提议对应的值会被Chosen(选定)。一旦有一个值被Chosen(选定),那么只要按照协议的规则继续交互。后续被Chosen的值都是同一个值,也就是保持了这个Chosen值的一致性。

(5)Paxos协议证明

上文就是基本Paxos协议的全部内容,其实是一个非常确定的数学问题。下面用数学语言表达,进而用严谨的数学语言加以证明。

一.Paxos原命题

如果一个提议[n0, v0]被大多数Acceptor接受,那么不存在提议[n1, v1]被大多数Acceptor接受,其中n0 < n1,v0 != v1。

二.Paxos原命题加强

如果一个提议[n0, v0]被大多数Acceptor接受,那么不存在Acceptor接受提议[n1, v1],其中n0 < n1,v0 != v1。

三.Paxos原命题进一步加强

如果一个提议[n0, v0]被大多数Acceptor接受,那么不存在Proposer发出提议[n1, v1],其中n0 < n1,v0 != v1。

如果"Paxos原命题进一步加强"成立,那么"Paxos原命题"显然成立。下面通过证明"Paxos原命题进一步加强",从而证明"Paxos原命题"。

四.归纳法证明

假设提议[m, v](简称提议m)被多数派接受,那么提议m到n(如果存在)对应的值都为v,其中n不小于m(m <= n)。

这里对n进行归纳假设,当n = m时,结论显然成立。设n = k时结论成立,即如果提议[m, v]被多数派接受,那么提议m到k对应的值都为v,其中k不小于m(m <= k)。

当n = k + 1时,若提议k + 1不存在,那么结论成立。若提议k + 1存在,对应的值为v1。

因为提议m已经被多数派接受,又k + 1的Prepare被多数派承诺并返回结果。基于两个多数派必有交集,易知提议k + 1的第一阶段B有带提议回来。那么v1是从返回的提议中选出来的,不妨设这个值是选自提议[t, v1]。

根据第二阶段B,因为t是返回的提议中编号最大的,所以t >= m。又由第一阶段A,知道t < n,即t < k + 1,也就是m <= t < k + 1。所以根据假设可知,提议m到k对应的值都为v。所以再根据m <= t < k + 1,可得出t对应的值就为v,即有v1 = v。因此由假设的n = k结论成立,可以推出n = k + 1成立。

于是对于任意的提议编号不小于m的提议n,对应的值都为v,所以命题成立。

五.反证法证明

要证明的是:如果一个提议[n0, v0]被大多数Acceptor接受,那么不存在Proposer发出提议[n1, v1],其中n0 < n1,v0 != v1。

假设存在,不妨设n1是满足条件的最小提议编号。

即存在提议[n1, v1],其中n0 < n1,v0 != v1。-----------------------(A)

那么提议n0、n0 + 1、n0 + 2、...、n1 - 1对应的值为v0。-------------(B)

由于存在提议[n1, v1],则说明大多数Acceptor已经接收n1的Prepare,并承诺将不会接受提议编号比n1小的提议。

又因为[n0, v0]被大多数Acceptor接受,所以存在一个Acceptor既对n1的Prepare进行了承诺,又接受了提议n0。

由协议的第二阶段B可知,这个Acceptor先接受了[n0, v0]。所以发出[n1, v1]提议的Proposer会从大多数的Acceptor返回中得知,至少某个编号不小于n0而且值为v0的提议已经被接受。----------(C)

由协议的第二阶段A知,该Proposer会从已经被接受的值中选择一个提议编号最大的值,作为提议的值。由(C)知可该提议编号不小于n0,由协议第二阶段B可知,该提议编号小于n1。于是由(B)知v1 == v0,与(A)矛盾。

所以命题成立。

(6)为什么要被多数派接受

因为两个多数派之间必有交集,所以Paxos协议一般是2F + 1个Acceptor。然后允许最多F个Acceptor停机,而保证协议依然能够正常进行,最终得到一个确定的值。

(7)为什么需要做一个承诺

可以保证第二阶段A中Proposer的选择不会受到未来变化的干扰。另外,对于一个Acceptor而言,这个承诺决定了:它回应提议编号较大的Prepare请求和接受提议编号较小的Accept请求的先后顺序。

(8)为什么第二阶段A要从返回的提议中选择一个编号最大的

这样选出来的提议编号一定不小于已经被多数派接受的提议编号,进而可以根据假设得到该提议编号对应的值是Chosen的那个值。

(9)Paxos协议的学习过程

如果一个提议被多数Acceptor接受,则这个提议对应的值被选定。一个简单直接的学习方法就是:获取所有Acceptor接受过的提议,然后看哪个提议被多数的Acceptor接受,那么该提议对应的值就是被选定的。

另外一个学习方法是:把Learner看作一个Proposer,根据协议流程,发起一个正常的提议,然后看这个提议是否被多数Acceptor接受。

注意:这里强调"一个提议被多数Acceptor接受",而不是"一个值被多数Acceptor接受"。

图片

上图中,提议[3, v3],[5, v3]分别被B、C接受。虽然出现了v3被多数派接受,但不能说明v3被选定(Chosen)。只有提议[7, v1]被多数派(A和C组成)接受,才能说v1被选定,而这个选定的值随着协议继续进行不会改变。

8.ZAB算法简述

zk的ZAB协议是Paxos协议的一个精简版。ZAB协议即Zookeeper Atomic Broadcast,zk原子广播协议。ZAB协议是用来保证zk各个节点之间数据的一致性的。

ZAB协议包括以下特色:

特色一:Follower节点上全部的写请求都转发给Leader

特色二:写操作严格有序

特色三:使用改编的两阶段提交协议来保证各个节点的事务一致性,半数以上的参与者回复yes即可

广播模式:

广播模式就是指zk正常工作的模式。正常状况下,一个写入命令会通过以下步骤被执行:

步骤一:Leader从客户端或者Follower那里收到一个写请求

步骤二:Leader生成一个新的事务并为这个事务生成一个唯一的ZXID

步骤三:Leader将这个事务以Proposal形式发送给全部的Follower节点

步骤四:Follower节点将收到的事务请求加入队列,并发送ACK给Leader

步骤五:当Leader收到大多数Follower的ACK消息,会发送Commit请求

步骤六:当Follower收到Commit请求时,会判断该事务的ZXID是否是比队列中任何事务的ZXID都小来决定Commit

恢复模式:

当第一次启动集群时,先启动的过半机器中ZXID、myid最大的为Leader。当Leader故障时,zk集群进入恢复模式,此时zk集群不能对外提供服务。此时必须选出一个新的Leader完成数据一致后才能从新对外提供服务,zk官方宣称集群能够在200毫秒内选出一个新Leader。

正常模式下的几个步骤,每一个步骤都有可能由于Leader故障而中断,可是恢复过程只与Leader有没有Commit有关。

首先看前三个步骤,只做了一件事,把事务发送出去。若是事务没有发出去,全部Follower都没有收到这个事务,Leader故障了,全部的Follower都不知道这个事务的存在。

根据心跳检测机制,Follower发现Leader故障,需要重新选出一个Leader。此时会根据每一个节点ZXID来选择。谁的ZXID最大,表示谁的数据最新,就会被选举成新的Leader。若是ZXID都同样,那么就表示在Follower故障以前,全部的Follower节点数据一致,此时选择myid最大的节点成为新的Leader。

所以由于有一个固定的选举标准会加快选举流程,新的Leader选出来后,全部节点的数据同步一致后就能够对外提供服务。

假设新的Leader选出来以后,原来的Leader又恢复了,此时原来的Leader会自动成为Follower。

以前的事务即便发送给新的Leader,由于新的Leader已经开启了新的纪元,而原先的Leader中ZXID仍是旧的纪元,所以该事务就会被丢弃,而且该节点的ZXID也会更新成新的纪元。纪元就是标识当前Leader是第几任Leader,至关于改朝换代时候的年号。

若是在Leader故障以前已经Commit,zk会根据ZXID或者myid选出数据最新的那个Follower作为新的Leader。

新Leader会为Follower创建FIFO的队列,首先将自身有而Follower缺失的事务发送给该队列,然后再将这些事务的Commit命令发送给Follower,这样便保证了全部的Follower都保存了全部的事务数据。

ZAB协议确保那些已经在Leader提交的事务最终会被全部服务器提交,ZAB协议确保丢弃那些只在Leader提出或复制,但是没有提交的事务。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

216. 组合总和 III 回溯

目录 问题描述 解决思路 关键点 代码实现 代码解析 1. 初始化结果和路径 2. 深度优先搜索&#xff08;DFS&#xff09; 3. 遍历候选数字 4. 递归与回溯 示例分析 复杂度与优化 回溯算法三部曲 1. 路径选择&#xff1a;记录当前路径 2. 递归探索&#xff1a;进入下…

从AI大模型到MCP中台:构建下一代智能服务的核心架构

从AI大模型到MCP中台&#xff1a;构建下一代智能服务的核心架构 引言&#xff1a;AI大模型带来的服务重构革命 在ChatGPT掀起全球AI热潮的今天&#xff0c;大模型展现出的惊人能力正在重塑整个软件服务架构。但鲜为人知的是&#xff0c;真正决定AI服务成败的不仅是模型本身&a…

美团小程序 mtgsig1.2 拼好饭案例 分析 mtgsig

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 逆向分析 美团网页、小程序、app全是指…

【大模型基础_毛玉仁】5.5 模型编辑应用

目录 5.5 模型编辑应用5.5.1 精准模型更新5.5.2 保护被遗忘权5.5.3 提升模型安全 5.5 模型编辑应用 大语言模型面临更新成本高、隐私保护难、安全风险大等问题。模型编辑技术&#xff1a; 通过细粒度修改预训练模型&#xff0c;避免从头训练&#xff0c;降低更新成本&#xff…

揭秘:父子组件之间的传递

基础知识 组件与组件之间有三大方面的知识点&#xff1a; 子组件通过props defineProps&#xff08;{}&#xff09;接收父组件传递到参数和方法&#xff1b;子组件可以通过定义 emit 事件&#xff0c;向父组件发送事件&#xff1b;父组件调用子组件通过defineExpose 导出的方法…

微前端实现方案对比Qiankun VS npm组件

架构层面&#xff1a; 1、Qiankun是典型的微前端架构&#xff0c;侧重构建多个独立前端应用协同工作的架构&#xff0c;主应用负责自用用的加载、卸载和通信&#xff1b;子应用不限制&#xff0c;可以是VUE、React等&#xff1b; 2、Qiankun松耦合&#xff0c;各个自应用独立…

可编辑160页PPT | 营销流程和管理数字化转型规划

荐言分享&#xff1a;随着技术的发展和消费者行为的变化&#xff0c;传统营销方式已难以满足现代企业的需求。企业需要借助数字化手段&#xff0c;对营销流程进行全面梳理和优化&#xff0c;提升营销活动的精准度和效率。同时&#xff0c;通过数字化营销管理&#xff0c;企业可…

Ecovadis认证需要准备哪些材料?

Ecovadis认证&#xff0c;作为全球领先的企业社会责任&#xff08;CSR&#xff09;评估平台&#xff0c;其准备材料的过程不仅需要详尽无遗&#xff0c;更要体现出企业在环境、社会、劳工和伦理四大方面的卓越实践与持续改进的决心。 首先&#xff0c;环境管理方面&#xff0c…

程序化广告行业(45/89):RTB竞价后续流程、结算规则及相关要点解读

程序化广告行业&#xff08;45/89&#xff09;&#xff1a;RTB竞价后续流程、结算规则及相关要点解读 大家好&#xff01;一直以来&#xff0c;我都希望能和大家一起在程序化广告这个领域不断探索、共同成长&#xff0c;这也是我写这系列博客的初衷。之前我们了解了程序化广告…

权重参数矩阵

目录 1. 权重参数矩阵的定义与作用 2. 权重矩阵的初始化与训练 3. 权重矩阵的解读与分析 (1) 可视化权重分布 (2) 统计指标分析 4. 权重矩阵的常见问题与优化 (1) 过拟合与欠拟合 (2) 梯度问题 (3) 权重对称性问题 5. 实际应用示例 案例1&#xff1a;全连接网络中的…

文法 2025/3/3

文法的定义 一个文法G是一个四元组&#xff1a;G(,,S,P) &#xff1a;一个非空有限的终极符号集合。它的每个元素称为终极符号或终极符&#xff0c;一般用小写字母表示。终极符号是一个语言不可再分的基本符号。 &#xff1a;一个非空有限的非终极符号集合。它的每个元素称为…

字符串复习

344:反转字符串 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 示例 1&#xff1a; 输入&#xff1a;s ["…

【数据结构】算法效率的双刃剑:时间复杂度与空间复杂度

前言 在算法的世界里&#xff0c;效率是衡量算法优劣的关键标准。今天&#xff0c;就让我们深入探讨算法效率的两个核心维度&#xff1a;时间复杂度和空间复杂度&#xff0c;帮助你在算法设计的道路上更进一步。 一、算法效率&#xff1a;衡量算法好坏的关键 算法的效率主要…

Java基础-26-多态-认识多态

在Java编程中&#xff0c;多态&#xff08;Polymorphism&#xff09; 是面向对象编程的核心概念之一。通过多态&#xff0c;我们可以编写更加灵活、可扩展的代码。本文将详细介绍什么是多态、如何实现多态&#xff0c;并通过具体的例子来帮助你更好地理解这一重要概念。 一、什…

使用自定义的RTTI属性对对象进行流操作

由于历史原因&#xff0c;在借鉴某些特定出名的游戏引擎中&#xff0c;不知道当时的作者的意图和编写方式 特此做这篇文章。&#xff08;本文出自游戏编程精粹4 中 使用自定义的RTTI属性对对象进行流操作 文章&#xff09; 载入和 保存 关卡&#xff0c;并不是一件容易办到的事…

周总结aa

上周学习了Java中有关字符串的内容&#xff0c;与其有关的类和方法 学习了static表示静态的相关方法和类的使用。 学习了继承(extends) 多态&#xff08;有继承关系&#xff0c;有父类引用指向子类对象&#xff09; 有关包的知识&#xff0c;final关键字的使用&#xff0c;及有…

密码学基础——密码学相关概念

目录 1.1 密码系统&#xff08;Cryptosystem&#xff09; 1.2 密码编码学 1.3 密码分析学 1.4 基于算法保密 1.5 基于密钥保密 1.6密码系统的设计要求 1.7 单钥体制 1.8 双钥体制 密钥管理 1.1 密码系统&#xff08;Cryptosystem&#xff09; 也称为密码体制&#xff0…

初始JavaEE篇 —— Mybatis-plus 操作数据库

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;JavaEE 目录 前言 Mybatis-plus 快速上手 Mybatis-plus 复杂操作 常用注解 TableName TableField TableId 打印日志 条件构造器 …

PyQt6实例_批量下载pdf工具_主线程启用线程池

目录 前置&#xff1a; 代码&#xff1a; 视频&#xff1a; 前置&#xff1a; 1 本系列将以 “PyQt6实例_批量下载pdf工具”开头&#xff0c;放在 【PyQt6实例】 专栏 2 本系列涉及到的PyQt6知识点&#xff1a; 线程池&#xff1a;QThreadPool,QRunnable&#xff1b; 信号与…

1.2 斐波那契数列模型:LeetCode 面试题 08.01. 三步问题

动态规划解三步问题&#xff1a;LeetCode 面试题 08.01. 三步问题 1. 题目链接 LeetCode 面试题 08.01. 三步问题 题目要求&#xff1a;小孩上楼梯&#xff0c;每次可以走1、2或3步&#xff0c;计算到达第 n 阶台阶的不同方式数&#xff0c;结果需对 1e9 7 取模。 2. 题目描述…