paxos通俗说就是 发起提案之前首先判断当前是否是最新的 如果不是 则把最新的值赋值 如果是则不用赋值
即 提案ID 提案内容 预提案 返回的提案ID及其最大值 保持一致性
paxos 保证决议的一致性 保证多值的一致性
在节点宕机 消息无序等场景可能出现情况下,相互独立节点如何达成决议 解决一致性问题的决议
paxos 确定并只确定一个值是确定多值的基础
Paxos先把节点分成两类,发起提议(proposal)的一方为proposer,参与决议的一方为acceptor。假如只有一个proposer发起提议,并且节点不宕机、消息不丢包,那么acceptor做到以下这点就可以确定一个值:P1. 一个acceptor接受它收到的第一项提议
首先proposer和acceptor需要满足以下两个条件:
- proposer发起的每项提议分别用一个ID标识,提议的组成因此变为(ID, value)
- acceptor可以接受(accept)不止一项提议,当多数(quorum) acceptor接受一项提议时该提议被确定(chosen)
(注: 注意以上“接受”和“确定”的区别)
约定后面发起的提议的ID比前面提议的ID大,并假设可以有多项提议被确定,为做到确定并只确定一个值acceptor要做到以下这点:
P2. 如果一项值为v的提议被确定,那么后续只确定值为v的提议
如果一个提案Proposal-j最终会被通过,那么对于任意的一个提案Proposal-i,如果Proposal-i.proposal_id > Proposal-j.proposal_id,那么必定Proposal-i.v = Proposal-j.v。
由于一项提议被确定(chosen)前必须先被多数派acceptor接受(accepted),为实现P2,实质上acceptor需要做到:
P2a. 如果一项值为v的提议被确定,那么acceptor后续只接受值为v的提议 满足P2a则P2成立 (P2a => P2)。
如果proposal_id在区间[j,i)内任意的提案,提案的值均为Proposal-j.v,那么必定Proposal-i.v=v;这个结论记做CP1_1。
假设acceptor c 宕机一段时间后恢复,c 宕机期间其他acceptor已经确定了一项值为v的决议但c 因为宕机并不知晓;c 恢复后如果有proposer马上发起一项值不是v的提议,由于条件P1,c 会接受该提议,这与P2a矛盾。为了避免这样的情况出现,进一步地我们对proposer作约束:
P2b. 如果一项值为v的提议被确定,那么proposer后续只发起值为v的提议 满足P2b则P2a成立 (P2b => P2a => P2)。
如果一个提案Proposal-j最终会被通过,且proposal_id在区间[j,i)内的提案值均为Proposal-j.v,i>j;那么如果对于提案Proposal-i, 必然Proposal-i.v = Proposal-j.v
P2b约束的是提议被确定(chosen)后proposer的行为,我们更关心提议被确定前proposer应该怎么做:
P2c. 对于提议(n,v),acceptor的多数派S中,如果存在acceptor最近一次(即ID值最大)接受的提议的值为v',那么要求v = v';否则v可为任意值
满足P2c则P2b成立 (P2c => P2b => P2a => P2)。
如果Proposal-j最终被会通过,且对于任意的一个法定集合Q,Q最终会接受的所有proposal_id小于i的提案组成的集合K,且K中proposal_id最大的提案的值为Proposal-j.v;那么Proposal-i的值必然等于Proposal-j.v。CP2
如果Proposal-j最终被会通过,且对于任意的一个法定集合Q,Q最终会接受的proposal_id小于i的提案组成的集合K;如果K非空,那么Proposal-i的值等于K中proposal_id最大的提案的值。CP3 —> CP2 —> CP1_2—> CP1 —>一致性
最终会接受的提案包括已经接受过的提案和未来会接受的提案。获悉已经接受过的提案是简单的,Q中的接受者只需记录它所有接受过的提案,当收到提出Proposal-i的提议者询问时,回复当中proposal_id小于i的提案即可;但是知悉未来是困难的。我们可以换个思路,既然无法知悉未来,那么我们约束未来,收到询问后,令Q中的接受者承诺不再接受任何proposal_id小于i的提案,即接受者未来将不接受任何proposal_id小于i的提案;这样Proposal-i的提议者就可以根据Q的回复得到完整的K。
paxos如何确定并只确定一个值?
发起提议为proposer 决议一方为acceptor
paxos应用于副本的一致性 实现一个 多节点一致 的日志
paos made simple:
直接阅读相关论文 理解证明 理解不同 本质上相同 与人探讨 工程上自己实现 阅读开源实现的源代码
paxos几乎等价于分布式一致性
paxos是个分布式一致性协议,它的事件需要多个节点共同参与,一个事件完成是指多个节点上均完成了自身负责的单机子事件(就让我门把这样的事件称为"分布式事件"),这样的分布式事件可以看作是多个单机子事件的复合,但是即不能从两个分布式事件的先后推导出某个节点上它们的单机子事件的先后,也不能根据某个节点上两个单机子事件的先后断言它们对应的分布式事件的先后。
paxos所保证的一致性的具体含义:
paxos面向的是一个理论的一致性问题。变量v,分布在N个进程中,进程A令v=a,进程B令v=b。最终所有的进程对v的值达成一致,
即v=a是v达成一致的值,那么B,v也是a。
** 某个时刻达成一致并不等价于该时刻所有进程的本地v值都相同。(可能进程挂了,所有存活的进程本地值都一致) **
1/ v达成一致时的值是由某个进程提出的。防止预先设置。
2/ v达成一致后,不能对另一个值再次达成一致,为了保证安全性。
3/ v总会被确定为某个值,即一致总会达成,不能够无休止的等待。活性。
达成一致的条件(何时达成一致)
N个进程中大多数进程都认为v是同一个值。 当v的值被决定后,paxos保证了它就像是单机的不可变变量,不再更改。【对于一个客户端多次改写值的可读写变量在不同节点上的一致性问题,paxos不能直接解决该问题,需要和状态机复制结合】
平等性原则:分布式环境下 无法保障单个进程的状态 能够容忍一定数量的进程挂了 这是分布式协议的必然要求 进程之间是平等的
对于分布式环境来说 消息是进程间通信的唯一手段
paxos要求满足的前置假设只有一个,消息内容不会被篡改即无拜占庭将军问题。
场景1:三个进程p1,p2,p3 p1使得v=a p2使得v=b p1/p2首先修改自己的v值,然后发送消息修改p3的v值。两次均更改,则两次被决定为不同的值。
只会改写v一次。 先来后到 学会拒绝
场景2:p1 p2同上,p3令v=c 每个进程只会被改写一次 将永远不会出现两个进程的v值相等 即v永远无法被决定,即不满足活性(一致总会达成,不能够无休止等待)
结论:进程必须能够多次改写v【多次改写时 v的值还没有被确定 一致性尚未达成】,进程受到第一个消息时,没有任何理由拒绝该消息的请求。
为了实现拒绝策略,如果采用先来后到的方式 只接受第一个到达的消息,但这不满足活性,为了区分两条消息,引入id描述消息。
id的大小就作为拒绝或者接受的依据,选择id更大的消息接受或者更小的消息。这个策略不会导致明显的活性问题,ID更大的消息总是能被接受,一个节点可以多次更改v的值。
例如在场景1'中,只要P1的消息ID比P3发送给自己的消息ID更大,P3就会接受P1的消息,令v=a,从而令v的值被决定为a。再来考虑最初的场景1,不妨假设P1的消息ID大于P2的消息ID,根据P3收消息的先后可以分为两种情况:
P3先收到P1的消息,记做场景1-2,由于P1的消息是P3收到的第一个消息,P3接受该请求,令v=a;同时为了能对之后的收到的消息作出是否接受的判断,P3需要记录该消息的ID作为判断的依据。之后P3又收到P2的消息,该消息的ID小于P3记录的ID,这是即是P1的消息ID,因此P3拒绝该消息,这样我们的目的就达到。
P3先收到P2的消息,记作场景1-3,同样P3接受该消息,令v=b,记录该消息的ID。之后P3收到P1的消息,由于P1的消息ID大于P3记录的ID,因此P3无法拒绝该消息,之前的问题依旧存在。尽管对于场景1-3,目前的策略依旧无法保证一致性,但是起码我们缩小协议无法保证安全性的场景的范围。先总结下我们目前的策略,并定义一些称谓以方便后面的论述。我们称呼 进程P发送的尝试修改另一个进程中变量v的值的消息称之为提案,记作Proposal;提案的ID记作proposal_id;如果提案中附带的值被决定为是v的值,即大多数接受者接受了这个提案,那么称提案被通过。进程P记录的接受的提案ID为a_proposal_id。
解决方案:
- P3能够拒绝掉P2的提案。 P1在正式发送提案前,还发送了一个消息给P3,这个消息先于P2的提案到达,给了P3拒绝P2提案的理由。预提案,
- P3能够拒绝掉P1的提案。
- 限制P1提出的提案,如果P1的提案尝试决定的v的值与P2的提案一致,那么接受P1也不会破坏一致性。 P1在正式发送提案前,还发送了一个消息给P3,但这个消息晚于P2的提案到达,将p1的值变为p2的值。
协议的流程如下:
对于提议者,在正式提案前,先向任意的法定集合Q发送一个消息,这个消息即是预提案,消息中要附带提案的proposal-id,以便接受者能根据此做出承诺。
接受者收到预提案后,承诺不再接受比预提案中附带的proposal-id更小的提案,并回复已经接受过proposal-id比于提案的proposal-id更小的提案,如之前所论述的,回复的多个提案可以优化为只回复一个比预提案proposal_id更小的提案中proposal_id最大的那个提案。
提议者收到所有Q中接受者回复的提案后,挑选其中proposal_id最大的提案的值作为本次提案的值。
通俗语言表述paxos算法:
针对某一固定变量在分布式环境下的一致性保障,除了会有多个进程进行更改请求之外,需要一定的机制保证接受者的数据一致性。
针对每一个操作称为一次提案,使用提案ID 与 提案内容标记每一个提案,提案ID会增长,后面提议的ID 会比之前提议的ID 更大。
针对某一变量 不同的客户端可能会有1,2,3,4.。。N个操作。客户端发送请求给leader,由leader发起提案,由于网络延迟及系荣原因,可能每个提案的到达顺序未必一致。只要确定变量的值,即达成一致。
因此,leader发起提案时,首先将当前的提案ID作为预提案的消息发送给各accecptor即选举者,投票者。
投票者受到该预提案后,不再接受比该消息所代表的提案ID更小的提案(对于某一指定的变量值而言 约定选择其ID 更大的消息值),假如当前的预案ID 由于网络延迟等原因后到了,即当前accecptor已经接收了ID 更大的提案,我们需要获取该ID提案的值,然后将该值作为本次提案的值传递过来,以保证数据的一致性。
如果当前ID是包括当前acceptor所有的提案当中最大的,则不需要重新赋值。
基于的一个基本的数学原理
它需要满足的假设。