pasxos與raft,與mysql的主從複製,不同的是,不依賴於leader節點,像mysql的主節點掛了,全部網絡就掛了,必須重新選舉主節點,並且mysql主從複製只能主節點寫。
pasxos多個節點可寫。
二個值:
value:要提議的值,也可以是某種操作(比如對a加1)
number:提議的序列號,可理解爲提議的版本號
三個角色:
1、proposer:提議者,發起提議。一輪共識中,多個proposer可以發起提議多個valuse。一輪的共識中,值有一個value值被達成全局一致性。
2、acceptor:接受提議者,或者稱爲提議接受者。proposer必須得到半數以上的accepter同意,才能寫入成功。
3、learner: 提議學習者,將半數以上accepter達成共識的提議,同步給剩下的未達成共識的協議。
主要是爲了解決多個副本同步過程中,由於網絡原因,延遲,故障等原因,造成順序不一致性,導致的整個系統數據的不一致性。
acceptor的結構
{
<#已經接受的序列號,#已經接受的值value>
#目前接受的最大的序列號
}
考慮基本方案1:
proposer獲取acceptor鎖的方式,哪個proposer獲得acceptor鎖,哪個proposer來對acceptor做寫操作。這種方式的問題,在proposer獲得acceptor的鎖後,掛掉了,那麼會造成死鎖,所以這個方案有BUG
考慮改進方案2:
讓acceptor給proposer發放鎖後,然後仍可以向更高序列號的proposer發放鎖。“喜新厭舊”的方式來發放鎖。
考慮1個acceptor的情況:
1、proposer1發送序列號<#1>給acceptor,
如果此時acceptor裏面的值爲<#空,#值空>, 那麼接受proposer的請求,發放鎖,裏面的值爲<#1,null>,此爲確定值。
如果此時proposer2發送更高的序列號<#2>給acceptor,那麼acceptor已經有了確定性的序列號#1,將不會再接受proposer#2。
2、proposer1發送第2階段,<#1,v1>給acceptor,acceptor會接受此v1值。
此時,appeptor結構裏的值爲
{
<#1,#值1>
<已經接受的最大序列號> #1
}
如果此時,讓proposer2發送來更高的序列號<#2>給acceptor,那麼acceptor會再次循環。
此方案的問題:只有1個acceptor,中心節點,此節點掛掉,整個系統掛掉。
改進方案3:引入多個acceptor的方案,解決方案2個問題。
考慮情況如下:
1、propose1向3個acceptor發動<#1>,此時3個acceptor的結構中都爲空,那麼接受<#1>,返回<#1,#值空>
此時,propose2向acceptor1發送<#2>, acceptor1看到#2比#1大,那麼會接受#2,給Propose2發放鎖,<#2,#值空>
2、prepose1得到了全部的3個acceptor的鎖,那麼就會向3個acceptor發送<#1,#值1>,
其中acceptor1,發現#1 小於 #2,那麼會拒絕接受prepose1的值。
其中acceptor2,acceptor3,仍佔領大多數,會接受這個prepose1這個值。
此時preposer2向acceptor2發送<#2>,acceptor2已經有確定#值1了,會回覆<#2,#值1>,此時,preposer2不會進入第2階段了, 會接受#值1。
不理解的地方:
acceptor得到一次確定值後,再進入下一輪循環,如何進入?
按邏輯分析,應該是把結構體中的<#序號,#值>清空變爲<#序號null,#值null>,保留 #最大已接受number。
下一輪開始,只接受比 #最大已接受number 大的序列號,以此反覆。
Paxos算法描述的過程是發生在“一次選舉”的過程中,這個在前面也提到過,實際Paxos算法執行是一輪接一輪,每輪還有個專有稱呼:instance(翻譯成中文有點怪),每instance都選出一個唯一的value。
問題1:活鎖問題
當proposer1第1階段達成以後,第2階段開始之前,3個acceptor中的2個,已經分別接受了proposer2和proposer3更高的序列號,此時會出現活鎖的現象,proposer1,2,3誰都不能獲得大多數選票。
解決辦法,proposer1,2,3節點,選出1個leader,只讓leader往acceptor解決請求。leader的選舉有隨機和超時機制,隨機很好理解了,超時機制可參考raft。
問題2:序號的全局唯一性
這也是1個分佈式一致性問題。
先給所有proposer節點編號,從0開始。0,1,2。。。。
公式:m*n+r舊的編號 = 新序列號
n爲propose的總數,m爲擁有最大值得那個proposer的編號,r爲計算節點自己的舊的小的編號。
問題3:learn角色學習問題
learn如何知道acceptor已經獲得確定的值,這需要由acceptor告訴他。
如果每個acceptor都需要告訴每個learn,那麼會對網絡造成很大負載,可以只告訴1個,或者1部分,或者選leader。根據算法自己定。
learn需要時有順序的,先學習#序號1的#值,再學習#序號2個#值。