《分佈式技術原理與算法解析》總結二:分佈式協調與同步

1 分佈式互斥

對於同一共享資源,要求同一時刻只能有一個程序能夠訪問,防止出錯

1.1 集中式算法

引入一個協調者程序,得到一個分佈式互斥算法:
每個程序在需要訪問臨界資源時,先給協調者發送一個請求;
如果當前沒有程序使用這個資源,協調者直接授權請求程序訪問,否則,按照FIFO規則進行排隊等待;
如果有程序使用完資源,則通知協調者,協調者從隊列裏取出排在最前面的請求,並給它發送授權消息,拿
到授權消息的程序,可以直接去訪問臨界資源

一個程序完成一次臨界資源訪問,需要如下幾個流程和消息交互(三次):

向協調者發送請求授權信息,1 次消息交互;

協調者向程序發放授權信息,1 次消息交互;

程序使用完臨界資源後,向協調者發送釋放授權,1 次消息交互。

優點:直觀、簡單、信息交互量少、易於實現、程序只需和協調者通信,程序之間無需通信

缺點:協調者可能會成爲系統的性能瓶頸、單點故障(使用主備)

場景:比較廣泛

1.2 分佈式算法(組播和邏輯時鐘的算法)

當一個程序要訪問臨界資源時,先向系統中的其他程序發送一條請求消息,在接收到所有程序返回的同意消息後,纔可以訪問臨界資源;
其中,請求消息需要包含所請求的資源、請求者的 ID,以及發起請求的時間

如果當前程序正在使用資源,其他程序申請了這個資源,那麼當前程序會將這個申請資源的程序放在隊列裏,等到釋放此資源,就向隊列裏的第一個需要此資源的程序發送”同意使用資源“的消息,並從隊列移除此程序(機制:先到先得、投票需全票通過)

隊列需要記錄請求資源的時間、對應的程序、申請的資源

一個程序完成一次臨界資源的訪問,需要進行如下幾個流程和信息交互(2*(n-1)):

向其他 n-1 個程序發送訪問臨界資源的請求,總共需要 n-1 次消息交互;

需要接收到其他 n-1 個程序回覆的同意消息,方可訪問資源,總共需要 n-1 次消息交
互。

優點:每個程序按時間順序公平地訪問資源、簡單粗暴、易於實現

缺點:可用性比集中式算法低,原因如下
1 當系統內需要訪問臨界資源的程序增多時,容易產生“信令風暴”,也就是程序收到的請求完全超過了自己的處理能力,而導致自己正常的業務無法開展;
2 一旦某一程序發生故障,無法發送同意消息,那麼其他程序均處在等待回覆的狀態中,使得整個系統處於停滯狀態,導致整個系統不可用;
改進:如果檢測到一個程序故障,則直接忽略這個程序,無需再等待它的同意消息

場景:適合節點數目少且變動不頻繁的系統,且由於每個程序均需通信交互,因此適合P2P結構的系統。(Hadoop)

1.3 令牌環算法(一致性哈希)

所有程序構成一個環結構,令牌按照順時針(逆時針)方向在程序之間傳遞,收到令牌的程序有權訪問臨界資源,訪問完成後將令牌傳送到下一個程序;
若該程序不需要訪問臨界資源,則直接把令牌傳送給下一個程序。

優點:
不需要像分佈式算法那樣挨個徵求其他程序的意見了,所以相對而言,在令牌環算法裏單個程序具有更高的通信效率;
同時,在一個週期內,每個程序都能訪問到臨界資源,因此令牌環算法的公平性也很好,甚至更好;

缺點:
不管環中的程序是否想要訪問資源,都需要接收並傳遞令牌,所以也會帶來一些無效通信(可以進行加權處理);
單點故障問題,可以這麼改進:若某一個程序出現故障,則直接將令牌傳遞給故障程序的下一個程序,這樣穩定性也挺好的

場景:非常適合通信模式爲令牌環方式的分佈式系統(移動自組織網絡系
統:無人機通信),即系統規模較小,並且系統中每個程序使用臨界資源的頻率高且使用時間比較短

1.4 兩層結構的分佈式令牌環算法

