Paxos算法2-算法過程

請先參考前文:Paxos算法1

 

1.編號處理

根據P2c ,proposer在提案前會先諮詢acceptor查看其批准的最大的編號和value,再決定提交哪個value。之前我們一直強調更高編號的proposal,而沒有說明低編號的proposal該怎麼處理。

|--------低編號(L<N)--------|--------當前編號(N)--------|--------高編號(H>N)--------|

P2c 的正確性是由當前編號N而產生了一些更高編號H來保證的,更低編號L在之前某個時刻,可能也是符合P2c 的,但因爲網絡通信的不可靠,導致L被延遲到與H同時提交,L與H有可能有不同的value,這顯然違背了P2c ,解決辦法是acceptor不接受任何編號已過期的proposal,更精確的描述爲:

 

P1a : An acceptor can accept a proposal numbered n iff it has not responded to a prepare request having a number greater than n.

顯然,acceptor接收到的第一個proposal符合這個條件,也就是說P1a 蘊含了P1。

關於編號問題進一步的討論請參考下節的【再論編號問題:唯一編號 】。

 

2. Paxos算法形成

重新整理P2c 和P1a 可以提出Paxos算法,算法分2個階段:

Phase1:prepare

   (a)proposer選擇一個proposal編號n,發送給acceptor中的一個多數派

   (b)如果acceptor發現n是它已回覆的請求中編號最大的,它會回覆它已accept的最大的proposal和對應的value(如果有);同時還附有一種承諾:不會批准編號小於n的proposal

 

Phase2:accept

   (a)如果proposer接收到了多數派的迴應,它發送一個accept消息到(編號爲n,value v的proposal)到acceptor的多數派(可以與prepare的多數派不同)

          關鍵是這個value v是什麼,如果acceptor迴應中包含了value,則取其編號最大的那個,作爲v;如果迴應中不包含任何value,則有proposer隨意選擇一個

   (b)acceptor接收到accept消息後check,如果沒有比n大的迴應比n大的proposal,則accept對應的value;否則拒絕或不迴應

 

感覺算法過程異常地簡單,而理解算法是怎麼形成卻非常困難。再仔細考慮下,這個算法又會產生更多的疑問:

 

再論編號問題:唯一編號


保證paxos正確運行的一個重要因素就是proposal編號,編號之間要能比較大小/先後,如果是一個proposer很容易做到,如果是多個proposer同時提案,該如何處理?Lamport不關心這個問題,只是要求編號必須是全序的,但我們必須關心。這個問題看似簡單,實際還稍微有點棘手,因爲這本質上是也是一個分佈式的問題。

 

在Google的Chubby論文中給出了這樣一種方法:

假設有n個proposer,每個編號爲ir (0<=ir <n),proposol編號的任何值s都應該大於它已知的最大值,並且滿足:s %n = ir => s = m*n + ir


proposer已知的最大值來自兩部分:proposer自己對編號自增後的值和接收到acceptor的reject後所得到的值

以3個proposer P1、P2、P3爲例,開始m=0,編號分別爲0,1,2

P1提交的時候發現了P2已經提交,P2編號爲1 > P1的0,因此P1重新計算編號:new P1 = 1*3+0 = 4

P3以編號2提交,發現小於P1的4,因此P3重新編號:new P3 = 1*3+2 = 5

 

整個paxos算法基本上就是圍繞着proposal編號在進行:proposer忙於選擇更大的編號提交proposal,acceptor則比較提交的proposal的編號是否已是最大,只要編號確定了,所對應的value也就確定了。所以說,在paxos算法中沒有什麼比proposal的編號更重要。

 

活鎖


當一proposer提交的poposal被拒絕時,可能是因爲acceptor promise了更大編號的proposal,因此proposer提高編號繼續提交。 如果2個proposer都發現自己的編號過低轉而提出更高編號的proposal,會導致死循環,也稱爲活鎖。

 

Leader選舉


 

活鎖的問題在理論上的確存在,Lamport給出的解決辦法是選舉出一個proposer作leader,所有的proposal都通過leader來提交,當Leader宕機時馬上再選舉其他的Leader。

Leader之所以能解決這個問題,是因爲其可以控制提交的進度,比如果之前的proposal沒有結果,之後的proposal就等一等,不着急提高編號再次提交,相當於把一個分佈式問題轉化爲一個單點問題,而單點的健壯性是靠選舉機制保證。

 

問題貌似越來越複雜,因爲又需要一個Leader選舉算法,但Lamport在fast paxos中認爲該問題比較簡單,因爲Leader選舉失敗不會對系統造成什麼影響,因此這個問題他不想討論。但是後來他又說,Fischer, Lynch, and Patterson的研究結果表明一個可靠的選舉算法必須使用隨機或超時(租賃)。

 

Paxos本來就是選舉算法,能否用paxos來選舉Leader呢?選舉Leader是選舉proposal的一部分,在選舉leader時再用paxos是不是已經在遞歸使用paxos?存在稱之爲PaxosLease的paxos算法簡化版可以完成leader的選舉,像Keyspace、Libpaxos、Zookeeper、goole chubby等實現中都採用了該算法。關於PaxosLease,之後我們將會詳細討論。

雖然Lamport提到了隨機和超時機制,但我個人認爲更健壯和優雅的做法還是PaxosLease。

 

Leader帶來的困惑


Leader解決了活鎖問題,但引入了一個疑問:

