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所有的提案當中最大的,則不需要重新賦值。
基于的一個基本的數學原理
它需要滿足的假設。