如上三個算法都不適用於規模過大、節點數量過多的系統,可以使用兩層結構的分佈式令牌環算法,把整個廣域網系統中的節點組織成兩層結構,可以用於節點數量較多的系統,或者是廣域網系統。

在該算法中,局域網是較低的層次,廣域網是較高的層次;
每個局域網中包含若干個局部進程和一個協調進程;
局部進程在邏輯上組成一個環形結構,在每個環形結構上有一個局部令牌 T 在局部進程間傳遞;
局域網與局域網之間通過各自的協調進程進行通信,這些協調進程同樣組成一個環結構,這個環就是廣域網中的
全局環;
在這個全局環上,有一個全局令牌在多個協調進程間傳遞。

1.5 總結對比

在這裏插入圖片描述

2 分佈式選舉

集羣裏選出一個主節點,由它來協調和管理其他節點,以保證集羣有序運行和節點間數據的一致性。

2.1 Bully算法

選舉原則是“長者爲大“,即在所有活着的節點中,選取ID最大的節點作爲主節點。

算法說明:

節點的角色有兩種:普通節點和主節點;
初始化時,所有節點都是平等的,都是普通節點,並且都有成爲主的權利;
選主成功後,有且僅有一個節點成爲主節點,其他所有節點都是普通節點;
當且僅當主節點故障或與其他節點失去聯繫後,纔會重新選主

在選舉過程中,需要用到以下3種消息:

Election:用於發起選舉

Alive:對 Election 消息的應答

Victory:競選成功的主節點向其他節點發送的宣誓主權的消息

選舉前提:集羣中每個節點均知道其他節點的 ID

選舉流程:

每個節點判斷自己的 ID 是否爲當前活着的節點中 ID 最大的:
如果是,則直接向其他節點發送 Victory 消息,宣誓主權;
如果不是,則向比自己 ID 大的所有節點發送Election 消息,並等待其他節點的回覆;

若在給定的時間範圍內:
本節點沒有接收到來自比自己ID 大的節點的 Alive 消息,則認爲自己成爲主節點(可能ID更大的節點出問題了,或者網絡不好),並向其他節點發送 Victory 消息,宣誓自己成爲主節點;
本節點接收到來自比自己ID 大的節點的 Alive 消息,說明有比我ID大的且沒故障、網絡沒問題的,則等待其他節點發送 Victory 消息;

若本節點收到比自己 ID 小的節點發送的 Election 消息,則回覆一個 Alive 消息,告知其他節點,我比你大,重新選舉。

優點:選舉速度快、算法複雜度低、簡單易實現

缺點:
需要每個節點有全局的節點信息,因此額外信息存儲較多;
任意一個比當前主節點 ID 大的新節點或節點故障後恢復加入集羣的時候,都可能會觸發重新選舉,成爲新的主節點,如果該節點頻繁退出、加入集羣,就會導致頻繁切主。

2.2 Raft算法

核心思想是“少數服從多數”,獲得投票最多的節點成爲主。

算法說明:

集羣節點的角色有 3 種:
Leader:主節點,同一時刻只有一個 Leader,負責協調和管理其他節點;
Candidate:候選者,每一個節點都可以成爲 Candidate,節點在該角色下才可以被選爲新的 Leader;
Follower:Leader 的跟隨者,不可以發起選舉

選舉流程:

初始化時,所有節點均爲 Follower 狀態。

開始選主時,所有節點的狀態由 Follower 轉化爲 Candidate,並向其他節點發送選舉請求。

其他節點根據接收到的選舉請求的先後順序,回覆是否同意成爲主;
在每一輪選舉中,一個節點只能投出一張票

若發起選舉請求的節點獲得超過一半的投票,則成爲主節點,其狀態轉化爲 Leader,其他節點的狀態則由 Candidate 降爲 Follower;
Leader節點與Follower節點之間會定期發送心跳包,以檢測主節點是否活着,如果主節點故障,會立馬發起選舉,重新選出一個主節點

當Leader節點的任期到了,即發現其他服務器開始下一輪選主週期時,Leader 節點的狀態由 Leader 降級爲 Follower,進入新一輪選主

優點:選舉速度快、算法複雜度低、易於實現

