這次準備開啟乙個新的系列來寫了,聊聊分布式系統中的關注點。節奏不會排的太緊湊,計畫兩周一更吧。本文是本系列的第二篇。是前一篇《不知道是不是最通俗易懂的《資料一致性》剖析了》的後續內容。
已經對資料一致性問題做了一次剖析,那麼怎麼解決由於故障導致的不一致問題呢?本文會圍繞「共識」這個點展開。
一致性問題其實是乙個「結果」,本質是由於資料冗餘導致的,如果沒有冗餘,也就不會有一致性問題了。
分布式系統裡的各個子系統之間之所以能夠相互協作,就是因為其之間冗餘了相同的資料作為「信物」,要不然我都不認識你的話,為什麼要配合你幹活呢。所以這個「信物」變了,你得通知我,要不然我又不認識你了。這個「信物」變更達成一致性的過程稱作達成「共識」。所以:
一致性問題是結果,共識是為達到這個結果所要經過的過程,或者說一種手段。
在分布式系統中,冗餘資料的場景不限於此,因為規模越大的系統,越不能容忍某乙個子系統出問題後產生蝴蝶效應,所以往往會做高可用。小明1號倒下了還有千千萬萬個小明x號在堅守崗位,理想中的全天候24小時提供服務~。高可用的本質是通過相同資料儲存多個副本,並都可對外提供服務。比如每個小明x號都有一本《按摩指法***》,誰請假了都可以由其它小明x號提供相同的按摩服務。但是這個本《按摩指法***》改了,就得通知到每個人,因為這是服務的全部和**,所以在做了高可用的集群中資料冗餘的問題更為突出。
實際上,如果分布式系統中各個節點都能保證瞬時響應、無故障執行,則達成共識很容易。就好像我們人一樣,在一定範圍內只要吼一嗓子,通過穩定的空氣傳播,相關人是否接收到這個訊息,並且給出響應幾乎可以是「瞬時」的。但是正如〖上篇,?點我〗文中提到,這樣的系統只停留在想象中,響應請求往往存在延時,網路會發生中斷,節點發生故障,甚至存在惡意節點故意要破壞系統。這就衍生出了經典的「拜占庭將軍問題」[1]。
我們一般把「拜占庭將軍問題」分為2種情況來看待:
拜占庭錯誤。表示通過偽造資訊進行惡意響應產生的錯誤。
非拜占庭錯誤。沒有進行響應產生的錯誤。
這個問題的核心在於:
如何解決某個變更在分布式網路中得到一致的執行結果,是被參與多方都承認的,同時這個資訊是被確定的,不可推翻的。
好比如何讓所有的小明x號收到的都是《按摩指法***ⅱ》,而不是其它的,並且把原來的那本銷毀掉。這個問題衍生出了很多「共識」演算法,解決「拜占庭錯誤」的稱作byzantine fault tolerance(bft)類演算法,解決「非拜占庭錯誤」的稱作crash fault tolerance(cft)類演算法。從這個2個名字中也可以看出,本質的工作就是「容錯」。有的小夥伴在平時的工作中可能對「容錯」的重要**知沒那麼強烈,不就產生乙個bug或者異常資料麼,但是在航天領域,乙個小錯誤可能導致整個發射的失敗,代價非常巨大。
我們常見的軟體開發中一般不會考慮「拜占庭錯誤」,但它是區塊鏈專案的必需品。不過在主流的分布式資料庫中,皆能看到「非拜占庭錯誤」的身影,諸如tidb的paxos演算法,cockroachdb的raft演算法。雖然我們大家在日常的coding中,對資料庫底層原理的了解並不是必須項。但是只要當我們涉及到應用程式級別的高可用時,那麼至少「非拜占庭錯誤」是必須要面臨的一道坎。
bft型別演算法又有2個分支。「基於確定性的」和「基於概率的」。
先聊聊「基於確定性的」,此類演算法表示一旦對某個結果達成共識就不可逆轉,即共識是最終結果。它的代表作是pbft(practical byzantine fault tolerance)演算法[2],自從有了央行背書(區塊鏈數字票據交易平台),名聲更大了。演算法的原理,如下圖:
拿軍隊來比喻,這裡的直線c可以認為是「總司令」,直線0是「軍長」,直線1、直線2、直線3都是「師長」,值得注意的是3號師長叛變了。整個過程這樣解釋:
「request」:總司令給軍長下了乙個命令,「幹!」。
「pre-prepare」:軍長把命令又廣播給3個師長。
「prepare」:每個師長收到並同意之後將傳送「收到」給軍長和其他兩個師長。
「commit」:每個師長收到2f個師長(軍長不做prepare)的「收到」請求後傳送「隨時開幹」給軍長和其他兩個師長。(f為可容忍的拜占庭節點數)
再聊聊「基於概率的」,此類演算法的共識結果則是臨時的,隨著時間推移或某種強化,共識結果被推翻的概率越來越小,成為事實上的最終結果。它的代表作是pow(proof of work)演算法,曾經高達2w美元/個的位元幣就是基於這個演算法來實現的。演算法的原理拿「修仙」來做個簡單的比喻(實際位元中的演算法比這更複雜):
被誤判的概率公式是: 0.5 ^ 個數,如果個數=6的話,誤判的概率是1.5625%。如果個數=10的話,就已經是0.09765625%了,指數級下降。
值得注意的是,「基於確定性的」和「基於概率的」對於不合作節點的標準是不同的,前者至多能容忍1/3,後者是小於1/2。
正如上面所說cft類演算法解決的是分布式系統中存在故障,但不存在惡意節點的場景(即可能訊息丟失或重複,但無錯誤訊息)下的共識達成問題。「拜占庭將軍問題」的提出者leslie lamport也在他另外的**[3]中提出過「paxos問題」,與這相似。在**中通過乙個故事模擬了這個問題,如下:
希臘島嶼paxon 上的「執法者」在「議會大廳」中表決通過『法律』,並通過「服務員」傳遞紙條的方式交流資訊,每個「執法者」會將通過的『法律』記錄在自己的「賬目」上。問題在於「執法者」和「服務員」都不可靠,他們隨時會因為各種事情離開「議會大廳」,並隨時可能有新的「執法者」進入「議會大廳」進行法律表決。這裡的關鍵物件在我們的系統中,可以模擬為:使用何種方式能夠使得這個表決過程正常進行,且通過的『法律』不發生矛盾。
leslie lamport自己也提出了解決這個問題的演算法,「paxos」演算法[4]。這個演算法的關鍵由以下3個定義來體現:
「paxos」演算法是一種無領導人(leaderless)演算法,實現比較複雜,所以產生了很多變種來簡化它,其中名氣最大的應該是「raft」,2023年才問世。「raft」演算法是一種領導人(leadership)的演算法。由以下2個過程保證達成共識:
雖然跟隨者的投票秉承先到先得,但是還是會遇到多個term相同的候選人獲得了相同票數(簡稱「分割投票問題」),那麼進行新一輪投票,直到決出勝負為止。由於raft用隨機定時器來自增term,加上網路是不穩定的,所以再次遇到相同票數的概率就大大降低了。
題外話,大家經常用的zookeeper裡的「zab」(zookeeper atomic broadcast)演算法也是cft類演算法,是以fast paxos演算法為基礎實現的。
回過頭來看,我們發現,想要更嚴謹的一致性,那麼就需要增加相互通訊確認的次數,但是這會導致效能低下,正如pbft和paxos一樣。但是分布式系統就是這樣,到處都需要balance,找到最適合的才是最重要的。
聊完了資料層面的「共識」問題,我們下回再聊聊「分布式事務」的問題,圍繞著常見的cap、base理論展開。
最後如果說想成為資料一致性專家,問有沒有捷徑的話。去閱讀老爺子leslie lamport的**就是捷徑,他的個人主頁:www.lamport.org/ 。
[1]《the byzantine generals problem, acm transactions on programming languages and systems》,leslie lamport,1982。
[2]《practical byzantine fault tolerance》,miguel castro&barbara liskov,1999。
[3]《the part-time parliament》,leslie lamport,1998。
[4]《in search of an understandable consensus algorithm》,diego ongaro&john ousterhout,2013
定期發表原創內容:架構設計丨分布式系統丨產品丨運營丨一些深度思考。
掃碼加入小圈子?
分布式系統關注點 初識 高可用
本文長度為2042字,建議閱讀6分鐘。所有 包裹的文字,只對第一次出現進行高亮顯示。閱讀目錄咳咳,從這篇開始,正式拉開分布式系統關注點中,我認為第二重要的內容 高可用 本篇的要點主要是明確 高可用 的定義,以及了解在分布式系統下哪些環節要做 高可用 為後續要講的策略 方式方案打下基礎。如有1年以上的...
分布式系統關注點 如何去實施 負載均衡 ?
本文長度為3032字,預計讀完需1.1mb流量,建議閱讀8分鐘。前面兩篇 分布式系統關注點 初識 高可用 分布式系統關注點 僅需這一篇,吃透 負載均衡 妥妥的 看完後,相信大家對實現高可用的思路和負載均衡的策略有了一些了解。這篇主要闡述一下在實施的時候主流的一些解決方案。再翻出第一篇中放出的一張圖來...
分布式系統關注點 如何去實施 負載均衡 ?
本文長度為3032字,預計讀完需1.1mb流量,建議閱讀8分鐘。前面兩篇 分布式系統關注點 初識 高可用 分布式系統關注點 僅需這一篇,吃透 負載均衡 妥妥的 看完後,相信大家對實現高可用的思路和負載均衡的策略有了一些了解。這篇主要闡述一下在實施的時候主流的一些解決方案。再翻出第一篇中放出的一張圖來...