日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

分布式之系統(tǒng)底層原理(上)

 菌心說 2021-07-17

作者:allanpan,騰訊 IEG 高級后臺工程師

導(dǎo)言

分布式事務(wù)是分布式系統(tǒng)必不可少的組成部分,基本上只要實現(xiàn)一個分布式系統(tǒng)就逃不開對分布式事務(wù)的支持。本文從分布式事務(wù)這個概念切入,嘗試對分布式事務(wù)以及分布式系統(tǒng)最核心的底層原理逐一進(jìn)行剖析,內(nèi)容包括但不限于 BASE 原則、兩階段原子提交協(xié)議三階段原子提交協(xié)議、Paxos/Multi-Paxos 分布式共識算法的原理與證明Raft 分布式共識算法分布式事務(wù)的并發(fā)控制等內(nèi)容。

事務(wù)

事務(wù)是訪問并可能更新各種數(shù)據(jù)項的一個程序執(zhí)行單元(unit)。事務(wù)由一個或多個步驟組成,一般使用形如 begin transaction 和 end transaction 語句或者函數(shù)調(diào)用作為事務(wù)界限,事務(wù)內(nèi)的所有步驟必須作為一個單一的、不可分割的單元去執(zhí)行,因此事務(wù)的結(jié)果只有兩種:1. 全部步驟都執(zhí)行完成,2. 任一步驟執(zhí)行失敗則整個事務(wù)回滾。

事務(wù)最早由數(shù)據(jù)庫管理系統(tǒng)(database management systemDBMS)引入并實現(xiàn),數(shù)據(jù)庫事務(wù)是數(shù)據(jù)庫管理系統(tǒng)執(zhí)行過程中的一個邏輯單位,由一個有限的數(shù)據(jù)庫操作序列構(gòu)成。數(shù)據(jù)庫事務(wù)嚴(yán)格遵循 ACID 原則,屬于剛性事務(wù),一開始數(shù)據(jù)庫事務(wù)僅限于對單一數(shù)據(jù)庫資源對象的訪問控制,這一類事務(wù)稱之為本地事務(wù) (Local Transaction),后來隨著分布式系統(tǒng)的出現(xiàn),數(shù)據(jù)的存儲也不可避免地走向了分布式,分布式事務(wù)(Distributed Transaction)便應(yīng)運(yùn)而生。

剛性事務(wù)

分布式之系統(tǒng)底層原理(上)