缺點:要求
系統內每個節點都可以相互通信,且需要獲得過半的投票數才能選主成功,因此通信量大;穩定性高於Bully算法,是因爲當有新節點加入或節點故障恢復後,會觸發選主,但不一定會真正切主,除非新節點或故障後恢復的節點獲得投票數過半,纔會導致切主。

場景:etcds、Redis

2.3 ZAB算法

相比於 Raft 算法的投票機制,ZAB 算法增加了通過節點 ID 和數據 ID 作爲參考進行選主,節點 ID 和數據 ID 越大,表示數據越新,優先成爲主
也就是說相比於Raft算法,ZAB 算法儘可能保證數據的最新性。所以,ZAB 算法可以說是對 Raft 算法的改進,具有了優先級

算法說明:

集羣節點的角色有 3 種:
Leader:主節點;
Follower:跟隨者節點;
Observer:觀察者,無投票權

選舉過程中,集羣中的節點擁有 4 個狀態:
Looking:選舉狀態。當節點處於該狀態時,它會認爲當前集羣中沒有 Leader,因此自己進入選舉狀態;
Leading 狀態:領導者狀態。表示已經選出主,且當前節點爲 Leader;
Following 狀態:跟隨者狀態。集羣中已經選出主後,其他非主節點狀態更新爲Following,表示對 Leader 的追隨;
Observing 狀態:觀察者狀態。表示當前節點爲 Observer,沒有投票權和選舉權

選舉流程:推薦閱讀https://mp.weixin.qq.com/s/6Lai6Gw9h2YAinS4QqNOLA

優點:
性能高、對系統無特殊要求;
穩定性比較好,當有新節點加入或節點故障恢復後,會觸發選主,但不一定會真正切主,除非新節點或故障後恢復的節點數據 ID 和節點ID 最大,且獲得投票數過半,纔會導致切主。

缺點:
採用廣播方式發送信息,若節點中有 n個節點,每個節點同時廣播,則集羣中信息量爲 n*(n-1) 個消息,容易出現廣播風暴;
除了投票,還增加了對比節點 ID 和數據 ID,這就意味着還需要知道所有節點的 ID 和數據ID,所以選舉時間相對較長

場景:ZooKeeper

2.4 選舉算法的技巧

“多數派”選主算法(Raft、ZAB)通常採用奇數節點,而不是偶數節點,因爲在偶數節點的情況下,無法選出主,必須重新投票選舉。但即使重新投票選舉,兩個節點擁有相同投票數的概率也會很大

3 分佈式共識

在多個節點均可獨自操作或記錄的情況下,使得所有節點針對某個狀態達成一致的過程;
通過共識機制,可以使得分佈式系統中的多個節點的數據達成一致;
分佈式選舉過程就是一個分佈式共識問題

分佈式選舉大多是基於多數投票策略實現的,如果用於分佈式在線記賬一致性問題中,那麼記賬權通常會完全掌握到主節點的手裏,這使得主節點非常容易造假,且存在性能瓶頸;(區塊鏈)
分佈式在線記賬:指在沒有集中的發行方,也就是沒有銀行參與的情況下,任意一臺接入互聯網的電腦都能參與買賣,所有看到該交易的服務器都可以記錄這筆交易,並且記錄信息最終都是一致的,以保證交易的準確性;
如何保證交易的一致性,就是該場景下的分佈式共識問題

在分佈式在線記賬問題中,針對同一筆交易,有且僅有一個節點或服務器可以獲得記賬權,然後其他
節點或服務器同意該節點或服務器的記賬結果,達成一致;
即分佈式共識包括兩個關鍵點:獲得記賬權所有節點或服務器達成一致

3.1 PoW(Proof-of-Work,工作量證明;區塊鏈1.0階段)

以每個節點或服務器的計算能力(算力)來競爭記賬權的機制,是一種使用工作量證明機制的共識算法;
也就是說,誰的計算力、工作能力強,誰獲得記賬權的可能性就越大

算法說明:

算力的體現:每個節點都去解一道題,誰能先解決誰的能力就強。

