用三國殺講分散式演算法,舒適了吧?
前言
《三國殺》是一款熱門的卡牌遊戲,結合中國三國時期背景,以身份為線索,以卡牌為形式,益智休閒,老少皆宜。
東漢末年,袁紹作為盟主,匯合了十八路諸侯一起攻打董卓。
在講解之前,我們先聊下分散式協議和演算法整體脈絡。
現在很多開發同學對分散式的元件怎麼使用都有一定經驗,也知道 CAP
理論和 BASE
理論的大致含義。但認真去看分散式演算法的真的很少,原因有三
:
擔心演算法過於複雜,所以花的時間很少。 網上的資料能用大白話將分散式演算法講清楚的比較少。 學習分散式演算法沒有一條清晰的路線。
學習路線
學習分散式協議和演算法的路線可以是先學習四大基礎理論,作為地基,再學習分散式協議和演算法,就像是在地基上建房子。地基打好了,才能建更穩固的高樓大廈。
四大基礎理論
拜占庭將軍問題 CAP 理論 ACID 理論 BASE 理論
八大分散式協議和演算法
Paxos 演算法 Raft 演算法 一致性 Hash 演算法 Gossip 協議演算法 Quorum NWR 演算法 FBFT 演算法 POW 演算法 ZAB 協議
因篇幅原因,本篇只涉及拜占庭將軍問題。
拜占庭將軍問題
大家可能聽過拜占庭將軍問題。它是由萊斯利·蘭伯特提出的點對點通訊中的基本問題,
拜占庭
位於如今的土耳其的伊斯坦布林
,是東羅馬帝國
的首都。由於當時拜占庭羅馬帝國國土遼闊,為了達到防禦目的,每個軍隊都分隔很遠,將軍與將軍之間只能靠信差傳訊息。在戰爭的時候,拜占庭軍隊內所有將軍和副官必須達成一致的共識,決定是否有贏的機會才去攻打敵人的陣營。但是,在軍隊內有可能存有叛徒和敵軍的間諜,這個就是拜占庭容錯問題。
實際上拜占庭問題是分散式領域最複雜的一個容錯模型,一旦理解它,就能掌握分散式共識問題的解決思路,還能幫助大家理解常用的共識演算法,也可以幫助我們在工作中選擇合適的演算法,或者設計合適的演算法。
為什麼第一個基礎理論是拜占庭將軍問題?
因為它很好地抽象出了分散式系統面臨的共識問題。
上面提到的 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 演算法。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2924967/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 三面阿里,面試官:講講分散式的CAP定理阿里面試分散式
- NoSQL資料庫的分散式演算法講解SQL資料庫分散式演算法
- 分散式ID系列(5)——Twitter的雪法演算法Snowflake適合做分散式ID嗎分散式演算法
- 分散式ID系列(2)——UUID適合做分散式ID嗎分散式UI
- 分散式演算法分散式演算法
- 分散式系統(三)——分散式事務分散式
- 分散式事務解決方案與適用場景分析分散式
- Git Message能引起極度舒適?Git
- 從“三國殺”到“三國殺+”,遊卡的IP生態創新之路
- 《三國殺》臺詞“殺”字遭和諧 網友:變成了三國打
- 基於redis分散式鎖實現“秒殺”Redis分散式
- 分散式之 Redis 複習精講分散式Redis
- 幽默!分散式系統共識演算法的三階段分散式演算法
- 分散式共識演算法分散式演算法
- 各種分散式事務的實現方式適用的場景分散式
- 《springcloud 三》分散式配置中心SpringGCCloud分散式
- elasticsearch(三)---分散式叢集Elasticsearch分散式
- 廣州辦公室出租,舒適靈活性
- 三國殺、狼人殺、劇本殺——社交演繹遊戲發展史遊戲
- 分散式 ID 生成演算法 — SnowFlake分散式演算法
- Worldpay:中國消費者期望更舒適的移動購物體驗
- TCC真沒這麼簡單,一文講透|分散式事務系列(三)分散式
- 分散式鎖初窺-分散式鎖的三種實現方式分散式
- 用Java寫一個分散式快取——快取淘汰演算法Java分散式快取演算法
- 求一個 phpstorm 的舒適護眼主題PHPORM
- Jtti:什麼是分散式伺服器?特點和適用場景分析Jtti分散式伺服器
- 分散式協議與演算法-Paxos演算法分散式協議演算法
- 分散式協議與演算法-Raft演算法分散式協議演算法Raft
- 分散式ID系列(3)——資料庫自增ID機制適合做分散式ID嗎分散式資料庫
- 從構建分散式秒殺系統聊聊WebSocket推送通知分散式Web
- 分散式:分散式事務(CAP、兩階段提交、三階段提交)分散式
- 分散式系統的Raft演算法分散式Raft演算法
- 分散式雪花演算法獲取id分散式演算法
- 分散式系統原理---CBCAST演算法分散式AST演算法
- Redis 應用-分散式鎖Redis分散式
- 分散式之訊息佇列複習精講分散式佇列
- 分散式應用的登入檢驗解決方案 JWT講解( json web token)分散式JWTJSONWeb
- Google分散式三篇論文--MapReduceGo分散式