剛性事務(wù)(如單一數(shù)據(jù)庫事務(wù))完全遵循 ACID 規(guī)范,即數(shù)據(jù)庫事務(wù)的四大基本特性:

  • Atomicity(原子性):一個事務(wù)(transaction)中的所有操作,或者全部完成,或者全部不完成,不會結(jié)束在中間某個環(huán)節(jié)。事務(wù)在執(zhí)行過程中發(fā)生錯誤,會被回滾(Rollback)到事務(wù)開始前的狀態(tài),就像這個事務(wù)從來沒有執(zhí)行過一樣。即,事務(wù)不可分割、不可約簡。

  • Consistency(一致性):在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預(yù)設(shè)約束、觸發(fā)器、級聯(lián)回滾等。

  • Isolation(隔離性):數(shù)據(jù)庫允許多個并發(fā)事務(wù)同時對其數(shù)據(jù)進(jìn)行讀寫和修改的能力,隔離性可以防止多個事務(wù)并發(fā)執(zhí)行時由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致。事務(wù)隔離分為不同級別,包括未提交讀(Read uncommitted)、提交讀(read committed)、可重復(fù)讀(repeatable read)和串行化(Serializable)。

  • Durability(持久性):事務(wù)處理結(jié)束后,對數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會丟失。

  • 剛性事務(wù)也能夠以分布式 CAP 理論中的 CP 事務(wù)來作為定義。

    柔性事務(wù)

    分布式之系統(tǒng)底層原理(上)

    在電商領(lǐng)域等互聯(lián)網(wǎng)場景下,傳統(tǒng)的事務(wù)在數(shù)據(jù)庫性能和處理能力上都遇到了瓶頸。因此,柔性事務(wù)被提了出來,柔性事務(wù)基于分布式 CAP 理論以及延伸出來的 BASE 理論,相較于數(shù)據(jù)庫事務(wù)這一類完全遵循 ACID 的剛性事務(wù)來說,柔性事務(wù)保證的是 “基本可用,最終一致”,CAP 原理相信大家都很熟悉了,這里我們講一下 BASE 原則:

  • 基本可用(Basically Available):系統(tǒng)能夠基本運(yùn)行、一直提供服務(wù)。

  • 軟狀態(tài)(Soft-state):系統(tǒng)不要求一直保持強(qiáng)一致狀態(tài)。

  • 最終一致性(Eventual consistency):系統(tǒng)需要在某一時刻后達(dá)到一致性要求。

  • 柔性事務(wù)(如分布式事務(wù))為了滿足可用性、性能與降級服務(wù)的需要,降低一致性(Consistency)與隔離性(Isolation)的要求,遵循 BASE 理論,傳統(tǒng)的 ACID 事務(wù)對隔離性的要求非常高,在事務(wù)執(zhí)行過程中,必須將所有的資源對象鎖定,因此對并發(fā)事務(wù)的執(zhí)行極度不友好,柔性事務(wù)(比如分布式事務(wù))的理念則是將鎖資源對象操作從本地資源對象層面上移至業(yè)務(wù)邏輯層面,再通過放寬對強(qiáng)一致性要求,以換取系統(tǒng)吞吐量的提升。

    此外,雖然柔性事務(wù)遵循的是 BASE 理論,但是還需要遵循部分 ACID 規(guī)范:

  • 原子性:嚴(yán)格遵循。

  • 一致性:事務(wù)完成后的一致性嚴(yán)格遵循;事務(wù)中的一致性可適當(dāng)放寬。

  • 隔離性:并行事務(wù)間不可影響;事務(wù)中間結(jié)果可見性允許安全放寬。

  • 持久性:嚴(yán)格遵循。

  • 本地事務(wù)

    本地事務(wù)(Local Transaction)指的是僅僅對單一節(jié)點(diǎn)/數(shù)據(jù)庫資源對象進(jìn)行訪問/更新的事務(wù),在這種事務(wù)模式下,BASE 理論派不上用場,事務(wù)完全遵循 ACID 規(guī)范,確保事務(wù)為剛性事務(wù)。

    分布式事務(wù)

    在分布式架構(gòu)成為主流的當(dāng)下,系統(tǒng)對資源對象的訪問不能還局限于單節(jié)點(diǎn),多服務(wù)器、多節(jié)點(diǎn)的資源對象訪問成為剛需,因此,本地事務(wù)無法滿足分布式架構(gòu)的系統(tǒng)的要求,分布式事務(wù)應(yīng)運(yùn)而生。

    訪問/更新由多個服務(wù)器管理的資源對象的平面事務(wù)或者嵌套事務(wù)稱之為分布式事務(wù)(Distributed Transaction),分布式事務(wù)是相對于本地事務(wù)來說的。

    平面事務(wù):單一事務(wù),訪問多個服務(wù)器節(jié)點(diǎn)的資源對象,一個平面事務(wù)完成一次請求之后才能發(fā)起下一個請求。

    嵌套事務(wù):多事務(wù)組成,頂層事務(wù)可以不斷創(chuàng)建子事務(wù),子事務(wù)又可以進(jìn)一步地以任意深度嵌套子事務(wù)。

    分布式之系統(tǒng)底層原理(上)

    對于分布式事務(wù)來說,有兩個最核心的問題:

    1. 如何管理分布式事務(wù)的提交/放棄決定?如果事務(wù)中的一個節(jié)點(diǎn)在執(zhí)行自己的本地事務(wù)過程中遇到錯誤,希望放棄整個分布式事務(wù),與此同時其他節(jié)點(diǎn)則在事務(wù)執(zhí)行過程中一切順利,希望提交這個分布式事務(wù),此時我們應(yīng)該如何做決策?

    2. 如何保證并發(fā)事務(wù)在涉及多個節(jié)點(diǎn)上資源對象訪問的可串行性(規(guī)避分布式死鎖)?如果事務(wù) T 對某一個服務(wù)器節(jié)點(diǎn)上的資源對象 S 的并發(fā)訪問在事務(wù) U 之前,那么我們需要保證在所有服務(wù)器節(jié)點(diǎn)上對 S 和其他資源對象的沖突訪問,T 始終在 U 之前。

    問題 1 的解決需要引入一類分布式原子提交協(xié)議的算法如兩階段提交協(xié)議等,來對分布式事務(wù)過程中的提交或放棄決策進(jìn)行管理,并確保分布式提交的原子性。而問題 2 則由分布式事務(wù)的并發(fā)控制機(jī)制來處理。

    原子提交協(xié)議

    原子性是分布式事務(wù)的前置性約束,沒有原子性則分布式事務(wù)毫無意義。

    原子性約束要求在分布式事務(wù)結(jié)束之時,它的所有操作要么全部執(zhí)行,要么全部不執(zhí)行。以分布式事務(wù)的原子性來分析,客戶端請求訪問/更新多個服務(wù)器節(jié)點(diǎn)上的資源對象,在客戶端提交或放棄該事務(wù)從而結(jié)束事務(wù)之后,多個服務(wù)器節(jié)點(diǎn)的最終狀態(tài)要么是該事務(wù)里的所有步驟都執(zhí)行成功之后的狀態(tài),要么恢復(fù)到事務(wù)開始前的狀態(tài),不存在中間狀態(tài)。滿足這種約束的分布式事務(wù)協(xié)議則稱之為原子提交協(xié)議。

    當(dāng)一個分布式事務(wù)結(jié)束時,事務(wù)的原子特性要求所有參與該事務(wù)的服務(wù)器節(jié)點(diǎn)必須全部提交或者全部放棄該事務(wù),為了實現(xiàn)這一點(diǎn),必須引入一個協(xié)調(diào)者(Coordinator)的角色,從參與事務(wù)的所有服務(wù)器節(jié)點(diǎn)中挑選一個作為協(xié)調(diào)者,由它來保證在所有服務(wù)器節(jié)點(diǎn)上最終獲得同樣的結(jié)果。協(xié)調(diào)者的工作原理取決于分布式事務(wù)選用的協(xié)議。

    一般來說,分布式事務(wù)中包含的兩個最基礎(chǔ)的角色就是:

  • Coordinator -- 協(xié)調(diào)者

  • Participants -- 參與者

  • 分布式之系統(tǒng)底層原理(上)

    單階段原子提交協(xié)議

    單階段原子提交協(xié)議(one-phase atomic commit protocol, 1APC)是最簡單的一種原子提交協(xié)議,它通過設(shè)置一個協(xié)調(diào)者并讓它不斷地向所有參與者發(fā)送提交(commit)或放棄(abort)事務(wù)的請求,直到所有參與者確認(rèn)已執(zhí)行完相應(yīng)的操作。

    1APC 協(xié)議的優(yōu)點(diǎn)是簡單易用,對一些事務(wù)不復(fù)雜的場景比較合適,但在復(fù)雜事務(wù)場景則顯得捉襟見肘,因為該協(xié)議不允許任何服務(wù)器節(jié)點(diǎn)單方面放棄事務(wù),事務(wù)的放棄必須由協(xié)調(diào)者來發(fā)起,這個設(shè)計會導(dǎo)致很多問題:首先因為只有一次通信,協(xié)調(diào)者并不會收集所有參與者的本地事務(wù)執(zhí)行的情況,所以協(xié)調(diào)者決定提交還是放棄事務(wù)只基于自己的判斷,在參與者執(zhí)行事務(wù)期間可能會遇到錯誤從而導(dǎo)致最終事務(wù)未能真正提交,錯誤一般與事務(wù)的并發(fā)控制有關(guān),比如事務(wù)執(zhí)行期間對資源對象加鎖,遇到死鎖,需要放棄事務(wù)從而解開死鎖,而協(xié)調(diào)者并不知道,因此在發(fā)起下一個請求之前,客戶端完全不知道事務(wù)已被放棄。另一種情況就是利用樂觀并發(fā)控制機(jī)制訪問資源對象,某一個服務(wù)器節(jié)點(diǎn)的驗證失敗將導(dǎo)致事務(wù)被放棄,而協(xié)調(diào)者完全不知情。

    兩階段提交協(xié)議

    定義

    兩階段提交協(xié)議(two-phase commit protocol, 2PC)的設(shè)計初衷是為了解決 1APC 不允許任意一個服務(wù)器節(jié)點(diǎn)自行放棄它自己的那部分本地事務(wù)的痛點(diǎn),2PC 允許任何一個參與者自行決定要不要放棄它的本地事務(wù),而由于原子提交協(xié)議的約束,任意一個本地事務(wù)被放棄將導(dǎo)致整個分布式事務(wù)也必須放棄掉。

    兩階段提交協(xié)議基于以下幾個假設(shè):

  • 存在一個節(jié)點(diǎn)作為協(xié)調(diào)者(Coordinator),分布式事務(wù)通常由協(xié)調(diào)者發(fā)起(當(dāng)然也可以由參與者發(fā)起),其余節(jié)點(diǎn)作為參與者(Participants),且節(jié)點(diǎn)之間可以自由地進(jìn)行網(wǎng)絡(luò)通信,協(xié)調(diào)者負(fù)責(zé)啟動兩階段提交流程以及決定事務(wù)最終是被提交還是放棄。

  • 每個節(jié)點(diǎn)會記錄該節(jié)點(diǎn)上的本地操作日志(op logs),日志必須持久化在可靠的存儲設(shè)備上(比如磁盤),以便在節(jié)點(diǎn)重啟之后需要恢復(fù)操作日志。另外,不記錄全局操作日志。

  • 所有節(jié)點(diǎn)不能發(fā)生永久性損壞,也就是說節(jié)點(diǎn)就算是損壞了也必須能通過可靠性存儲恢復(fù)如初,不允許出現(xiàn)數(shù)據(jù)永久丟失的情況。

  • 參與者對協(xié)調(diào)者的回復(fù)必須要去除掉那些受損和重復(fù)的消息。

  • 整個集群不會出現(xiàn)拜占庭故障(Byzantine Fault)-- 服務(wù)器要么崩潰,要么服從其發(fā)送的消息。

  • 原理

    兩階段提交協(xié)議,顧名思義整個過程需要分為兩個階段:

    1. 準(zhǔn)備階段(Prepare Phase)

    2. 提交階段(Commit Phase)

    在進(jìn)行兩階段提交的過程中,協(xié)調(diào)者會在以下四種狀態(tài)間流轉(zhuǎn):

    1. init

    2. preparing

    3. committed

    4. aborted

    而參與者則會在以下三種狀態(tài)間流轉(zhuǎn):

    1. working

    2. prepared

    3. committed

    階段 I(投票表決階段)

    1. 任意一個參與者發(fā)起分布式事務(wù) T 并執(zhí)行本地事務(wù)成功,接著將一條 <ready T> 記錄追加到本地日志 buffer 中并 flush 到可靠性存儲設(shè)備如磁盤上,從 working 狀態(tài)進(jìn)入 prepared 狀態(tài),然后向協(xié)調(diào)者發(fā)送 prepare T 消息;

    2. 收到參與者發(fā)來的 prepare T 消息后,協(xié)調(diào)者將一條 <prepare T> 記錄追加到日志中,然后從 init 狀態(tài)進(jìn)入 preparing 狀態(tài),緊接著向分布式事務(wù)的其他參與者發(fā)出 canCommit? 消息,發(fā)起事務(wù)表決過程;

    3. 當(dāng)參與者收到 canCommit? 請求后,除了發(fā)起事務(wù)的那一個之外,其他還在working 狀態(tài)的參與者會先嘗試執(zhí)行本地事務(wù),如果本地事務(wù)執(zhí)行成功,則會往本地日志 buffer 寫入一條 <ready T> 記錄并 flush 到可靠性存儲中,但不提交事務(wù),進(jìn)入 prepared 狀態(tài),然后回復(fù)一條 ready T 消息對此事務(wù)投 YES 票;如果本地事務(wù)執(zhí)行失敗,則參與者會往本地日志 buffer 寫入一條 <don't commit T> 記錄并 flush 到可靠性存儲中,然后回復(fù)一條 don't commit T 消息投 NO 票。

    階段 II(收集投票結(jié)果完成事務(wù))

    1. 協(xié)調(diào)者收集所有的投票(包括它自己的投票);(a) 如果所有的投票都是 ready T,則表示沒有故障發(fā)生,那么協(xié)調(diào)者決定提交該事務(wù),首先它會在其本地日志中追加一條 <commit T> 記錄,從 preparing 狀態(tài)進(jìn)入committed 狀態(tài),然后向所有的參與者發(fā)送 doCommit 請求消息,要求參與者提交它們的本地事務(wù);(b) 如果有任一個投票是 No,則協(xié)調(diào)者決定放棄掉該事務(wù),首先它會往本地日志中追加一條記錄,從 preparing 狀態(tài)進(jìn)入 aborted 狀態(tài),然后發(fā)送 doAbort 請求消息給所有的參與者,通知它們回滾各自的本地事務(wù)。

    2. 投了 YES 票的參與者阻塞等待協(xié)調(diào)者給它發(fā)來 doCommit 或 doAbort 消息,如果接收到的是 doCommit 消息則提交本地事務(wù)并在此過程中記錄日志 <commit T>,然后進(jìn)入 committed 狀態(tài),最后回復(fù)一個 haveCommitted 的消息通知協(xié)調(diào)者本地事務(wù)已經(jīng)成功提交;反之,如果收到的是 doAbort 消息則回滾本地事務(wù)并寫入日志<abort T>,然后進(jìn)入 aborted狀態(tài)。

    上面的過程是一種更通用的流程,即由任意的參與者發(fā)起一個分布式事務(wù),而在實踐中一般把分布式事務(wù)的發(fā)起交給協(xié)調(diào)者來做,減少事務(wù)發(fā)起者確認(rèn)該事務(wù)已被提交所需等待的網(wǎng)絡(luò)消息延遲:

    分布式之系統(tǒng)底層原理(上)

    性能

    網(wǎng)絡(luò) I/O 開銷

    假設(shè)兩階段提交過程一切運(yùn)行正常,即協(xié)調(diào)者和參與者都不出現(xiàn)崩潰和重啟,網(wǎng)絡(luò)通信也都正常。那么假設(shè)有一個協(xié)調(diào)者和 N 個參與者,兩階段提交過程中將會發(fā)送如下的消息:

  • 任意一個參與者從 working 狀態(tài)進(jìn)入 prepared 狀態(tài)并發(fā)送 Prepared 消息給協(xié)調(diào)者,1 條消息。

  • 協(xié)調(diào)者收到消息后,向其他參與者發(fā)送 canCommit? 請求消息,N - 1 條消息。

  • 收到 canCommit? 消息的參與者各自回復(fù)協(xié)調(diào)者投票消息,N - 1 條消息。

  • 協(xié)調(diào)者統(tǒng)計投票情況之后,發(fā)送 doCommit 消息給其他參與者,N 條消息。

  • 所以,事務(wù)發(fā)起者在經(jīng)過 4 條網(wǎng)絡(luò)消息延遲之后確認(rèn)該分布式事務(wù)已被提交,而整個過程共計發(fā)送 3N - 1 條網(wǎng)絡(luò)消息(因為 haveCommitted 在 2PC 僅僅是用于最后通知協(xié)調(diào)者而已,屬于可有可無的一次網(wǎng)絡(luò)消息,2PC 在該消息缺省的情況下也能正常運(yùn)行,因此 haveCommitted 一般不計入網(wǎng)絡(luò)延遲成本中)。

    前面我們提到,在實踐中一般是由協(xié)調(diào)者來發(fā)起事務(wù),如果考慮這種情況的話,事務(wù)發(fā)起者 -- 協(xié)調(diào)者在經(jīng)過 3 條網(wǎng)絡(luò)消息延遲之后確認(rèn)該分布式事務(wù)已經(jīng)被提交,而整個過程實際發(fā)送的網(wǎng)絡(luò)消息則變成 3N 條。

    總而言之,兩階段提交協(xié)議的網(wǎng)絡(luò)通信開銷和集群節(jié)點(diǎn)的數(shù)量成 3 倍正比。

    本地存儲設(shè)備 I/O 開銷

    基于前文中敘述的兩階段提交協(xié)議的基本假設(shè)之一:每個節(jié)點(diǎn)會通過日志來記錄在本地執(zhí)行的操作,以便在節(jié)點(diǎn)發(fā)生故障并重啟節(jié)點(diǎn)之后能利用日志恢復(fù)到故障前的狀態(tài),因此兩階段提交過程中除了網(wǎng)絡(luò) I/O 的開銷之外,還有本地存儲設(shè)備 I/O 的開銷:

  • 發(fā)起事務(wù)的參與者執(zhí)行本地事務(wù),1 次寫操作。

  • 其余參與者執(zhí)行各自的本地事務(wù),N - 1 次寫操作。

  • 協(xié)調(diào)者統(tǒng)計投票結(jié)果并決定提交事務(wù),1 次寫操作。

  • 所以事務(wù)發(fā)起者在經(jīng)過 3 次本地存儲設(shè)備 I/O 延遲之后確認(rèn)該事務(wù)已被提交,整個過程總計有 N + 1 次本地存儲設(shè)備 I/O,而如果由協(xié)調(diào)者來發(fā)起事務(wù)的話,則還是需要 N + 1 次本地存儲設(shè)備 I/O,但是只需要經(jīng)過 2 次本地存儲設(shè)備 I/O 延遲即可確認(rèn)事務(wù)已被提交。

    恢復(fù)

    在分布式事務(wù)中,所有的參與者節(jié)點(diǎn)都可能發(fā)生故障,所以我們需要保證在該故障節(jié)點(diǎn)恢復(fù)時發(fā)生的一切都和分布式事務(wù) T 的全局決策保持一致。節(jié)點(diǎn)在恢復(fù)的時候會讀取 T 的最后一個本地日志記錄并作出相應(yīng)的操作:

    1. 如果 T 的最后一條日志記錄是 <commit T>,那么說明協(xié)調(diào)者在節(jié)點(diǎn)發(fā)生故障時的全局決策是提交 T,根據(jù)本地事務(wù)所使用的日志方式,在該節(jié)點(diǎn)上可能需要執(zhí)行 redo T。

    2. 如果 T 的最后一條日志記錄是 <abort T>,那么說明協(xié)調(diào)者在節(jié)點(diǎn)發(fā)生故障時的全局決策是中止 T,根據(jù)本地事務(wù)所使用的日志方式,在該節(jié)點(diǎn)上可能需要執(zhí)行 undo T。

    3. 如果 T 的最后一條日志記錄是 <don't commit T>,則和第 2 中情況類似,執(zhí)行 undo T。

    4. 如果 T 的最后一條日志記錄是 <ready T>,這種情況比較麻煩,因為恢復(fù)節(jié)點(diǎn)無法確認(rèn)在它故障之后協(xié)調(diào)者發(fā)出的最終全局決策是什么,因此它必須要和集群中其余至少一個節(jié)點(diǎn)取得聯(lián)系,詢問 T 的最終結(jié)果是什么:恢復(fù)節(jié)點(diǎn)先嘗試詢問協(xié)調(diào)者,如果此時協(xié)調(diào)者正在工作,則告知恢復(fù)節(jié)點(diǎn) T 的最終結(jié)果,如果是提交就執(zhí)行 redo T,中止就執(zhí)行 undo T;如果協(xié)調(diào)者因故不在工作,則恢復(fù)節(jié)點(diǎn)可以要求其他某一個參與者節(jié)點(diǎn)去查看本地日志以找出 T 的最終結(jié)果并告知恢復(fù)節(jié)點(diǎn)。在最壞的情況下,恢復(fù)節(jié)點(diǎn)無法和集群中其他所有節(jié)點(diǎn)取得聯(lián)系,這時恢復(fù)節(jié)點(diǎn)只能阻塞等待,直至得知 T 的最終結(jié)果是提交還是中止。

    5. 如果本地日志中沒有記錄任何關(guān)于 T 在兩階段提交過程中的操作,那么根據(jù)前面的兩階段提交流程可知恢復(fù)節(jié)點(diǎn)還沒來得及回復(fù)協(xié)調(diào)者的 canCommit? 請求消息就發(fā)生了故障,因此根據(jù)兩階段算法,恢復(fù)節(jié)點(diǎn)只能執(zhí)行 undo T。

    缺陷

    1. 同步阻塞:兩階段提交協(xié)議是一個阻塞的協(xié)議,在第二階段期間,參與者在事務(wù)未提交之前會一直鎖定其占有的本地資源對象,直到接收到來自協(xié)調(diào)者的 doCommit 或 doAbort 消息。

    2. 單點(diǎn)故障:兩階段提交協(xié)議中只有一個協(xié)調(diào)者,而由于在第二階段中參與者在收到協(xié)調(diào)者的進(jìn)一步指示之前會一直鎖住本地資源對象,如果唯一的協(xié)調(diào)者此時出現(xiàn)故障而崩潰掉之后,那么所有參與者都將無限期地阻塞下去,也就是一直鎖住本地資源對象而導(dǎo)致其他進(jìn)程無法使用。

    3. 數(shù)據(jù)不一致:如果在兩階段提交協(xié)議的第二階段中,協(xié)調(diào)者向所有參與者發(fā)送 doCommit 消息之后,發(fā)生了局部網(wǎng)絡(luò)抖動或者異常,抑或是協(xié)調(diào)者在只發(fā)送了部分消息之后就崩潰了,那么就只會有部分參與者接收到了 doCommit 消息并提交了本地事務(wù);其他未收到 doCommit 消息的參與者則不會提交本地事務(wù),因而導(dǎo)致了數(shù)據(jù)不一致問題。

    XA 標(biāo)準(zhǔn)接口

    2PC 兩階段提交協(xié)議本身只是一個通用協(xié)議,不提供具體的工程實現(xiàn)的規(guī)范和標(biāo)準(zhǔn),在工程實踐中為了統(tǒng)一標(biāo)準(zhǔn),減少行業(yè)內(nèi)不必要的對接成本,需要制定標(biāo)準(zhǔn)化的處理模型及接口標(biāo)準(zhǔn),國際開放標(biāo)準(zhǔn)組織 Open Group 定義了分布式事務(wù)處理模型 DTP(Distributed Transaction Processing)Model,現(xiàn)在 XA 已經(jīng)成為 2PC 分布式事務(wù)提交的事實標(biāo)準(zhǔn),很多主流數(shù)據(jù)庫如 Oracle、MySQL 等都已經(jīng)實現(xiàn) XA。

    兩階段事務(wù)提交采用的是 X/OPEN 組織所定義的 DTP Model 所抽象的 AP(應(yīng)用程序), TM(事務(wù)管理器)和 RM(資源管理器) 概念來保證分布式事務(wù)的強(qiáng)一致性。 其中 TM 與 RM 間采用 XA 的協(xié)議進(jìn)行雙向通信。 與傳統(tǒng)的本地事務(wù)相比,XA 事務(wù)增加了準(zhǔn)備階段,數(shù)據(jù)庫除了被動接受提交指令外,還可以反向通知調(diào)用方事務(wù)是否可以被提交。 TM 可以收集所有分支事務(wù)的準(zhǔn)備結(jié)果,并于最后進(jìn)行原子提交,以保證事務(wù)的強(qiáng)一致性。

    分布式之系統(tǒng)底層原理(上)

    Java 通過定義 JTA 接口實現(xiàn)了 XA 模型,JTA 接口中的 ResourceManager 需要數(shù)據(jù)庫廠商提供 XA 驅(qū)動實現(xiàn), TransactionManager 則需要事務(wù)管理器的廠商實現(xiàn),傳統(tǒng)的事務(wù)管理器需要同應(yīng)用服務(wù)器綁定,因此使用的成本很高。 而嵌入式的事務(wù)管器可以以 jar 包的形式提供服務(wù),同 Apache ShardingSphere 集成后,可保證分片后跨庫事務(wù)強(qiáng)一致性。

    通常,只有使用了事務(wù)管理器廠商所提供的 XA 事務(wù)連接池,才能支持 XA 的事務(wù)。Apache ShardingSphere 在整合 XA 事務(wù)時,采用分離 XA 事務(wù)管理和連接池管理的方式,做到對應(yīng)用程序的零侵入。

    三階段提交協(xié)議

    由于前文提到的兩階段提交協(xié)議的種種弊端,研究者們后來又提出了一種新的分布式原子提交協(xié)議:三階段提交協(xié)議(three-phase commit protocol, 3PC)。

    三階段提交協(xié)議是對兩階段提交協(xié)議的擴(kuò)展,它在特定假設(shè)下避免了同步阻塞的問題。該協(xié)議基于以下兩個假設(shè):

    1. 集群不發(fā)生網(wǎng)絡(luò)分區(qū);

    2. 故障節(jié)點(diǎn)數(shù)不超過 K 個(K 是預(yù)先設(shè)定的一個數(shù)值)。

    基于這兩個假設(shè),三階段提交協(xié)議通過引入超時機(jī)制和一個額外的階段來解決阻塞問題,三階段提交協(xié)議把兩階段提交協(xié)議的第一個階段拆分成了兩步:1) 評估,2) 資源對象加鎖,最后才真正提交:

    1. CanCommit 階段:協(xié)調(diào)者發(fā)送 CanCommit 請求消息,詢問各個參與者節(jié)點(diǎn),參與者節(jié)點(diǎn)各自評估本地事務(wù)是否可以執(zhí)行并回復(fù)消息(可以執(zhí)行則回復(fù) YES,否則回復(fù) NO),此階段不執(zhí)行事務(wù),只做判斷;

    2. PreCommit 階段:協(xié)調(diào)者根據(jù)上一階段收集的反饋決定通知各個參與者節(jié)點(diǎn)執(zhí)行(但不提交)或中止本地事務(wù);有兩種可能:1) 所有回復(fù)都是 YES,則發(fā)送 PreCommit請求消息,要求所有參與者執(zhí)行事務(wù)并追加記錄到 undo 和 redo 日志,如果事務(wù)執(zhí)行成功則參與者回復(fù) ACK 響應(yīng)消息,并等待下一階段的指令;2) 反饋消息中只要有一個 NO,或者等待超時之后協(xié)調(diào)者都沒有收到參與者的回復(fù),那么協(xié)調(diào)者會中止事務(wù),發(fā)送 Abort 請求消息給所有參與者,參與者收到該請求后中止本地事務(wù),或者參與者超時等待仍未收到協(xié)調(diào)者的消息,同樣也中止當(dāng)前本地事務(wù)。

    3. DoCommit 階段:協(xié)調(diào)者根據(jù)上一階段收集到的反饋決定通知各個參與者節(jié)點(diǎn)提交或回滾本地事務(wù),分三種情況:1) 協(xié)調(diào)者收到全部參與者回復(fù)的 ACK,則向所有參與者節(jié)點(diǎn)廣播 DoCommit 請求消息,各個參與者節(jié)點(diǎn)收到協(xié)調(diào)者的消息之后決定提交事務(wù),然后釋放資源對象上的鎖,成功之后向協(xié)調(diào)者回復(fù) ACK,協(xié)調(diào)者接收到所有參與者的 ACK 之后,將該分布式事務(wù)標(biāo)記為 committed;2) 協(xié)調(diào)者沒有收到全部參與者回復(fù)的 ACK(可能參與者回復(fù)的不是 ACK,也可能是消息丟失導(dǎo)致超時),那么協(xié)調(diào)者就會中止事務(wù),首先向所有參與者節(jié)點(diǎn)廣播 Abort 請求消息,各個參與者收到該消息后利用上一階段的 undo 日志進(jìn)行事務(wù)的回滾,釋放占用的資源對象,然后回復(fù)協(xié)調(diào)者 ACK 消息,協(xié)調(diào)者收到參與者的 ACK 消息后將該分布式事務(wù)標(biāo)記為 aborted;3) 參與者一直沒有收到協(xié)調(diào)者的消息,等待超時之后會直接提交事務(wù)。

    分布式之系統(tǒng)底層原理(上)

    事實上,在最后階段,協(xié)調(diào)者不是通過追加本地日志的方式記錄提交決定的,而是首先保證讓至少 K 個參與者節(jié)點(diǎn)知道它決定提交該分布式事務(wù)。如果協(xié)調(diào)者發(fā)生故障了,那么剩下的參與者節(jié)點(diǎn)會重新選舉一個新的協(xié)調(diào)者,這個新的協(xié)調(diào)者就可以在集群中不超過 K 個參與者節(jié)點(diǎn)故障的情況下學(xué)習(xí)到舊協(xié)調(diào)者之前是否已經(jīng)決定要提交分布式事務(wù),若是,則重新開始協(xié)議的第三階段,否則就中止該事務(wù),重新發(fā)起分布式事務(wù)。

    在最后的 DoCommit 階段,如果參與者一直沒有收到協(xié)調(diào)者的 DoCommit 或者Abort 請求消息時,會在等待超時之后,直接提交事務(wù)。這個決策機(jī)制是基于概率學(xué)的:當(dāng)已經(jīng)進(jìn)入第三階段之后,說明參與者在第二階段已經(jīng)收到了 PreCommit 請求消息,而協(xié)調(diào)者發(fā)出 PreCommit 請求的前提條件是它在第二階段開頭收集到的第一階段向所有參與者發(fā)出的 CanCommit 請求消息的反饋消息都是 YES。所以參與者可以根據(jù)自己收到了 PreCommit 請求消息這一既定事實得出這樣的一個結(jié)論:其他所有參與者都同意了進(jìn)行這次的事務(wù)執(zhí)行,因此當(dāng)前的參與者節(jié)點(diǎn)有理由相信,進(jìn)入第三階段后,其他參與者節(jié)點(diǎn)的本地事務(wù)最后成功提交的概率很大,而自己遲遲沒有收到 DoCommit 或 Abort 消息可能僅僅是因為網(wǎng)絡(luò)抖動或異常,因此直接提交自己的本地事務(wù)是一個比較合理的選擇。

  •  

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多