假設每個節點會劃分多個區塊用於記錄用戶交易的信息,那麼此算法獲取記賬權的原理是:
利用區塊的 index、前一個區塊的哈希值、交易的時間戳、區塊數據和 nonce 值,通過SHA256哈希算法計算出一個哈希值,並判斷前 k 個值是否都爲0:(nonce 值是用來找到一個滿足哈希值的數字;k 爲哈希值前導零的個數,標記了計算的難度,0 越多計算難度越大。)
如果不是,則遞增 nonce 值,重新按照上述方法計算;
如果是,則本次計算的哈希值爲要解決的題目的正確答案;
誰最先計算出正確答案,誰就獲得這個區塊的記賬權

達成共識的過程,就是獲得記賬權的節點將該區塊信息廣播給其他節點,其他節點判斷該節點找到的區塊中的所有交易都是有效且之前未存在過的,則認爲該區塊有效,並接受該區塊,達成一致。

優點:允許全網 50% 的節點出錯,因此,如果要破壞系統,則需要投入極大成本(有全球 51% 的算力,則可嘗試攻擊比特幣)

缺點:
每次達成共識需要全網共同參與運算,增加了每個節點的計算量;
如果題目過難,會導致計算時間長、資源消耗多;如果題目過於簡單,會導致大量節點同時獲得記賬權,衝突多;
這些問題,都會增加達成共識的時間(也就是說共識達成的週期長、效率低,資源消耗大)

3.2 PoS(Proof-of-Stake,權益證明;2.0)

爲了解決 PoW 算法的缺點,引入了 PoS 算法;
核心原理:由系統權益代替算力來決定區塊記賬權,擁有的權益越大獲得記賬權的概率就越大。

算法說明:

權益:每個節點佔有貨幣的數量和時間,而貨幣就是節點所獲得的獎勵;
PoW 算法充分利用了分佈式在線記賬中的獎勵,支持“利滾利”。

公式:利息 = (幣數 * 持有的天數 * 利率 / 365)
例子:
比如持有 100 個幣,總共持有了 50 天,那麼,幣齡就爲 5000;
這時如果發現了一個 PoS 區塊,幣齡就會被減少 365;
每被減少 365 幣齡,就可以從區塊中獲得 0.05 個幣的利息 (可理解爲年利率 5%);
此時,利息 = 100 * 50 *5% /365 = 0.68 個幣。

不同節點通過公式計算自己的利息,誰最大,誰將自己的區塊廣播給其他節點,當然必須保證該區塊的有效性

優點:與PoW相比
PoS不需要消耗大量的就能夠保證區塊鏈網絡的安全性;
不需要在每個區塊中創建新的貨幣來激勵記賬者參與當前網絡的運行,在一定程度上縮短了達成共識所需要的時間。

缺點:與PoW相比
持幣越多或持幣越久,幣齡就會越高,持幣人就越容易挖到區塊並得到激勵,而持幣少的人基本沒有機會,這樣整個系統的安全性實際上會被持幣數量較大的一部分人掌握,容易出現壟斷現象。

3.3 DPoS(Delegated Proof of Stake,委託權益證明;3.0)

爲了解決 PoS 算法的缺點,提出了此算法:類似股份制公司的董事會制度,普通股民雖然擁有股權,但進不了董事會,他們可以投票選舉代表(受託人)代他們做決策;
DPoS 是由被社區選舉的可信帳戶來擁有記賬權

算法說明:

爲了成爲正式受託人,用戶要去社區拉票,獲得足夠多的信任,用戶根據自己持有的貨幣數量佔總量的百分比來投票

選出k(比如 101) 個受託節點,它們的權利是完全相等的;
受託節點之間爭取記賬權是根據算力進行競爭的;
如果受託節點提供的算力不穩定,計算機宕機或者利用手中的權力作惡,隨時可以被握着貨幣的普通節點投票踢出整個系統,而後備的受託節點可以隨時頂上去

優點:與PoS相比
由投票選舉出的若干信譽度更高的受託人來記賬,解決了所有節點均參與競爭導致消息量大、達成一致的週期長的問題,也就是說,DPoS 能耗更低,具有更快的交易速度;
每隔一定週期會調整受託人,避免受託人造假和獨權

缺點:與PoS相比
由於大多數持幣人通過受託人參與投票,投票的積極性並不高;
一旦出現故障節點,DPoS 無法及時做出應對,導致安全隱患

3.4 總結對比

在這裏插入圖片描述

  • 一致性與共識的區別

