淺顯易懂地解讀Paxos演算法
什麼是Paxos演算法?
Paxos演算法是分散式技術大師Lamport提出的。
(世外高人的即視感,有木有?)這個演算法的主要目的是:讓參與分散式處理的每個參與者逐步達成一致意見。用好理解的方式來說,就是在一個選舉過程中,讓不同的選民最終做出一致的決定。
Lamport為了講述這個演算法,假想了一個叫做Paxos的希臘城邦進行選舉的情景,這個演算法也是因此而得名。在他的假想中,這個城邦要採用民主提議和投票的方式選出一個最終的決議,但由於城邦的居民沒有人願意把全部時間和精力放在這種事情上,所以他們只能不定時的來參加提議,不定時來了解提議、投票進展,不定時的表達自己的投票意見。Paxos演算法的目標就是讓他們按照少數服從多數的方式,最終達成一致意見。
這樣做的意義何在呢?
如果你了解分散式系統,那就比較好理解上面做法的意義了。如果你不了解也沒關係,用最簡單的方式解釋:以前都是一台伺服器幹活,但是後來發現一台伺服器壞了,乾的活就要停下來。於是,聰明人發明了多台伺服器同時幹活的方案。但這個方案有個問題,多台伺服器同時提出下一步幹什麼事情時,最終聽誰的呢?這時,Paxos演算法橫空出世了,利用它,可以在這多台伺服器中間建立一種選舉機制,並通過這個機制最終讓所有伺服器對下一步動作達成一致意見。這樣,無論有多少台伺服器同時工作,都不會發生衝突啦~
下面開始介紹Paxos演算法的具體情況:
Paxos演算法其實很簡單,就是一個先提議再投票的過程。關鍵點包括:
1、演算法涉及的主要角色:主要的角色就是「提議者」(向「接受者」提出提議)和「接受者」(收到「提議者」的提議後,向「提議者」表達自己的意見)。先有提議,再來表決,這個很好理解。(註:實際應用中,可以將一堆伺服器任意指定角色,一部分做「提議者」、一部分做「接受者」,也可以指定特定的伺服器做「提議者」,剩下的都是「接受者」。)
2、整個演算法的大致過程為:
第一階段:因為存在多個「提議者」,如果都提意見,那麼「接受者」接受誰的不接受誰的?太混亂了。所以,要先明確哪個「提議者」是意見領袖有權提出提議,未來,「接受者」們就主要處理這個「提議者」的提議了(這樣,也可以在提出提議時就盡量讓意見統一,謀求儘早形成多數派)。第二階段:由上階段選出的意見領袖提出提議,「接受者」反饋意見。如果多數「接受者」接受了一個提議,那麼提議就通過了。3、必須要了解的其他相關規則:1)怎麼明確意見領袖呢?通過編號。每個「提議者」在第一階段先報個號,誰的號大,誰就是意見領袖。如果不好理解,可以想像為賄選。每個提議者先拿著鈔票賄賂一圈「接受者」,誰給的錢多,第二階段「接受者」就聽誰的。(註:這裡和下文提到的「意見領袖」,並不是一個新的角色,而是代表在那一輪賄賂成功的「提議者」。所以,請把意見領袖理解為賄賂中勝出的「提議者」即可)2)有個跟選舉常識不一樣的地方,就是每個「提議者」不會執著於讓自己的提議通過,而是每個「提議者」會執著於讓提議儘快達成一致意見。所以,為了這個目標,如果「提議者」在賄選的時候,發現「接受者」已經接受過前面意見領袖的提議了,即便「提議者」賄選成功,也會默默的把自己的提議改為前面意見領袖的提議。所以一旦賄賂成功,勝出的「提議者」再提出提議,提議內容也是前面意見領袖的提議(這樣,在謀求儘早形成多數派的路上,又前進了一步)。
3)錢的多少很重要,如果錢少了,無論在第一還是第二階段「接受者」都不會尿你,直接拒絕。4)上面2)中講到,如果「提議者」在賄選時,發現前面已經有意見領袖的提議,那就將自己的提議默默改成前面意見領袖的提議。這裡有一種情況,如果你是「提議者」,在賄賂的時候,「接受者1」跟你說「他見過的意見領袖的提議是方案1」,而「接受者2」跟你說「他見過的意見領袖提議是方案2」,你該怎麼辦?這時的原則也很簡單,還是:錢的多少很重要!你判斷一下是「接受者1」見過的意見領袖有錢,還是「接受者2」見過的意見領袖有錢?如何判斷呢?因為「接受者」在被「提議者」賄賂的時候,自己會記下賄賂的金額。所以當你賄賂「接受者」時,一旦你給的賄賂多而勝出,「接受者」會告訴你兩件事情:a.前任意見領袖的提議內容(如果有的話),b.前任意見領袖當時賄賂了多少錢。這樣,再面對剛才的情景時,你只需要判斷一下「接受者1」和「接受者2」告訴你的信息中,哪個意見領袖當時給的錢多,那你就默默的把自己的提議,改成那個意見領袖的提議。5)最後這一部分最有意思,但描述起來有點繞,如果不能一下子就理解可以先看後面的例子。在整個選舉過程中,每個人誰先來誰後到,「接受者」什麼時間能夠接到「提議者」的信息,是完全不可控的。所以很可能一個意見領袖已經產生了,但是由於這個意見領袖的第二階段剛剛開始,絕大部分「接受者」還沒有收到這個意見領袖的提議。結果,這時突然衝進來了一個新的土豪「提議者」,那麼這個土豪「提議者」也是有機會讓自己的提議勝出的!這時就形成了一種博弈:a.上一個意見領袖要趕在土豪「提議者」賄賂到「接受者」前,趕到「接受者」面前讓他接受自己的提議,否則會因為自己的之前賄賂的錢比土豪少而被拒絕。b.土豪「提議者」要趕在上一個意見領袖將提議傳達給「接受者」前,賄賂到「接受者」,否則土豪「提議者」即便賄賂成功,也要默默的將自己的提議改為前任意見領袖的提議。這整個博弈的過程,最終就看這兩個「提議者」誰的進展快了。但最終一定會有一個意見領袖,先得到多數「接受者」的認可,那他的提議就勝出了。4、總結好啦,故事到這裡基本講述完了,咱們來總結一下,其實Paxos演算法就下面這麼幾個原則:1)Paxos演算法包括兩個階段:第一個階段主要是賄選,還沒有提出提議;第二個階段主要根據第一階段的結果,明確接受誰的提議,並明確提議的內容是什麼(這個提議可能是賄選勝出「提議者」自己的提議,也可能是前任意見領袖的提議,具體是哪個提議,往下看,見下面第3點的內容)。2)編號(賄賂金額)很重要,無論在哪個階段,編號(賄賂金額)小的,都會被鄙視(被拒絕)。3)在第一階段中,一旦「接受者」已經接受了之前意見領袖的提議,那後面再來找這個「接受者」的「提議者」,即便在賄賂中勝出,也要被洗腦,默默將自己的提議改為前任意見領袖的提議,然後他會在第二階段提出該提議(也就是之前意見領袖的提議,以力爭讓大家的意見趨同)。如果「接受者」之前沒有接受過任何提議,那賄選勝出的「提議者」就可以提出自己的提議了。5、舉例
最後舉個例子,加深一下印象:有兩個「提議者」和三個「接受者」。1)首先「提議者1」賄賂了3個「接受者」2)3個「接受者」記錄下賄賂金額,因為目前只有一個「提議者」出價,因此$1就是最高的了,所以「接受者」們返回賄賂成功。此外,因為沒有任何先前的意見領袖提出的提議,因此「接受者」們告訴「提議者1」沒有之前接受過的提議(自然也就沒有上一個意見領袖的賄賂金額了)。3)「提議者1」向「接受者1」提出了自己的提議:1號提議,並告知自己之前已賄賂$1。4)「接受者1」檢查了一下,目前記錄的賄賂金額就是$1,於是接受了這一提議,並把1號提議記錄在案。推薦閱讀:
※分散式系統理論基礎 - 時間、時鐘和事件順序
※Scaling Memcache in Facebook 筆記(二)
※分散式系統理論進階 - Raft、Zab
※搞分散式,大數據都寫些什麼代碼,是不是寫不了幾行?
※bifrost : Rust 下的分散式系統框架