《三國殺》是一款熱門的卡牌遊戲,結合中國三國時期背景,以身份爲線索,以卡牌爲形式,益智休閒,老小皆宜。
東漢末年,袁紹做爲盟主,匯合了十八路諸侯一塊兒攻打董卓。算法
在講解以前,咱們先聊下分佈式協議和算法總體脈絡。小程序
如今不少開發同窗對分佈式的組件怎麼使用都有必定經驗,也知道 CAP
理論和 BASE
理論的大體含義。但認真去看分佈式算法的真的不多,緣由有三
:架構
我會在後續的文章中用故事、大白話的方式來說解分佈式算法的原理,以及學習路線究竟是怎麼樣的。分佈式
學習分佈式協議和算法的路線能夠是先學習四大基礎理論,做爲地基,再學習分佈式協議和算法,就像是在地基上建房子。地基打好了,才能建更穩固的高樓大廈。學習
因篇幅緣由,本篇只涉及拜占庭將軍問題。區塊鏈
你們可能聽過拜占庭將軍問題。它是由萊斯利·蘭伯特提出的點對點通訊中的基本問題,spa
拜占庭
位於現在的土耳其的伊斯坦布爾
,是東羅馬帝國
的首都。因爲當時拜占庭羅馬帝國國土遼闊,爲了達到防護目的,每一個軍隊都分隔很遠,將軍與將軍之間只能靠信差傳消息。在戰爭的時候,拜占庭軍隊內全部將軍和副官必須達成一致的共識,決定是否有贏的機會纔去攻打敵人的陣營。可是,在軍隊內有可能存有叛徒和敵軍的間諜,這個就是拜占庭容錯問題。設計
實際上拜占庭問題是分佈式領域最複雜的一個容錯模型,一旦理解它,就能掌握分佈式共識問題的解決思路,還能幫助你們理解經常使用的共識算法,也能夠幫助咱們在工做中選擇合適的算法,或者設計合適的算法。code
爲何第一個基礎理論是拜占庭將軍問題?教程
由於它很好地抽象出了分佈式系統面臨的共識問題。
上面提到的 8 種分佈式算法中有 5 種跟拜占庭問題相關,能夠說弄懂拜占庭問題對後面學習其餘算法就會容易不少。
下面我用三國殺遊戲中的身份牌來說解拜占庭將軍問題。
三國殺中主要有四種身份:主公、忠臣、反賊、內奸。每一個遊戲玩家都會得到一個身份牌。主公只有 1 個。忠臣 最多 2 個,反賊最多 4個,內奸最多一個。
主公身份牌
獲勝條件: 消滅全部反賊和內奸
技巧: 以本身生存爲首要目標,分散反賊注意力。配合忠內剿滅反賊並判斷誰是忠誰是內。
忠臣身份牌
獲勝條件:保護主公存活的前提下消滅全部反賊和內奸。
技巧:忠臣是主公的屏障,威懾反賊和內奸的天平。
反賊身份牌
獲勝條件:消滅主公便可獲勝。
技巧: 反賊做爲數量最多的身份,須要集中火力猛攻敵人弱點。正確的思路是獲勝的關鍵。
內奸身份牌
獲勝條件: 先消滅反賊和忠臣,最後與主公單挑成爲最後惟一輩子還者。
技巧:正確的戰術+ 冷靜的頭腦+ 運氣。
東漢末年,袁紹做爲盟主,匯合了十八路諸侯一塊兒攻打董卓。把董卓定爲反賊,袁紹定爲主公,另外有兩個忠臣和一個內奸,就選這三個風雲人物:曹操,劉備,孫堅(孫權的爸比),內奸扮演的角色是忠臣,主公和兩個忠臣不知道內奸的身份,都看成忠臣對待了。
董卓是很是強大的,擁有精良的西涼兵,麾下還有戰神呂布。你們都知道三英站呂布的故事,呂布以一已之力對陣劉備、張飛、關羽三人。
要想幹掉董卓,袁紹必須統一忠臣的做戰計劃,三位忠臣還不知道有什麼其餘花花腸子,有一個仍是內奸。若是內奸暗通反賊董卓,給忠臣發送誤導性的做戰信息,該怎麼辦?另外假定這幾個忠臣都是經過書信交流做戰信息,若是書信被攔截了或書信裏面的信息被替換了咋辦?這些場景均可能擾亂做戰計劃,最後出現有的忠臣在進攻,有的忠臣撤退了。那麼反賊就能夠乘此機會發起進攻,逐一攻破。
袁紹原本就沒有曹操的機智,那他如何讓忠臣們達成共識,制定統一的做戰計劃呢?
上面的映射關係就是一個拜占庭將軍問題的一個簡化表述,袁紹如今面臨的就是典型的共識問題。也就是在可能有誤導信息的狀況下,採用合適的通信機制,讓多個將軍達成共識,制定一致性的做戰計劃。
劉備、曹操、孫堅經過信使傳遞進攻或撤退的信息,而後進行協商,究竟是進攻仍是撤退。遵循少數服從多數,不容許棄權。
曹操疑心比較重,偵查了反賊的地形後,決定撤退。而劉備和孫堅定定進攻。
一方選擇撤退
曹操收到的信息:進攻 2 票,本身的一張撤退票,票數一比,進攻票:撤退票 = 2 : 1,按照上面的少數服從多數原則進行投票表決,曹操仍是會進攻。那麼三方的做戰方案都是進攻,因此是一個一致性的做戰方案。最後打敗了董卓。
由於咱們前期的設定,孫堅做爲內奸,早已與反賊董卓私下溝通好了,不攻打董卓。
內奸登場-撤退
劉備收到進攻和撤退各一票,而本身又選擇撤退,因此劉備獲得的票數是:進攻 : 撤退 = 1 : 2,聽從少數服從多數的原則,劉備選擇最後選擇撤退,那麼三方的做戰方案都是撤退,因此也是一個一致性的做戰方案。
內奸看了上述計劃,發現忠臣都撤退了,並無被消滅,就想經過使詐的方式來消滅其中一個忠臣。
內奸使詐-一進一退
那麼結果是什麼呢?
劉備的票數爲進攻 2 票,撤退 1 票,曹操的票數爲進攻 1 票,撤退 2 票。按照少數服從多數的原則,劉備最後會選擇進攻,而曹操會選擇撤退,孫堅做爲內奸確定不會進攻,劉備單獨進攻反賊董卓,勢單力薄,被董卓幹掉了。
從這個場景中,咱們看到內奸孫堅經過發送誤導信息,很是容易地就干擾了劉備和曹操的做戰計劃,致使兩位忠臣被逐一擊破。這個現象就是二忠一判難題。那麼主公袁紹該怎麼解決這個問題?
就是將袁紹也參與進來進行投票,這樣就增長了一位忠臣的數量。三個忠臣一個叛賊。而後 4 位將軍作了一個約定,若是沒有收到命令,則執行默認命令,好比撤退。另外約定流程來發送做戰信息和如何執行做戰指令。這個解法的關鍵點就是執行兩輪做戰信息協商。
咱們來看下第一輪是怎麼作的。
咱們用圖來演示:袁紹做爲主公先發送做戰信息,做戰指令爲進攻。而後曹操、劉備、孫堅收到進攻的做戰指令。
第一輪
再來看下第二輪是怎麼作的。
若是孫堅使詐,好比給曹操和劉備都發送撤退信息,以下圖所示。那麼劉備和曹操收到的做戰信息爲 進攻 2票,撤退 1 票,按照少數服從多數的原則,最後劉備和曹操執行進攻,實現了做戰計劃的一致性,曹操和劉備聯合做戰擊敗了反賊董卓(即便孫堅沒有參加做戰。)
孫堅使詐 - 兩撤退
假如孫堅使詐,給曹操發送撤退指令,給劉備發送進攻指令,那麼劉備收到的做戰信息是進攻 3票,確定會發起進攻了,而曹操收到的做戰信息是進攻 2 票,撤退 1 票,最後曹操仍是會進攻,因此劉備和曹操仍是聯合做戰擊敗了反賊董卓。
如此看來,引入了一位指揮官後,確實能夠避免孫堅使詐,但若是是孫堅在第一輪做爲指揮官,其餘人做爲副官呢?
孫堅使詐 - 一進一退
第一輪孫堅向其中一個副官袁紹發送撤退指令,向另外兩個副官曹操、劉備發送進攻指令。那麼第一輪的結果以下圖:
第一輪
第二輪孫堅休息,其餘副官按照孫堅發送的指令開始向另外的副官發送指令。
以下圖所示,最後曹操、劉備、袁紹收到的指令爲進攻 2 票,撤退 1 票,按照少數服從多數原則,三我的都是發起進攻。執行了一致的做戰計劃,保證做戰的勝利。
第二輪
經過上面的演示,咱們知道了如何解決拜占庭將軍問題。其實蘭伯特在他的論文中也提到過如何解決。
若是叛將人數爲 m,將軍數 n >= 3m + 1,那麼就能夠解決拜占庭將軍問題。前提條件:叛將數 m 已知,須要進行 m + 1 輪的做戰協商。
這個公式,你們只須要記住就能夠了,推到過程能夠參考論文。
好比上述的攻打董卓問題,曹操、劉備、孫堅三我的當中,孫堅是叛將,他可使詐,使做戰計劃不統一。必須增長一位忠臣袁紹來協商共識,才能達成一致性做戰計劃。
那能夠在不增長忠臣的狀況下,解決拜占庭的二忠一判問題呢?
解法二就是經過簽名消息。好比將軍之間經過印章、虎符等信物進行通訊。來保證這幾個特徵:
限於篇幅緣由,簽名的演示這裏就不作展開了,感興趣的@我,後續會加上。
經過三國殺角色來說解分佈式中共識場景。那他們和分佈式系統的映射關係是怎麼樣的呢?
可不要小瞧拜占庭問題,它但是分佈式場景最複雜的的故障場景。好比在數字貨幣的區塊鏈技術中就有用到這些知識點。並且必須使用拜占庭容錯算法(也就是 Byzantine Fault Tolerance,BFT
)。
拜占庭容錯算法還有 FBFT
算法,PoW
算法,固然不會在這篇中去講這些算法,後續再講解。一口吃不了大胖子~
有了拜占庭容錯算法,確定有非拜占庭容錯算法,顧名思義,就是沒有發送誤導信息的節點。CFT
算法就是解決分佈式系統中存在故障,但不存在惡意節點的場景下的共識問題。簡單來講就是可能因系統故障形成丟失消息或消息重複,但不存在錯誤消息、僞造消息。對應的算法有 Paxos
算法、Raft
算法、ZAB
協議。後續講解~
上面提到了 5 種算法,竟然都是跟拜占庭問題有關,你說今天講的拜占庭問題重要不重要?
這麼多算法該如何選擇?
節點可信,選非拜占庭容錯算法。不然就用拜占庭容錯算法,如區塊鏈中用到的 PoW 算法。
巨人的肩膀:分佈式協議與算法,極客時間
建了學習交流羣,能夠掃碼加我,備註[加羣] 一塊兒進階!
我是悟空,努力變強,變身超級賽亞人!
我是悟空,努力變強,變身超級賽亞人!手寫了一套 Spring Cloud 進階教程和 PMP 刷題小程序。 歡迎關注公衆號:悟空聊架構