一致性:分佈式系統中的多個節點之間,給定一系列的操作,在約定協議的保障下,對外界呈現的數據(狀態)是一致的

共識:分佈式系統中多個節點之間,彼此對某個狀態達成一致結果的過程

也就是說一致性強調的是結果,共識強調的是達成一致的過程,共識算法是保障系統滿足不同程度一致性的核心技術

4 分佈式事務

不同業務會運行在不同的機器上,比如訂單機器和庫存機器,針對同一筆訂單,當且僅當訂單操作和減庫存操作一致時,才能保證交易的正確性;
也就是說一筆訂單隻有這兩個操作都完成,才能算做處理成功,否則處理失敗,這個問題就是分佈式事務要解決的問題

分佈式事務基本能夠滿足 ACID,但隨着分佈式系統規模不斷擴大,複雜度急劇上升,達成強一致性所需時間週期較長,限定了複雜業務的處理;
爲了適應複雜業務,出現了BASE理論,該理論的一個關鍵點就是採用最終一致性代替強一致性,算是ACID的弱化

4.1 基於 XA 協議的二階段提交協議方法(強一致性)

XA協議可以分爲兩部分:事務管理器和本地資源管理器

算法說明:

原理類似分佈式互斥的集中式算法:
事務管理器作爲協調者,負責各個本地資源的提交和回滾;
資源管理器就是分佈式事務的參與者,通常由數據庫實現(實現XA接口)

二階段提交協議(The two-phase commitprotocol,2PC)用於保證分佈式系統中事務提交時的數據一致性,是 XA 在全局事務中用於協調多個資源的機制。

二階段提交協議算法說明:投票(voting)和提交(commit)

第一階段:投票
協調者(Coordinator,即事務管理器)會向事務的參與者(Cohort,即本地資源管理器)發起執行操作的 CanCommit 請求,並等待參與者的響應;
參與者接收到請求後,會執行請求中的事務操作,記錄日誌信息但不提交;
待參與者執行成功,則向協調者發送“Yes”消息,表示同意操作;若不成功,則發送“No”消息,表示終止操作。

第二階段:提交
當所有的參與者都返回了響應後(Yes 或 No 消息)後,系統進入了提交階段;
在提交階段,協調者會根據所有參與者返回的信息向參與者發送 DoCommit 或 DoAbort 指令:
若協調者收到的都是“Yes”消息,則向參與者發送“DoCommit”消息,參與者會完成剩餘的操作並釋放資源,然後向協調者返回“HaveCommitted”消息;
如果協調者收到的消息中包含“No”消息,則向所有參與者發送“DoAbort”消息,此時發送“Yes”的參與者則會根據之前執行操作時的回滾日誌對操作進行回滾,然後所有參與者會向協調者發送“HaveCommitted”消息;
協調者接收到“HaveCommitted”消息,就意味着整個事務結束了。

流程圖:《從Paxos到ZooKeeper》
在這裏插入圖片描述
優點:簡單

缺點:
1 同步阻塞:二階段提交算法在執行過程中,所有參與節點都是事務阻塞型的;
也就是說,當本地資源管理器佔有臨界資源時,其他資源管理器如果要訪問同一臨界資源,會處於阻塞狀態。
2 單點故障:事務管理器會有此問題
3 數據不一致:在提交階段,當協調者向參與者發送 DoCommit 請求之後,如果發生了局部網絡異常,或者在發送提交請求的過程中協調者發生了故障,就會導致只有一部分參與者接收到了提交請求並執行提交操作,但其他未接到提交請求的那部分參與者則無法執行事務提交,於是整個分佈式系統便出現了數據不一致的問題。

4.2 三階段提交協議方法3PC(強一致性)

爲了解決2PC的單點故障、部分數據不一致問題,引入了超時機制和準備階段,成爲3PC

算法說明:

協調者和參與者都引入超時機制;
如果協調者或參與者在規定的時間內沒有接收到來自其他節點的響應,就會根據當前的狀態選擇提交或者終止整個事務。

在第一階段和第二階段中間引入了一個準備階段,也就是在提交階段之前,加入了一個預提交階段;
在預提交階段排除一些不一致的情況,保證在最後提交之前各參與節點的狀態是一致的;
實現:把 2PC 的提交階段一分爲二,全部有CanCommit、PreCommit、DoCommit 三個階段。

