以前《淺談分佈式CAP定理》簡單介紹了數據在分佈式系統中存在的必然定理。簡單回顧一下,一個數據在一個節點須要同步到另一個節點的過程當中,在未完成同步的時候,會出現數據不一致的狀況,因此此時必然存在分區容錯性(Partition tolerance)。分佈式系統只能從一致性(Consistency)或可用性(Availability)之間去選擇。redis
CAP講的是分佈式一致性,而此次咱們來聊聊分佈式共識性。不少開發者一直覺得一致性與共識性是同一個東西,但二者講的是徹底不一樣的東西。算法
共識性比較常見的場景就是選主,例如redis主掛掉了,集羣通用共識性算法選出一個主。比特幣之類的電子貨幣也須要更復雜的共識性算法。網絡
下面咱們一步步聊下分佈式共識性的一些常見算法與問題。分佈式
Leslie Lamport(論文排版系統LaTeX的開發者,同時也是2013年的圖靈獎得主)在其論文中描述了以下系統:ide
一組拜占庭將軍分別各率領一支軍隊共同圍困一座城市。加密
爲了簡化模型,將各支軍隊的行動策略限定爲進攻或撤離兩種。由於部分軍隊進攻部分軍隊撤離可能會形成災難性後果,所以各位將軍必須經過投票來達成一致策略,即全部軍隊一塊兒進攻或全部軍隊一塊兒撤離。設計
同時各位將軍分處城市不一樣方向,他們只能經過信使互相聯繫。在投票過程當中每位將軍都將本身投票給進攻仍是撤退的信息經過信使分別通知其餘全部將軍,這樣一來每位將軍根據本身的投票和其餘全部將軍送來的信息就能夠知道共同的投票結果而決定行動策略。中間件
此係統的名字叫作拜占庭將軍問題。從描述中,能夠顯然知道,將軍們須要經過少數服從多數的算法在分佈式的場景下進行投票決議一個一致性的決定去執行。blog
在拜占庭將軍問題中,默認是認爲信使是不會被截獲而且消息會傳遞到的。更多的狀況中,將軍中可能會出現叛徒、信使會被截獲冒充、消息沒法到達。而叛徒或信使冒充會惡意地向其餘將軍投票,給不一樣將軍展現不一樣的投票結果,從而破壞了將軍們執行的一致性。而此類錯誤則稱爲拜占庭錯誤。進程
若是系統能處理拜占庭將軍錯誤正常運行的話,則稱系統擁有拜占庭容錯「Byzantine fault tolerance」,簡稱爲BFT。
假設當時有5位將軍投票(單數投票的結果必能造成少數服從多數),其中有1名是叛徒,4名忠誠的將軍中出2人投進攻,2人投撤離的。
這時候叛徒可能故意給2名投進攻的將軍送信表示投進攻,而給另外2名投撤離的將軍送信表示投撤離。這樣在2名投進攻的將領看來,投票結果是3人投進攻,從而發起進攻;而在2名投撤離的將軍看來則是3人投撤離。這樣各支軍隊的一致協同就遭到了破壞,結果是災難性的。
即便這5個將軍都是忠誠的,但投票結果是須要信使在將軍之間去傳遞的,而這些信使在傳遞過程當中是有可能被截冒充或者並無傳遞到將軍的投票結果,最終仍是會影響軍隊的一致協同。
上述的故事映射到計算機系統中,將軍便成了計算機,而信使則是通訊系統。有人會以爲這個問題能夠經過加密或簽名的方式解決,但本質上加密過程、簽名算法也會出錯。雖然加密和簽名必定程度是能夠解決這個問題,但這個問題並非要討論這些加密簽名的強度,而是更多地在於研究集羣系統客觀上已經出現錯誤了,他們要怎麼在存在錯誤的狀況下讓系統正常的工做。
首先要知道,爲何這個標題是經典的簡單解決?由於這個解決只是個簡單的解決,在現代系統不少場景中,並不具備廣泛的解決能力。
你們看完上面的例子,可能會涌現一種想法,就是在收到來自同一個將軍的投票後,交換各自的結果檢驗看該將軍是否叛徒。例如A將軍把進攻指令發給B將軍,把撤離指令發給C將軍,那麼BC將軍交互一下來自A將軍的指令,就能夠知道A將軍是個叛徒,而後把他揪出來幹掉,再也不聽他的指令。
可是這種作法根本不能解決問題。雖然在BC交換指令後,能夠知道有叛徒的存在,但其實你並不能肯定A就是叛徒,由於有可能BC交換指令的過程出現」拜錯「,因此上面的思路並不能解決問題。
回到問題自己,咱們是須要在存在錯誤的狀況下讓系統正常進行,因此咱們只須要設計一套系統在兼容這些」叛徒「就足夠了。怎麼理解?回到拜占庭軍隊上,拜占庭軍隊攻下一座城池至少須要6個將軍,那麼讓軍隊裝備更多將軍,例如10個,在經過兩兩交互指令驗證完消息後,能夠知道有多少個叛徒的存在。只要忠誠的將軍數大於等於6那麼就能夠執行指令(進攻或撤離),不然軍隊則按兵不動。這個容錯率能夠根據本身的系統進行設置,在這個方案被提出時,容錯率描述是1/3。
開頭也說到這個方案在現代系統並不具備廣泛解決問題的能力。一是相似比特幣這種分佈式記帳本千千萬個節點,若是要進行兩兩的信息驗證,這個過程和開銷是很是大的,會變得不實際。另外就是並非全部性質的系統都能容許錯誤節點的執行,例如註冊中心、交易中心等。
在「簡單解決」的方案提出以後,有很是多的方案算法被提出,實用拜占庭容錯(PBFT)、聯邦拜占庭協議(FBA)、受權拜占庭容錯算法(dBFT)等等。因爲其中的複雜度與文章篇幅問題,不一一贅述,有興趣能夠到網上查閱。
但其中一個比較有意思的是比特幣中所用到的工做量證實「Proof Of Work,POW」能夠大概提一下。
工做量證實是一種對應服務與資源濫用、或是拒絕服務侵入的經濟對策。通常是要求用戶進行一些耗時適當的複雜運算,而且答案能被服務方快速驗算,以此耗用的時間、設備與能源作爲擔保成本,以確保服務與資源是被真正的需求所使用。(來自維基百科的解釋)
結合比特幣的場景去理解,用戶是須要經過挖礦來得到比特幣,而挖礦是須要花費大量的計算資源的。這個挖礦的過程實際上是比特幣設計的一道解密算法,用戶(節點)是須要必定量的計算才能得到答案,而後其餘給節點驗算,成功後最終得到比特幣獎勵爭取記帳權。一句話歸納工做量證實就是不校驗你的過程,只看你的結果,但獲取這個結果是有壁壘的。具體的算法原理在後續講到共識性算法的應用咱們再用新篇幅去闡述。
那麼比特幣怎樣才能造假呢?其實它本質依然是少數服從多數的投票,節點獲取結果後是須要其餘節點進行驗證投票的,若是你擁有大於50%的假節點,的確是能夠篡改數據,控制交易。可是工做量證實引入使得構造一個節點的成本已經足夠大了,在千千萬的節點下想要構造大於50%的假節點,估計有這種財力去實現的人已經能夠統治地球了。
拜占庭將軍錯誤看似一個很是嚴重的問題,能形成災難性後果,但其實在大部分場景下並不會出現「拜錯」。下一篇將會落到比較應用層面的共識性算法,聊下市面上主流的分佈式中間件是怎麼在不考慮「拜錯」的狀況下,解決分佈式共識性問題的。
更多技術文章、精彩乾貨,×××
我的博客:zackku.com ×××碼