溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

分布式事務(wù)——2PC、3PC 和 TCC

發(fā)布時(shí)間:2020-06-23 12:54:46 來源:網(wǎng)絡(luò) 閱讀:2772 作者:wx5d6cccb1cb158 欄目:編程語言

對于單機(jī)下的本地事務(wù),很顯然我們有已被實(shí)踐證明的成熟 ACID 模型來保證數(shù)據(jù)的嚴(yán)格一致性。但對于一個(gè)高訪問量、高并發(fā)的分布式系統(tǒng)來說,如果我們期望實(shí)現(xiàn)一套嚴(yán)格滿足 ACID 特性的分布式事務(wù),很可能出現(xiàn)的情況就是在系統(tǒng)的可用性和嚴(yán)格一致性之間出現(xiàn)沖突——因?yàn)楫?dāng)我們要求分布式系統(tǒng)具有嚴(yán)格一致性時(shí),很可能就要犧牲掉系統(tǒng)的可用性。但毋庸置疑的一點(diǎn)是,可用性又是一個(gè)所有用戶不允許我們討價(jià)還價(jià)的屬性,比如像淘寶這樣的網(wǎng)站,我們要求它 7x24 小時(shí)不間斷地對外服務(wù)。因此,我們需要在可用性和一致性之間做一些取舍,圍繞這種取舍,出現(xiàn)了兩個(gè)經(jīng)典的分布式理論——CAP 和 BASE,這兩者也是所有分布式事務(wù)協(xié)議的基石。

一、CAP 定理

CAP 首次在 ACM PODC 會議上作為猜想被提出,兩年后被證明為定理,從此深深影響了分布式計(jì)算的發(fā)展。CAP 理論告訴我們,一個(gè)分布式系統(tǒng)不可能同時(shí)滿足一致性(Consistency)、可用性(Availability)和分區(qū)容錯(cuò)性(Partition tolerance)這三個(gè)基本需求,最多只能同時(shí)滿足其中的兩項(xiàng)。

  • 一致性:數(shù)據(jù)在多個(gè)副本之間保持一致。當(dāng)有一個(gè)節(jié)點(diǎn)的數(shù)據(jù)發(fā)生更新后,其它節(jié)點(diǎn)應(yīng)該也能同步地更新數(shù)據(jù)。

  • 可用性:對于用戶的每一個(gè)操作請求,系統(tǒng)總能在有限的時(shí)間內(nèi)返回結(jié)果。

  • 分區(qū)容錯(cuò)性:分布式系統(tǒng)中的不同節(jié)點(diǎn)可能分布在不同的子網(wǎng)絡(luò)中,這些子網(wǎng)絡(luò)被稱為網(wǎng)絡(luò)分區(qū)。由于一些特殊原因?qū)е伦泳W(wǎng)絡(luò)之間出現(xiàn)網(wǎng)絡(luò)不連通的情況,系統(tǒng)仍需要能夠保證對外提供一致性和可用性的服務(wù)。

CAP 定理告訴了我們同時(shí)滿足這三項(xiàng)是不可能的,那么放棄其中的一項(xiàng)會是什么樣的呢?

放棄項(xiàng)

放棄P : 如果希望能夠避免出現(xiàn)分區(qū)容錯(cuò)性問題,一種較為簡單的做法是將所有數(shù)據(jù)放在一個(gè)節(jié)點(diǎn)上。這樣肯定不會受網(wǎng)絡(luò)分區(qū)影響。但此時(shí)分布式系統(tǒng)也失去了意義。因此在實(shí)際的架構(gòu)設(shè)計(jì)中,P是一定要滿足的。

放棄A: 放棄可用性就是在系統(tǒng)遇到網(wǎng)絡(luò)分區(qū)或其他故障時(shí),受影響的服務(wù)可以暫時(shí)不對外提供,等到系統(tǒng)恢復(fù)后再對外提供服務(wù)。

放棄C: 放棄一致性不代表完全放棄數(shù)據(jù)一致性,這樣的話系統(tǒng)就沒有意義了。而是放棄數(shù)據(jù)的強(qiáng)一致性,保留最終一致性。這樣的系統(tǒng)無法保證數(shù)據(jù)保持實(shí)時(shí)的一致性,但能夠承諾數(shù)據(jù)最終會達(dá)到一個(gè)一致的狀態(tài)。