第一階段:CanCommit,與2PC的第一階段類似
協調者向參與者發送請求操作(CanCommit請求),詢問參與者是否可以執行事務提交操作,然後等待參與者的響應;
參與者收到CanCommit 請求之後,回覆 Yes,表示可以順利執行事務,否則回覆 No。

第二階段:PreCommit
協調者根據參與者的回覆情況,來決定是否可以進行 PreCommit 操作:
如果所有參與者回覆的都是“Yes”,那麼協調者就會執行事務的預執行:
1 發送預提交請求:協調者向參與者發送 PreCommit 請求,進入預提交階段。
2 事務預提交:參與者接收到 PreCommit 請求後執行事務操作,並將 Undo 和 Redo信息記錄到事務日誌中。
3 響應反饋:如果參與者成功執行了事務操作,則返回 ACK 響應,同時開始等待最終指令。
如果任何一個參與者向協調者發送了“No”消息,或者等待超時之後,協調者都沒有收到參與者的響應,就執行中斷事務的操作:
1 發送中斷請求:協調者向所有參與者發送“Abort”消息。
2 終斷事務:參與者收到“Abort”消息之後,或超時後仍未收到協調者的消息,執行事務的終斷操作。

第三階段:DoCommit
根據 PreCommit 階段協調者發送的消息,進入執行提交階段或事務中斷階段:
執行提交階段:
1 發送提交請求:協調者接收到所有參與者發送的 Ack 響應,從預提交狀態進入到提交狀態,並向所有參與者發送 DoCommit 消息。
2 事務提交:參與者接收到 DoCommit 消息之後,正式提交事務。完成事務提交之後,釋放所有鎖住的資源。
3 響應反饋:參與者提交完事務之後,向協調者發送 Ack 響應。
4 完成事務:協調者接收到所有參與者的 Ack 響應之後,完成事務。
事務中斷階段:
1 發送中斷請求:協調者向所有參與者發送 Abort 請求。
2 事務回滾:參與者接收到 Abort 消息之後,利用其在 PreCommit 階段記錄的 Undo信息執行事務的回滾操作,並釋放所有鎖住的資源。
3 反饋結果:參與者完成事務回滾之後,向協調者發送 Ack 響應。
4 終斷事務:協調者接收到參與者反饋的 Ack 消息之後,執行事務的終斷,並結束事務。

流程圖:《從Paxos到ZooKeeper》
在這裏插入圖片描述
優點:無單點故障問題、無同步阻塞問題、強一致性、同步執行

缺點:
參與者接收到doCommit消息後,如果網絡出現分區,此時協調者所在的節點和參與者無法進行通信,參與者依然會進行事務的提交,會出現數據的不一致性(在 DoCommit 階段,當參與者向協調者發送 Ack 消息後,如果長時間沒有得到協調者的響應,在默認情況下,參與者會自動將超時的事務進行提交,不會像兩階段提交那樣被阻塞住。)
性能較低
系統吞吐量不高

4.3 基於消息的最終一致性方法(最終一致性)

2PC和3PC有兩個共同的缺點:
1 需要鎖定資源,降低系統性能
2 沒有解決數據不一致的問題

基於分佈式消息的最終一致性方案:將需要分佈式處理的事務通過消息或者日誌的方式異步執行,消息或日誌可以存到本地文件、數據庫或消息隊列中,再通過業務規則進行失敗重試。

實現:引入MQ,用於在多個應用之間進行消息傳遞:
在這裏插入圖片描述

4.4 總結對比

在這裏插入圖片描述

  • 剛性事務與柔性事務

剛性事務:遵循 ACID 原則,具有強一致性,比如數據庫事務。(ACID)

柔性事務:根據不同的業務場景使用不同的方法實現最終一致性,也就是說我們可以根據業務的特性做部分取捨,容忍一定時間內的數據不一致。(BASE)

5 分佈式鎖

分佈式互斥算法主要解決了“協調多個進程獲取權限和根據權限有序訪問共享資源”的問題,分佈式鎖則解決”這個權限是如何設置或產生的,以及設置或產生這個權限的工作原理是什麼“的問題

具體實現的方式網上有很多文章,這裏就不多說啦,放張圖:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章