前言
本文參考Paxos made simple這篇論文, 對Paxos演算法的推導過程用接地氣的場景來表述. 下文會從"n個同學開party, 需要確定誰來當東道主"的場景, 一步一步的推導出Paxos演算法.
背景
假設有n個同學, 準備週末去某個人家裡開party, 他們現在需要確認他們這些人中究竟誰做東道主負責party的舉辦事宜.
每個人都可以提議自己當東道主, 並且有權同意、否決別人的提議(也就是系統中, 每個節點既是proposer, 又是acceptor).另外, 他們每個人之間都是點對點通信的, 比如說通過微信私聊的方式.
那麼, 通過什麼投票方案可以得到一個共識呢? 總體方向肯定就是"多數派原則"了. 但是這個原則之下, 還是有很多邊邊角角的問題會導致無法達成共識, 還需要有具體措施來規避這些問題.
下面會從"多數派原則"這個最基本方案, 一步一步的解決遇到的問題, 一次次的迭代, 最終漸漸推導出完善的一套方案: Paxos!
例如, 下文的版本1隻是使用"多數派原則"這個基本方案存在明顯的漏洞, 後面的版本2、3、4在版本1的基礎上, 一步一步的解決這些問題.
版本1 多數派原則
問題:
無法達成多數派, 出現split vote, 形成僵持局面
假設n=5, 共有ABCDE這些個同學(系統中有5個節點).
另外還假設這些同學脾氣都很犟, 不肯變通, 自己同意了一個提議後, 打死都不再改變主意了(不允許各個節點accept一個值後, 不能再改變).
我們看看這樣的設定會有什麼問題, 最後來思考如何避免這個問題.
那麼考慮這個場景: 同學A向提議"來我家", AB都同意了; 與此同時, 同學C提議"來我家", CD都同意了; 與此同時,同學E提議"來我家", E自己同意了. 這樣下來, 沒有一個提議可以形成多數派.
由於這些同學脾氣都很犟, 互不相讓,不再改變主意, 那麼這次開party肯定就泡湯了, 因為5個同學沒有達成一致的共識.
解決方案:
允許acceptor改變自己的主意, 如果acceptor即是已經accept了某個值, 後面也可以accept其他的提議.
也就是一輪投票不成, 大家可以再商量商量, 不要脾氣犟的跟驢一樣.
版本2 節點可以接受後續的提議
在版本1的基礎上, 添加一個新措施: 節點可以改變主意, 接受後續的提議. 這樣我們就有了迭代2. 我們繼續看版本2的問題是什麼.
問題:
有acceptor在接受一個提議後又改變了主意, 可能會導致系統選擇了多個值(conflict choice)
假設n=5, 共有ABCDE這些個同學(系統中有5個節點).
另外還假設這些同學脾氣都很好, 可以改變自己的主意.
那麼考慮這個場景: 同學A向提議"來我家", ABC都同意了; 與此同時, 同學E提議"來我家", CDE都同意了;
這裡E充當了老好人的作用, 導致這5個同學都以為達成共識了, 同學們裡面有兩個人都認為自己是東道主了. 最後AB高高興興的在A的家裡開party, 然而CDE就是在E的家裡開party...
解決方案:
在proposer提議之前, 再引入一個prepare階段: 先向所有acceptor發起詢問, 詢問它有沒有已經接受某個值(accepted, 不一定是chosen. 當然, 在Paxos中, 這個accepted的值肯定也是最後被chosen的值), 如果有接受的值, 那proposer必須改變自己的提議值, 使用已經接受的值作為新的提議值. prepare階段之後, 再進行提議階段(accept階段).
版本3 兩階段協議
在版本2的基礎上, 引入了兩階段協議的思想. 這樣我們就有了版本3.
問題:
系統節點之間的通信沒有保障, 消息可能丟失, 也可能延時到達. 可能導致proposer誤認為當前還沒有被accepted值, 也就是兩階段協議形如虛設, 最後導致了和版本2一樣的問題(conflict choice)
假設n=5, 共有ABCDE這些個同學, 他們使用兩階段協議的思想來進行協商.
考慮如下圖所示場景: