在樸素Paxos算法中, 各個節點通過 Prepare 和 Accept 階段, 會達成一個值, 這個值一旦達成, 就不能被修改, 以下例子:git
圖示1github
上面的操做幾乎沒有任何實用價值, 因而演變成下面這種操做, 多個"實例(Instance)", 每一個Instance負責一輪Paxos投票, 這樣能夠有序肯定多個值, 造成日誌;算法
圖2數據庫
將日誌輸入到狀態機, 就造成了一套KV系統, 若是有全局統一的時鐘 能夠在日誌裏面帶上時間戳, KV裏面也帶上時間戳, 這樣能夠實現數據快照讀(snapshot);網絡
上面的paxos系統可用性依然不好, 由於以下緣由:性能
1. 即便提議沒有競爭, 每次提議依然須要2次寫盤(Prepare階段寫一次, Accept階段寫一次); 若是提議發生競爭, 寫盤次數會更高;動畫
2. 一個日誌被肯定以後, 落在多數派上的讀取能夠讀取到最新的值, 落在少數派上的讀取不能讀取到最新的值(取決於少數派何時可以同步到最新的日誌);日誌
因而, 算法進化成以下的形式,blog
1. 選出一個Leader, 每次寫和讀都落在Leader上, 這樣, 讀操做能獲取到最新的值;同步
2. Prepare只發起一次, 而後就是屢次Accept, 這樣能夠將寫盤次數下降;
雖然有Leader, 可是即便Follower上有寫入, 依然不會破壞一致性, 由於Follower上的寫入會提高Prepare(Promise ID)的值, 這種狀況下Multi Paxos會退化爲 Basic Paxos;
借用phxpaxos的技術文章裏的一句話來描寫Leader的做用---"Leader的引入是爲了性能, 不是爲了一致性";
選舉和續租暫時不講了, 我也沒怎麼看懂;
能夠看到, Paxos通過演化以後, 最終實現了以下的特性:
1. 讀寫落到Leader上, 讀操做能夠能夠讀取到最新的數據;
2. Leader的引入將2次或大於2次的磁盤寫降爲1次; (正常狀況下);
3. 發生從新選舉的狀況下, 數據最新的節點可以競選;
Raft用更簡單的方式實現了這些特性, 這裏有一個很是簡單的Raft協議動畫演示, 咱們能夠輕鬆的理解Raft:
http://thesecretlivesofdata.com/raft/
Raft中有幾個重要的概念:
日誌index(順序號)
日誌term)(時間)
兩階段: 日誌複製(Replicate)階段 和 日誌提交(Commit)階段;
Raft協議的細節咱們不講了, 咱們看看Raft是怎麼面對下面的問題的;
1. Leader崩潰了, 怎麼選舉; 要確保新的Leader是有最新日誌, 不影響讀操做;
Raft選舉須要2個參數, 日誌 Index和日誌時間戳; 落後的節點不可能得到多數派經過;
2. 網絡問題出現, 節點發生分裂, 該怎樣保證整個集羣的數據的Consensus;
分裂以後, 少數派的日誌沒法Commit,
Raft實現相對Paxos簡單, 不像Paxos那樣容易出錯, 因此有不少語言版的Raft實現, 國內著名開源數據庫TiDB貢獻了rust語言的實現: https://github.com/pingcap/raft-rs
咱們以Raft論文裏的示例, 留下一個問題來思考吧:
(a) 場景下, S1 掛掉, S5 競選(S5競選會獲得S3, S4, S5的贊成, 會遭到S2的拒絕, 由於S2的日誌Index和日期都大於S5);
(b) 場景下S5寫入3, 還沒複製到其餘節點就掛掉了;
(c) 場景下, S1又活過來, 競選成爲Leader, 將前次的 2 記錄的日誌"複製"給多數派;
由於不能Commit上個任期的日誌, 因此2折條日誌仍然是UnCommited;
而後新寫入了 4 的日誌, 沒來得及複製和Commit, S1又掛掉了;
下面兩種狀況能出現嗎?
(d) 場景下, S5活過來, 競選成爲Leader, 將日誌3 複製到其餘節點上;
或者
(e) 場景下, S1活過來, 競選成爲Leader, 將日誌 2, 4 覆蓋掉 S5 的日誌;
答案:
Raft爲了防止Commit的日誌被沖掉, 有一個重要的約束:
Leader不能 "直接提交上個任期複製過的日誌",
"只能提交這個任期的日誌, 使上個任期的日誌被間接提交";
因此:
(d)場景能夠出現, 由於2這個日誌並無被Commit, 能夠被S5的3覆蓋, 可是S5不能直接提交3這個日誌;
(e)場景能夠出現, S1經過 複製 和 提交 4 這條日誌, 使得 2 這條日誌被間接提交; 以後即便S1再掛掉, S5也不能得到多數派投票;