實(shí)際的實(shí)現(xiàn)中,我們往往會把精力花在如何根據(jù)業(yè)務(wù)特點(diǎn)在 C(一致性)和 A(可用性)之間尋求平衡。

二、BASE 理論

BASE 是 Basically Available(基本可用)、Soft state(軟狀態(tài))和 Eventually consistent(最終一致性)三個(gè)短語的簡寫。BASE 是對 CAP 中一致性和可用性權(quán)衡的結(jié)果,其來源于對大規(guī)?;ヂ?lián)網(wǎng)系統(tǒng)分布式實(shí)踐的總結(jié)。其核心思想是:即使無法做到強(qiáng)一致性,但每個(gè)應(yīng)用都可以根據(jù)自身的業(yè)務(wù)特點(diǎn),采用適當(dāng)?shù)姆绞絹硎瓜到y(tǒng)達(dá)到最終一致性。

  • 基本可用:基本可用是指在分布式系統(tǒng)出現(xiàn)不可預(yù)知的故障時(shí),允許損失部分性能。比如:正常情況下 0.5 秒就能返回結(jié)果的服務(wù),但在故障情況(網(wǎng)絡(luò)分區(qū)或其他故障)下,需要 1~2 秒;正常情況下,電商網(wǎng)站的首頁展示的是每個(gè)用戶個(gè)性化的推薦內(nèi)容,但在節(jié)日大促的情況下,展示的是統(tǒng)一的推薦內(nèi)容。

  • 軟狀態(tài):軟狀態(tài)是指運(yùn)行系統(tǒng)中的數(shù)據(jù)存在中間狀態(tài),并認(rèn)為該中間狀態(tài)的存在不會影響系統(tǒng)的整體可用性,即允許系統(tǒng)在不同節(jié)點(diǎn)的數(shù)據(jù)副本之間進(jìn)行數(shù)據(jù)同步的過程存在延時(shí)。比如秒殺系統(tǒng)中,用戶余額的扣減和商家余額的增加可以存在延時(shí),當(dāng)用戶余額減了之后即可返回支付成功,商家余額的增加可以等系統(tǒng)壓力小的時(shí)候再做。

  • 最終一致性:最終一致性強(qiáng)調(diào)的是系統(tǒng)中所有的數(shù)據(jù)副本,在經(jīng)過一段時(shí)間的同步后,最終能達(dá)到一個(gè)一致的狀態(tài)。這也是分布式系統(tǒng)的一個(gè)基本要求。

嚴(yán)格遵守 ACID 的分布式事務(wù)我們稱為剛性事務(wù),而遵循 BASE 理論的事務(wù)我們稱為柔性事務(wù)。在分布式環(huán)境下,剛性事務(wù)會讓系統(tǒng)的可用性變得難以忍受,因此實(shí)際生產(chǎn)中使用的分布式事務(wù)都是柔性事務(wù),其中使用最多的就是 2PC、3PC 和 TCC。

三、2PC 協(xié)議

2PC 是二階段提交(Two-phase Commit)的縮寫,顧名思義,這個(gè)協(xié)議分兩階段完成。第一個(gè)階段是準(zhǔn)備階段,第二個(gè)階段是提交階段,準(zhǔn)備階段和提交階段都是由事務(wù)管理器(協(xié)調(diào)者)發(fā)起的,協(xié)調(diào)的對象是資源管理器(參與者)。二階段提交協(xié)議的概念來自 X/Open 組織提出的分布式事務(wù)的規(guī)范 XA 協(xié)議,協(xié)議主要定義了(全局)事務(wù)管理器和(局部)資源管理器之間的接口。XA 接口是雙向的系統(tǒng)接口,在事務(wù)管理器以及一個(gè)或多個(gè)資源管理器之間形成通信橋梁。Java 平臺上的事務(wù)規(guī)范 JTA(Java Transaction API)提供了對 XA 事務(wù)的支持,它要求所有需要被分布式事務(wù)管理的資源(由不同廠商實(shí)現(xiàn))都必須實(shí)現(xiàn)規(guī)定接口(XAResource 中的 prepare、commit 和 rollback 等)。

