分散式系統理論概述
分散式系統是什麼
分散式系統:一個硬體或軟體元件分佈在不同的網路計算機上,彼此之間僅僅通過訊息傳遞進行通訊和協調的系統
這是分散式系統,在不同的硬體,不同的軟體,不同的網路,不同的計算機上,僅僅通過訊息來進行通訊與協調
這是他的特點,更細緻的看這些特點又可以有:分佈性、對等性、併發性、缺乏全域性時鐘、
故障隨時會發生。
分佈性
既然是分散式系統,最顯著的特點肯定就是分佈性,從簡單來看,如果我們做的是個電商專案,整個專案會分成不同的功能,專業點就不同的微服務,比如使用者微服務,產品微服務,訂單微服務,這些服務部署在不同的tomcat中,不同的伺服器中,甚至不同的叢集中,整個架構都是分佈在不同的地方的,在空間上是隨意的,而且隨時會增加,刪除伺服器節點,這是第一個特性
對等性
對等性是分散式設計的一個目標,還是以電商網站為例,來說明下什麼是對等性,要完成一個分散式的系統架構,肯定不是簡單的把一個大的單一系統拆分成一個個微服務,然後部署在不同的伺服器叢集就夠了,其中拆分完成的每一個微服務都有可能發現問題,而導致整個電商網站出現功能的丟失。
比如訂單服務,為了防止訂單服務出現問題,一般情況需要有一個備份,在訂單服務出現問題的時候能頂替原來的訂單服務。
這就要求這兩個(或者2個以上)訂單服務完全是對等的,功能完全是一致的,其實這就是一種服務副本的冗餘。
還一種是資料副本的冗餘,比如資料庫,快取等,都和上面說的訂單服務一樣,為了安全考慮需要有完全一樣的備份存在,這就是對等性的意思。
併發性
併發性其實對我們來說並不模式,在學習多執行緒的時候已經或多或少學習過,多執行緒是併發的基礎。
但現在我們要接觸的不是多執行緒的角度,而是更高一層,從多程序,多JVM的角度,例如在一個分散式系統中的多個節點,可能會併發地操作一些共享資源,如何準確並高效的協調分散式併發操作。
後面實戰部分的分散式鎖其實就是解決這問題的。
缺乏全域性時鐘
在分散式系統中,節點是可能反正任意位置的,而每個位置,每個節點都有自己的時間系統,因此在分散式系統中,很難定義兩個事務糾結誰先誰後,原因就是因為缺乏一個全域性的時鐘序列進行控制,當然,現在這已經不是什麼大問題了,已經有大把的時間伺服器給系統呼叫
故障隨時會發生
任何一個節點都可能出現停電,宕機等現象,伺服器叢集越多,出現故障的可能性就越大,隨著叢集數目的增加,出現故障甚至都會成為一種常態,怎麼樣保證在系統出現故障,而系統還是正常的訪問者是作為系統架構師應該考慮的。
分散式系統協調“方法論”
分散式系統帶來的問題
如果把分散式系統和平時的交通系統進行對比,哪怕再穩健的交通系統也會有交通事故,分散式系統也有很多需要攻克的問題,比如:通訊異常,網路分割槽,三態,節點故障等。
通訊異常
通訊異常其實就是網路異常,網路系統本身是不可靠的,由於分散式系統需要通過網路進行資料傳輸,網路光纖,路由器等硬體難免出現問題。只要網路出現問題,也就會影響訊息的傳送與接受過程,因此資料訊息的丟失或者延長就會變得非常普遍。
網路分割槽
網路分割槽,其實就是腦裂現象,本來有一個交通警察,來管理整個片區的交通情況,一切井然有序,突然出現了停電,或者出現地震等自然災難,某些道路接受不到交通警察的指令,可能在這種情況下,會出現一個零時工,片警零時來指揮交通。
但注意,原來的交通警察其實還在,只是通訊系統中斷了,這時候就會出現問題了,在同一個片區的道路上有不同人在指揮,這樣必然引擎交通的阻塞混亂。
這種由於種種問題導致同一個區域(分散式叢集)有兩個相互衝突的負責人的時候就會出現這種精神分裂的情況,在這裡稱為腦裂,也叫網路分割槽。
. 三態
三態是什麼?三態其實就是成功,與失敗以外的第三種狀態,當然,肯定不叫變態,而叫超時態。
在一個jvm中,應用程式呼叫一個方法函式後會得到一個明確的相應,要麼成功,要麼失敗,而在分散式系統中,雖然絕大多數情況下能夠接受到成功或者失敗的相應,但一旦網路出現異常,就非常有可能出現超時,當出現這樣的超時現象,網路通訊的發起方,是無法確定請求是否成功處理的。
節點故障
這個其實前面已經說過了,節點故障在分散式系統下是比較常見的問題,指的是組成伺服器叢集的節點會出現的宕機或“僵死”的現象,這種現象經常會發生。
CAP理論
前面花費了很大的篇幅來了解分散式的特點以及會碰到很多會讓人頭疼的問題,這些問題肯定會有一定的理論思想來解決問題的。
接下來花點時間來談談這些理論,其中CAP和BASE理論是基礎,也是面試的時候經常會問到的
首先看下CAP,CAP其實就是一致性,可用性,分割槽容錯性這三個詞的縮寫
一致性
一致性是事務ACID的一個特性【原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、永續性(Durability)】,學習資料庫優化的時候deer老師講過。
這裡講的一致性其實大同小異,只是現在考慮的是分散式環境中,還是不單一的資料庫。
在分散式系統中,一致性是資料在多個副本之間是否能夠保證一致的特性,這裡說的一致性和前面說的對等性其實差不多。如果能夠在分散式系統中針對某一個數據項的變更成功執行後,所有使用者都可以馬上讀取到最新的值,那麼這樣的系統就被認為具有【強一致性】。
可用性
可用性指系統提供服務必須一直處於可用狀態,對於使用者的操作請求總是能夠在有限的時間內訪問結果。
這裡的重點是【有限的時間】和【返回結果】
為了做到有限的時間需要用到快取,需要用到負載,這個時候伺服器增加的節點是為效能考慮;
為了返回結果,需要考慮伺服器主備,當主節點出現問題的時候需要備份的節點能最快的頂替上來,千萬不能出現OutOfMemory或者其他500,404錯誤,否則這樣的系統我們會認為是不可用的。
分割槽容錯性
分散式系統在遇到任何網路分割槽故障的時候,仍然需要能夠對外提供滿足一致性和可用性的服務,除非是整個網路環境都發生了故障。
不能出現腦裂的情況
具體描述
來看下CAP理論具體描述:
一個分散式系統不可能同時滿足一致性、可用性和分割槽容錯性這三個基本需求,最多隻能同時滿足其中的兩項
TIPS:不可能把所有應用全部放到一個節點上,因此架構師的精力往往就花在怎麼樣根據業務場景在A和C直接尋求平衡;
BASE理論
根據前面的CAP理論,架構師應該從一致性和可用性之間找平衡,系統短時間完全不可用肯定是不允許的,那麼根據CAP理論,在分散式環境下必然也無法做到強一致性。
BASE理論:即使無法做到強一致性,但分散式系統可以根據自己的業務特點,採用適當的方式來使系統達到最終的一致性;
Basically Avaliable 基本可用
當分散式系統出現不可預見的故障時,允許損失部分可用性,保障系統的“基本可用”;體現在“時間上的損失”和“功能上的損失”;
e.g:部分使用者雙十一高峰期淘寶頁面卡頓或降級處理;
Soft state 軟狀態
其實就是前面講到的三態,既允許系統中的資料存在中間狀態,既系統的不同節點的資料副本之間的資料同步過程存在延時,並認為這種延時不會影響系統可用性;
e.g:12306網站賣火車票,請求會進入排隊佇列;
Eventually consistent 最終一致性
所有的資料在經過一段時間的資料同步後,最終能夠達到一個一致的狀態;
e.g:理財產品首頁充值總金額短時不一致;
其實可能發現不管是CAP理論,還是BASE理論,他們都是理論,這些理論是需要演算法來實現的,今天講的2PC、3PC、Paxos演算法,ZAB演算法就是幹這事情。
所以解決的問題全部都是在分散式環境下,怎麼讓系統儘可能的高可用,而且資料能最終能達到一致。
1.1.1. 兩階段提交 two-phase commit (2PC)
首先來看下2PC,翻譯過來叫兩階段提交演算法,它本身是一致強一致性演算法,所以很適合用作資料庫的分散式事務。其實資料庫的經常用到的TCC本身就是一種2PC.
MySQL innodb儲存引擎,對資料庫的修改都會寫到undo和redo中,不只是資料庫,很多需要事務支援的都會用到這個思路。
對一條資料的修改操作首先寫undo日誌,記錄的資料原來的樣子,接下來執行事務修改操作,把資料寫到redo日誌裡面,萬一捅婁子,事務失敗了,可從undo裡面回覆資料。
不只是資料庫,在很多企業裡面,比如華為等提交資料庫修改都回要求這樣,你要新增一個欄位,首先要把修改資料庫的欄位SQL提交給DBA(redo),這不夠,還需要把刪除你提交欄位,把資料還原成你修改之前的語句也一併提交者叫(undo)
資料庫通過undo與redo能保證資料的強一致性,要解決分散式事務的前提就是當個節點是支援事務的。
這在個前提下,2pc借鑑這失效,首先把整個分散式事務分兩節點,首先第一階段叫準備節點,事務的請求都發送給一個個的資源,這裡的資源可以是資料庫,也可以是其他支援事務的框架,他們會分別執行自己的事務,寫日誌到undo與redo,但是不提交事務。
當事務管理器收到了所以資源的反饋,事務都執行沒報錯後,事務管理器再發送commit指令讓資源把事務提交,一旦發現任何一個資源在準備階段沒有執行成功,事務管理器會發送rollback,讓所有的資源都回滾。這就是2pc,
優點:原理簡單,實現方便
缺點:同步阻塞,單點問題,資料不一致,容錯性不好
同步阻塞
在二階段提交的過程中,所有的節點都在等待其他節點的響應,無法進行其他操作。這種同步阻塞極大的限制了分散式系統的效能。
單點問題
協調者在整個二階段提交過程中很重要,如果協調者在提交階段出現問題,那麼整個流程將無法運轉。更重要的是,其他參與者將會處於一直鎖定事務資源的狀態中,而無法繼續完成事務操作。
資料不一致
假設當協調者向所有的參與者傳送commit請求之後,發生了局部網路異常,或者是協調者在尚未傳送完所有 commit請求之前自身發生了崩潰,導致最終只有部分參與者收到了commit請求。這將導致嚴重的資料不一致問題。
.容錯性不好
二階段提交協議沒有設計較為完善的容錯機制,任意一個節點是失敗都會導致整個事務的失敗。
三階段提交 three-phase commit (3PC)
由於二階段提交存在著諸如同步阻塞、單點問題,所以,研究者們在二階段提交的基礎上做了改進,提出了三階段提交。
第一階段canCommit
確認所有的資源是否都是健康、線上的,以約女孩舉例,你會打個電話問下她是不是在家,而且可以約個會。
如果女孩有空,你在去約她。
就因為有了這一階段,大大的減少了2段提交的阻塞時間,在2段提交,如果有3個數據庫,恰恰第三個資料庫出現問題,其他兩個都會執行耗費時間的事務操作,到第三個卻發現連線不上。3段優化了這種情況
第二階段PreCommit
如果所有服務都ok,可以接收事務請求,這一階段就可以執行事務了,這時候也是每個資源都回寫redo與undo日誌,事務執行成功,返回ack(yes),否則返回no
第三階段doCommit
這階段和前面說的2階段提交大同小異,這個時候協調者發現所有提交者事務提交者事務都正常執行後,給所有資源傳送commit指令。
和二階段提交有所不同的是,他要求所有事務在協調者出現問題,沒給資源傳送commit指令的時候,三階段提交演算法要求資源在一段時間超時後回預設提交做commit操作。
這樣的要求就減少了前面說的單點故障,萬一事務管理器出現問題,事務也回提交。
但回顧整個過程,不管是2pc,還是3pc,同步阻塞,單點故障,容錯機制不完善這些問題都沒本質上得到解決,尤其是前面說得資料一致性問題,反而更糟糕了。
所有資料庫的分散式事務一般都是二階段提交,而者三階段的思想更多的被借鑑擴散成其他的演算法。
Paxos演算法
身這演算法的提出者萊斯利·蘭伯特在前面幾篇論文中都不是以嚴謹的數學公式進行的。
paxos演算法也分成兩階段。首先這個圖有2個角色,提議者與接收者
第一階段
提議者對接收者吼了一嗓子,我有個事情要告訴你們,當然這裡接受者不只一個,它也是個分散式叢集
相當於星期一開早會,可恥的領導吼了句:“要開會了啊,我要公佈一個編號為001的提案,收到請回復”。
這個時候領導就會等著,等員工回覆1“好的”,如果回覆的數目超過一半,就會進行下一步。
如果由於某些原因(接收者宕機,網路問題,本身業務問題),導通過的協議未超過一半,
這個時候的領導又會再吼一嗓子,當然氣勢沒那凶殘:“好了,怕了你們了,我要公佈一個新的編號未002的提案,收到請回復1”
第二階段
接下來到第二階段,領導苦口婆心的把你們叫來開會了,今天編號002提案的內容是:“由於專案緊張,今天加班到12點,同意的請舉手”這個時候如果絕大多少的接收者都同意,那麼好,議案就這麼決定了,如果員工反對或者直接奪門而去,那麼領導又只能從第一個階段開始:“大哥,大姐們,我有個新的提案003,快回會議室吧。。”
上面那個故事描繪的是個苦逼的領導和凶神惡煞的員工之間的鬥爭,通過這個故事你們起碼要懂paxos協議的流程是什麼樣的(paxos的核心就是少數服從多數)。
上面的故事有兩個問題:
苦逼的領導(單點問題):有這一幫凶殘的下屬,這領導要不可能被氣死,要不也會辭職,這是單點問題。
凶神惡煞的下屬(一致性問題):如果員工一種都拒絕,故意和領導擡杆,最終要產生一個一致性的解決方案是不可能的。
所以paxos協議肯定不會只有一個提議者,作為下屬的員工也不會那麼強勢
協議要求:如果接收者沒有收到過提案編號,他必須接受第一個提案編號
如果接收者沒有收到過其他協議,他必須接受第一個協議。
舉一個例子:
有2個Proposer(老闆,老闆之間是競爭關係)和3個Acceptor(政府官員):
. 階段一
1.現在需要對一項議題來進行paxos過程,議題是“A專案我要中標!”,這裡的“我”指每個帶著他的祕書Proposer的Client老闆。
2.Proposer當然聽老闆的話了,趕緊帶著議題和現金去找Acceptor政府官員。
3.作為政府官員,當然想誰給的錢多就把專案給誰。
4.Proposer-1小姐帶著現金同時找到了Acceptor-1~Acceptor-3官員,1與2號官員分別收取了10比特幣,找到第3號官員時,沒想到遭到了3號官員的鄙視,3號官員告訴她,Proposer-2給了11比特幣。不過沒關係,Proposer-1已經得到了1,2兩個官員的認可,形成了多數派(如果沒有形成多數派,Proposer-1會去銀行提款在來找官員們給每人20比特幣,這個過程一直重複每次+10比特幣,直到多數派的形成),滿意的找老闆覆命去了,但是此時Proposer-2保鏢找到了1,2號官員,分別給了他們11比特幣,1,2號官員的態度立刻轉變,都說Proposer-2的老闆懂事,這下子Proposer-2放心了,搞定了3個官員,找老闆覆命去了,當然這個過程是第一階段提交,只是官員們初步接受賄賂而已。故事中的比特幣是編號,議題是value。
這個過程保證了在某一時刻,某一個proposer的議題會形成一個多數派進行初步支援(初步達成共識)
1.1.1.3.2. 階段二
5. 現在進入第二階段提交,現在proposer-1小姐使用分身術(多執行緒併發)分了3個自己分別去找3位官員,最先找到了1號官員籤合同,遭到了1號官員的鄙視,1號官員告訴他proposer-2先生給了他11比特幣,因為上一條規則的性質proposer-1小姐知道proposer-2第一階段在她之後又形成了多數派(至少有2位官員的贓款被更新了);此時她趕緊去提款準備重新賄賂這3個官員(重新進入第一階段),每人20比特幣。剛給1號官員20比特幣, 1號官員很高興初步接受了議題,還沒來得及見到2,3號官員的時候
這時proposer-2先生也使用分身術分別找3位官員(注意這裡是proposer-2的第二階段),被第1號官員拒絕了告訴他收到了20比特幣,第2,3號官員順利簽了合同,這時2,3號官員記錄client-2老闆用了11比特幣中標,因為形成了多數派,所以最終接受了Client2老闆中標這個議題,對於proposer-2先生已經出色的完成了工作;
這時proposer-1小姐找到了2號官員,官員告訴她合同已經簽了,將合同給她看,proposer-1小姐是一個沒有什麼職業操守的聰明人,覺得跟Client1老闆混沒什麼前途,所以將自己的議題修改為“Client2老闆中標”,並且給了2號官員20比特幣,這樣形成了一個多數派。順利的再次進入第二階段。由於此時沒有人競爭了,順利的找3位官員籤合同,3位官員看到議題與上次一次的合同是一致的,所以最終接受了,形成了多數派,proposer-1小姐跳槽到Client2老闆的公司去了。
總結:Paxos過程結束了,這樣,一致性得到了保證,演算法執行到最後所有的proposer都投“client2中標”所有的acceptor都接受這個議題,也就是說在最初的第二階段,議題是先入為主的,誰先佔了先機,後面的proposer在第一階段就會學習到這個議題而修改自己本身的議題,因為這樣沒職業操守,才能讓一致性得到保證,這就是paxos演算法的一個過程。原來paxos演算法裡的角色都是這樣的不靠譜,不過沒關係,結果靠譜就可以了。該演算法就是為了追求結果的一致性。
叢集一致性協議ZAB解析
懂了paxos演算法,其實zab就很好理解了。很多論文和資料都證明zab其實就是paxos的一種簡化實現,但Apache 自己的立場說zab不是paxos演算法的實現,這個不需要去計較。