既然有了Leader,那只要在Leader上設置一個Queue,所有的proposal便可以被全局編號,除了Leader是可以選舉的,與Paxos算法1 提到的單點MQ非常相似。

那是不是說,只要從多個MQ中選舉出一個作爲Master就等於實現了paxos算法?現在的MQ本身就支持Master-Master模式,難道饒了一圈,paxos就是雙Master模式?

 

僅從編號來看,的確如此,只要選舉出單個Master接收所有proposal,編號問題迎刃而解,實在無須再走acceptor的流程。但paxos算法要求無論發生什麼錯誤,都能保證在每次選舉中能選定一個value,並能被learn學習。比如leader、acceptor,learn都可能宕機,之後,還可能“甦醒”,這些過程都要保證算法的正確性。

如果僅有一個Master,宕機時選舉的結果根本就無法被learn學習, 也就是說,Leader選舉機制更多的是保證異常情況下算法的正確性,虛驚一場,paxos原來不是Master-Master。

在此,我們第一次提到了"learn"這個角色,在value被選擇後,learn的工作就是去學習最終決議,學習也是算法的一部分,同樣要在任何情況下保證正確性,後續的主要工作將圍繞“learn”展開。

 

Paxos與二段提交


Google的人曾說,其他分佈式算法都是paxos的簡化形式。

假如leader只提交一個proposal給acceptor的簡單情況:

  • 發送prepared給多數派acceptor
  • 接收多數派的響應
  • 發送accept給多數派使其批准對應的value

其實就是一個二段提交問題,整個paxos算法可以看作是多個交叉執行而又相互影響的二段提交算法。

 

如何選出多個Value


Paxos算法描述的過程是發生在“一次選舉”的過程中,這個在前面也提到過,實際Paxos算法執行是一輪接一輪,每輪還有個專有稱呼:instance(翻譯成中文有點怪),每instance都選出一個唯一的value。

 

在每instanc中,一個proposal可能會被提交多次才能獲得acceptor的批准,一般做法是,如果acceptor沒有接受,那proposer就提高編號繼續提交。如果acceptor還沒有選擇(多數派批准)一個value,proposer可以任意提交value,否則就必須提交意見選擇的,這個在P2c 中已經說明過。

 

Paxos中還有一個要提一下的問題是,在prepare階段提交的是proposal的編號,之後再決定提交哪個value,就是value與編號是分開提交的,這與我們的思維有點不一樣。

 

3. 學習決議

在決議被最終選出後,最重要的事情就是讓learn學習決議,學習決議就是決定如何處理決議。

在學習的過程中,遇到的第一個問題就是learn如何知道決議已被選出,簡單的做法就是每個批准proposal的acceptor都告訴每個需要學習的learn,但這樣的通信量非常大。簡單的優化方式就是隻告訴一個learn,讓這個唯一learn通知其他learn,這樣做的好是減少了通信量,但壞處同樣明顯,會形成單點;當然折中方案是告訴一小部分learn,複雜性是learn之間又會有分佈式的問題。

無論如何,有一點是肯定的,就是每個acceptor都要向learn發送批准的消息,如果不是這樣的話,learn就無法知道這個value是否是最終決議,因此優化的問題縮減爲一個還是多個learn的問題。

 

能否像proposer的Leader一樣爲learn也選個Leader?因爲每個acceptor都有持久存儲,這樣做是可以的,但會把系統搞的越來越複雜,之後我們還會詳細討論這個問題。

Learn學習決議時,還有一個重要的問題就是要按順序學習,之前的選舉算法花費很多精力就是爲了給所有的proposal全局編號,目的是能被按順序使用。但learn收到的決議的順序可能不不一致,有可能先收到10號決議,但9號還未到,這時必須等9號到達,或主動向acceptor去請求9號決議,之後才能學習9號、10號決議。

 

4. 異常情況、持久存儲

在算法執行的過程中會產生很多的異常情況,比如proposer宕機、acceptor在接收proposal後宕機,proposer接收消息後宕機,acceptor在accept後宕機,learn宕機等,甚至還有存儲失敗等諸多錯誤。

但無論何種錯誤必須保證paxos算法的正確性,這就需要proposer、aceptor、learn都做能持久存儲,以做到server”醒來“後仍能正確參與paxos處理。

  • propose該存儲已提交的最大proposal編號、決議編號(instance id)
  • acceptor儲已promise的最大編號;已accept的最大編號和value、決議編號
  • learn存儲已學習過的決議和編號

以上就是paxos算法的大概介紹,目的是對paxos算法有粗略瞭解,知道算法解決什麼問題、算法的角色及怎麼產生的,還有就是算法執行的過程、核心所在及對容錯處理的要求。

但僅根據上面的描述還很難翻譯成一個可執行的算法程序,因爲還有無限多的問題需要解決:

  • Leader選舉算法
  • Leader宕機,但新的Leader還未選出,對系統會有什麼影響
  • 更多交叉在一起的錯誤發生,還能否保證算法的正確性
  • learn到達該怎麼學習決議
  • instance no、proposal no是該維護在哪裏?
  • 性能

衆多問題如雪片般飛來,待這些都逐一解決後才能討論實現的問題。當然還有一個最重要的問題,paxos算法被證明是正確的,但程序如何能被證明是正確的?

 

更多的請參考後面的章節。

發佈了32 篇原創文章 · 獲贊 77 · 訪問量 69萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章