兩階段如下:

  • 準(zhǔn)備階段:協(xié)調(diào)者向參與者發(fā)起指令,參與者評估自己的狀態(tài),如果參與者評估指令可以完成,參與者會寫 redo 和 undo 日志,然后鎖定資源,執(zhí)行操作,但是并不提交。

  • 提交階段:如果每個(gè)參與者明確返回準(zhǔn)備成功,也就是預(yù)留資源和執(zhí)行操作成功,協(xié)調(diào)者向參與者發(fā)起提交指令,參與者提交資源變更的事務(wù),釋放鎖定的資源;如果任何一個(gè)參與者明確返回準(zhǔn)備失敗,也就是預(yù)留資源或者執(zhí)行操作失敗,協(xié)調(diào)者向參與者發(fā)起中止指令,參與者取消已經(jīng)變更的事務(wù),執(zhí)行 undo 日志,釋放鎖定的資源。

兩階段提交協(xié)議成功場景示意圖如下:


分布式事務(wù)——2PC、3PC 和 TCC



我們看到兩階段提交協(xié)議在準(zhǔn)備階段鎖定資源,是一個(gè)重量級的操作,并能保證強(qiáng)一致性,但是實(shí)現(xiàn)起來復(fù)雜、成本較高,不夠靈活,更重要的是它有如下致命的問題:

  • 阻塞:從上面的描述來看,對于任何一次指令必須收到明確的響應(yīng),才會繼續(xù)做下一步,否則處于阻塞狀態(tài),占用的資源被一直鎖定,不會被釋放。

  • 單點(diǎn)故障:如果協(xié)調(diào)者宕機(jī),參與者沒有了協(xié)調(diào)者指揮,會一直阻塞,盡管可以通過選舉新的協(xié)調(diào)者替代原有協(xié)調(diào)者,但是如果之前協(xié)調(diào)者在發(fā)送一個(gè)提交指令后宕機(jī),而提交指令僅僅被一個(gè)參與者接受,并且參與者接收后也宕機(jī),新上任的協(xié)調(diào)者無法處理這種情況。

  • 腦裂:協(xié)調(diào)者發(fā)送提交指令,有的參與者接收到執(zhí)行了事務(wù),有的參與者沒有接收到事務(wù),就沒有執(zhí)行事務(wù),多個(gè)參與者之間是不一致的。

上面所有的這些問題,都是需要人工干預(yù)處理,沒有自動化的解決方案,因此兩階段提交協(xié)議在正常情況下能保證系統(tǒng)的強(qiáng)一致性,但是在出現(xiàn)異常情況下,當(dāng)前處理的操作處于錯(cuò)誤狀態(tài),需要管理員人工干預(yù)解決,因此可用性不夠好,這也符合 CAP 定理的一致性和可用性不能兼得的原理。

四、3PC 協(xié)議

三階段提交協(xié)議(3PC 協(xié)議)是兩階段提交協(xié)議的改進(jìn)版本。它通過超時(shí)機(jī)制解決了阻塞的問題,并且把兩個(gè)階段增加為三個(gè)階段:

  • 詢問階段:協(xié)調(diào)者詢問參與者是否可以完成指令,協(xié)調(diào)者只需要回答是還是不是,而不需要做真正的操作,這個(gè)階段參與者在等待超時(shí)后會自動中止。

  • 準(zhǔn)備階段:如果在詢問階段所有的參與者都返回可以執(zhí)行操作,協(xié)調(diào)者向參與者發(fā)送預(yù)執(zhí)行請求,然后參與者寫 redo 和 undo 日志,鎖定資源,執(zhí)行操作,但是不提交操作;如果在詢問階段任何參與者返回不能執(zhí)行操作的結(jié)果,則協(xié)調(diào)者向參與者發(fā)送中止請求,這里的邏輯與兩階段提交協(xié)議的的準(zhǔn)備階段是相似的,這個(gè)階段參與者在等待超時(shí)后會自動提交。

  • 提交階段:如果每個(gè)參與者在準(zhǔn)備階段返回準(zhǔn)備成功,也就是預(yù)留資源和執(zhí)行操作成功,協(xié)調(diào)者向參與者發(fā)起提交指令,參與者提交資源變更的事務(wù),釋放鎖定的資源;如果任何一個(gè)參與者返回準(zhǔn)備失敗,也就是預(yù)留資源或者執(zhí)行操作失敗,協(xié)調(diào)者向參與者發(fā)起中止指令,參與者取消已經(jīng)變更的事務(wù),執(zhí)行 undo 日志,釋放鎖定的資源,這里的邏輯與兩階段提交協(xié)議的提交階段一致。

三階段提交協(xié)議成功場景示意圖如下:


分布式事務(wù)——2PC、3PC 和 TCC



這里與兩階段提交協(xié)議有兩個(gè)主要的不同:

  • 增加了一個(gè)詢問階段,詢問階段可以確保盡可能早的發(fā)現(xiàn)無法執(zhí)行操作而需要中止的行為,但是它并不能發(fā)現(xiàn)所有的這種行為,只會減少這種情況的發(fā)生。

  • 增加了等待超時(shí)的處理邏輯,如果在詢問階段等待超時(shí),則自動中止;如果在準(zhǔn)備階段之后等待超時(shí),則自動提交。這也是根據(jù)概率統(tǒng)計(jì)上的正確性最大。

三階段提交協(xié)議相比二階段提交協(xié)議,避免了資源被無限鎖定的情況。但也增加了系統(tǒng)的復(fù)雜度,增加了參與者和協(xié)調(diào)者之間的通信次數(shù)。

五、TCC 協(xié)議

無論是 2PC 還是 3PC,都存在一個(gè)大粒度資源鎖定的問題。為了解釋這個(gè)問題,我們先來想象這樣一種場景,用戶在電商網(wǎng)站購買商品1000元,使用余額支付800元,使用紅包支付200元。我們看一下在 2PC 中的流程:

prepare 階段:

  • 下單系統(tǒng)插入一條訂單記錄,不提交

  • 余額系統(tǒng)減 800 元,給記錄加鎖,寫 redo 和 undo 日志,不提交

  • 紅包系統(tǒng)減 200 元,給記錄加鎖,寫 redo 和 undo 日志,不提交

commit 階段:

  • 下單系統(tǒng)提交訂單記錄

  • 余額系統(tǒng)提交,釋放鎖

  • 紅包系統(tǒng)提交,釋放鎖

為什么說這是一種大粒度的資源鎖定呢?是因?yàn)樵?prepare 階段,當(dāng)數(shù)據(jù)庫給用戶余額減 800 元之后,為了維持隔離性,會給該條記錄加鎖,在事務(wù)提交前,其它事務(wù)無法再訪問該條記錄。但實(shí)際上,我們只需要預(yù)留其中的 800 元,不需要鎖定整個(gè)用戶余額。這是 2PC 和 3PC 的局限,因?yàn)檫@兩者是資源層的協(xié)議,無法提供更靈活的資源鎖定操作。為了解決這個(gè)問題,TCC 應(yīng)運(yùn)而生。TCC 本質(zhì)上也是一個(gè)二階段提交協(xié)議,但和 JTA 中的二階段協(xié)議不同的是,它是一個(gè)服務(wù)層的協(xié)議,因此開發(fā)者可以根據(jù)業(yè)務(wù)自由控制資源鎖定的粒度。我們等會兒可以看到 TCC 在上面這個(gè)場景中的優(yōu)勢,但在那之前,我們先來看一下 TCC 協(xié)議的運(yùn)行過程。

TCC 將事務(wù)的提交過程分為 try-confirm-cancel(實(shí)際上 TCC 就是 try、confirm、cancel 的簡稱) 三個(gè)階段:

  • try:完成業(yè)務(wù)檢查、預(yù)留業(yè)務(wù)資源

  • confirm:使用預(yù)留的資源執(zhí)行業(yè)務(wù)操作(需要保證冪等性)

  • cancel:取消執(zhí)行業(yè)務(wù)操作,釋放預(yù)留的資源(需要保證冪等性)

和 JTA 二階段事務(wù)的參與方都要實(shí)現(xiàn) prepare、commit、rollback 一樣,TCC 的事務(wù)參與方也必須實(shí)現(xiàn) try、confirm、cancel 三個(gè)接口。流程如下:

  1. 事務(wù)發(fā)起方向事務(wù)協(xié)調(diào)器發(fā)起事務(wù)請求,事務(wù)協(xié)調(diào)器調(diào)用所有事務(wù)參與者的 try 方法完成資源的預(yù)留,這時(shí)候并沒有真正執(zhí)行業(yè)務(wù),而是為后面具體要執(zhí)行的業(yè)務(wù)預(yù)留資源,這里完成了一階段。

  2. 如果事務(wù)協(xié)調(diào)器發(fā)現(xiàn)有參與者的 try 方法預(yù)留資源時(shí)候發(fā)現(xiàn)資源不夠,則調(diào)用參與方的 cancel 方法回滾預(yù)留的資源,需要注意 cancel 方法需要實(shí)現(xiàn)業(yè)務(wù)冪等,因?yàn)橛锌赡苷{(diào)用失?。ū热缇W(wǎng)絡(luò)原因參與者接受到了請求,但是由于網(wǎng)絡(luò)原因事務(wù)協(xié)調(diào)器沒有接受到回執(zhí))會重試。

  3. 如果事務(wù)協(xié)調(diào)器發(fā)現(xiàn)所有參與者的 try 方法返回都 OK,則事務(wù)協(xié)調(diào)器調(diào)用所有參與者的 confirm 方法,不做資源檢查,直接進(jìn)行具體的業(yè)務(wù)操作。

  4. 如果協(xié)調(diào)器發(fā)現(xiàn)所有參與者的 confirm 方法都 OK 了,則分布式事務(wù)結(jié)束。

  5. 如果協(xié)調(diào)器發(fā)現(xiàn)有些參與者的 confirm 方法失敗了,或者由于網(wǎng)絡(luò)原因沒有收到回執(zhí),則協(xié)調(diào)器會進(jìn)行重試。這里如果重試一定次數(shù)后還是失敗,會怎么樣?常見的是做事務(wù)補(bǔ)償。

TCC 執(zhí)行場景示意圖如下:

分布式事務(wù)——2PC、3PC 和 TCC


現(xiàn)在我們再回到開始的那個(gè)支付場景中,看看 TCC 在該場景中的流程:

Try操作

  • tryX 下單系統(tǒng)創(chuàng)建待支付訂單

  • tryY 凍結(jié)賬戶紅包 200 元

  • tryZ 凍結(jié)資金賬戶 800 元

Confirm操作

  • confirmX 訂單更新為支付成功

  • confirmY 扣減賬戶紅包 200 元

  • confirmZ 扣減資金賬戶 800 元

Cancel操作

  • cancelX 訂單處理異常,資金紅包退回,訂單支付失敗

  • cancelY 凍結(jié)紅包失敗,賬戶余額退回,訂單支付失敗

  • cancelZ 凍結(jié)余額失敗,賬戶紅包退回,訂單支付失敗

可以看到,我們使用了凍結(jié)代替了原先的賬號鎖定(實(shí)際操作中,凍結(jié)操作可以用數(shù)據(jù)庫減操作+日志實(shí)現(xiàn)),這樣在凍結(jié)操作之后,事務(wù)提交之前,其它事務(wù)也能使用賬戶余額,提高了并發(fā)性。

總結(jié)一下,相比于二階段提交協(xié)議,TCC 主要有以下區(qū)別:

  • 2PC 位于資源層而 TCC 位于服務(wù)層。

  • 2PC 的接口由第三方廠商實(shí)現(xiàn),TCC 的接口由開發(fā)人員實(shí)現(xiàn)。

  • TCC 可以更靈活地控制資源鎖定的粒度。

  • TCC 對應(yīng)用的侵入性強(qiáng)。業(yè)務(wù)邏輯的每個(gè)分支都需要實(shí)現(xiàn) try、confirm、cancel 三個(gè)操作,應(yīng)用侵入性較強(qiáng),改造成本高。


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI