自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

還不理解“分布式事務(wù)”?這篇給你講清楚!

原創(chuàng)
開(kāi)發(fā) 架構(gòu) 開(kāi)發(fā)工具 分布式
這篇文章將介紹什么是分布式事務(wù),分布式事務(wù)解決什么問(wèn)題,對(duì)分布式事務(wù)實(shí)現(xiàn)的難點(diǎn),解決思路,不同場(chǎng)景下方案的選擇,通過(guò)圖解的方式進(jìn)行梳理、總結(jié)和比較。

【51CTO.com原創(chuàng)稿件】這篇文章將介紹什么是分布式事務(wù),分布式事務(wù)解決什么問(wèn)題,對(duì)分布式事務(wù)實(shí)現(xiàn)的難點(diǎn),解決思路,不同場(chǎng)景下方案的選擇,通過(guò)圖解的方式進(jìn)行梳理、總結(jié)和比較。

[[252091]]

相信耐心看完這篇文章,談到分布式事務(wù),不再只是有“2PC”、“3PC”、“MQ的消息事務(wù)”、“最終一致性”、“TCC”等這些知識(shí)碎片,而是能夠?qū)⒅R(shí)連成一片,形成知識(shí)體系。

什么是事務(wù)

介紹分布式事務(wù)之前,先介紹什么是事務(wù)。

事務(wù)的具體定義

事務(wù)提供一種機(jī)制將一個(gè)活動(dòng)涉及的所有操作納入到一個(gè)不可分割的執(zhí)行單元,組成事務(wù)的所有操作只有在所有操作均能正常執(zhí)行的情況下方能提交,只要其中任一操作執(zhí)行失敗,都將導(dǎo)致整個(gè)事務(wù)的回滾。

簡(jiǎn)單地說(shuō),事務(wù)提供一種“ 要么什么都不做,要么做全套(All or Nothing)”機(jī)制。

還不理解“分布式事務(wù)”?這篇給你講清楚!

數(shù)據(jù)庫(kù)事務(wù)的 ACID 屬性

事務(wù)是基于數(shù)據(jù)進(jìn)行操作,需要保證事務(wù)的數(shù)據(jù)通常存儲(chǔ)在數(shù)據(jù)庫(kù)中,所以介紹到事務(wù),就不得不介紹數(shù)據(jù)庫(kù)事務(wù)的 ACID 特性。

ACID 指數(shù)據(jù)庫(kù)事務(wù)正確執(zhí)行的四個(gè)基本特性的縮寫(xiě),包含:

原子性(Atomicity)

整個(gè)事務(wù)中的所有操作,要么全部完成,要么全部不完成,不可能停滯在中間某個(gè)環(huán)節(jié)。

事務(wù)在執(zhí)行過(guò)程中發(fā)生錯(cuò)誤,會(huì)被回滾(Rollback)到事務(wù)開(kāi)始前的狀態(tài),就像這個(gè)事務(wù)從來(lái)沒(méi)有執(zhí)行過(guò)一樣。

例如:銀行轉(zhuǎn)賬,從 A 賬戶轉(zhuǎn) 100 元至 B 賬戶,分為兩個(gè)步驟:

  • 從 A 賬戶取 100 元。
  • 存入 100 元至 B 賬戶。

這兩步要么一起完成,要么一起不完成,如果只完成***步,第二步失敗,錢(qián)會(huì)莫名其妙少了 100 元。

一致性(Consistency)

在事務(wù)開(kāi)始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫(kù)數(shù)據(jù)的一致性約束沒(méi)有被破壞。

例如:現(xiàn)有完整性約束 A+B=100,如果一個(gè)事務(wù)改變了 A,那么必須得改變 B,使得事務(wù)結(jié)束后依然滿足 A+B=100,否則事務(wù)失敗。

隔離性(Isolation)

數(shù)據(jù)庫(kù)允許多個(gè)并發(fā)事務(wù)同時(shí)對(duì)數(shù)據(jù)進(jìn)行讀寫(xiě)和修改的能力,如果一個(gè)事務(wù)要訪問(wèn)的數(shù)據(jù)正在被另外一個(gè)事務(wù)修改,只要另外一個(gè)事務(wù)未提交,它所訪問(wèn)的數(shù)據(jù)就不受未提交事務(wù)的影響。

隔離性可以防止多個(gè)事務(wù)并發(fā)執(zhí)行時(shí)由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致。

例如:現(xiàn)有有個(gè)交易是從 A 賬戶轉(zhuǎn) 100 元至 B 賬戶,在這個(gè)交易事務(wù)還未完成的情況下,如果此時(shí) B 查詢(xún)自己的賬戶,是看不到新增加的 100 元的。

持久性(Durability)

事務(wù)處理結(jié)束后,對(duì)數(shù)據(jù)的修改就是***的,即便系統(tǒng)故障也不會(huì)丟失。

還不理解“分布式事務(wù)”?這篇給你講清楚!

簡(jiǎn)單而言,ACID 是從不同維度描述事務(wù)的特性:

  • 原子性:事務(wù)操作的整體性。
  • 一致性:事務(wù)操作下數(shù)據(jù)的正確性。
  • 隔離性:事務(wù)并發(fā)操作下數(shù)據(jù)的正確性。
  • 持久性:事務(wù)對(duì)數(shù)據(jù)修改的可靠性。

一個(gè)支持事務(wù)(Transaction)的數(shù)據(jù)庫(kù),需要具有這 4 種特性,否則在事務(wù)過(guò)程當(dāng)中無(wú)法保證數(shù)據(jù)的正確性,處理結(jié)果極可能達(dá)不到請(qǐng)求方的要求。

什么時(shí)候使用數(shù)據(jù)庫(kù)事務(wù)

在介紹完事務(wù)基本概念之后,什么時(shí)候該使用數(shù)據(jù)庫(kù)事務(wù)?

簡(jiǎn)單而言,就是業(yè)務(wù)上有一組數(shù)據(jù)操作,需要如果其中有任何一個(gè)操作執(zhí)行失敗,整組操作全部不執(zhí)行并恢復(fù)到未執(zhí)行狀態(tài),要么全部成功,要么全部失敗。

在使用數(shù)據(jù)庫(kù)事務(wù)時(shí)需要注意,盡可能短的保持事務(wù),修改多個(gè)不同表的數(shù)據(jù)的冗長(zhǎng)事務(wù)會(huì)嚴(yán)重妨礙系統(tǒng)中的所有其他用戶,這很有可能導(dǎo)致一些性能問(wèn)題。

二、什么是分布式事務(wù)

介紹完事務(wù)相關(guān)基本概念之后,下面介紹分布式事務(wù)。

分布式產(chǎn)生背景與概念

隨著互聯(lián)網(wǎng)快速發(fā)展,微服務(wù),SOA 等服務(wù)架構(gòu)模式正在被大規(guī)模的使用,現(xiàn)在分布式系統(tǒng)一般由多個(gè)獨(dú)立的子系統(tǒng)組成,多個(gè)子系統(tǒng)通過(guò)網(wǎng)絡(luò)通信互相協(xié)作配合完成各個(gè)功能。

有很多用例會(huì)跨多個(gè)子系統(tǒng)才能完成,比較典型的是電子商務(wù)網(wǎng)站的下單支付流程,至少會(huì)涉及交易系統(tǒng)和支付系統(tǒng)。

而且這個(gè)過(guò)程中會(huì)涉及到事務(wù)的概念,即保證交易系統(tǒng)和支付系統(tǒng)的數(shù)據(jù)一致性,此處我們稱(chēng)這種跨系統(tǒng)的事務(wù)為分布式事務(wù)。

具體一點(diǎn)而言,分布式事務(wù)是指事務(wù)的參與者、支持事務(wù)的服務(wù)器、資源服務(wù)器以及事務(wù)管理器分別位于不同的分布式系統(tǒng)的不同節(jié)點(diǎn)之上。

舉個(gè)互聯(lián)網(wǎng)常用的交易業(yè)務(wù)為例:

還不理解“分布式事務(wù)”?這篇給你講清楚!

上圖中包含了庫(kù)存和訂單兩個(gè)獨(dú)立的微服務(wù),每個(gè)微服務(wù)維護(hù)了自己的數(shù)據(jù)庫(kù)。

在交易系統(tǒng)的業(yè)務(wù)邏輯中,一個(gè)商品在下單之前需要先調(diào)用庫(kù)存服務(wù),進(jìn)行扣除庫(kù)存,再調(diào)用訂單服務(wù),創(chuàng)建訂單記錄。

還不理解“分布式事務(wù)”?這篇給你講清楚!

可以看到,如果多個(gè)數(shù)據(jù)庫(kù)之間的數(shù)據(jù)更新沒(méi)有保證事務(wù),將會(huì)導(dǎo)致出現(xiàn)子系統(tǒng)數(shù)據(jù)不一致,業(yè)務(wù)出現(xiàn)問(wèn)題。

分布式事務(wù)的難點(diǎn)

事務(wù)的原子性

事務(wù)操作跨不同節(jié)點(diǎn),當(dāng)多個(gè)節(jié)點(diǎn)某一節(jié)點(diǎn)操作失敗時(shí),需要保證多節(jié)點(diǎn)操作的要么什么都不做,要么做全套(All or Nothing)的原子性。

事務(wù)的一致性

當(dāng)發(fā)生網(wǎng)絡(luò)傳輸故障或者節(jié)點(diǎn)故障,節(jié)點(diǎn)間數(shù)據(jù)復(fù)制通道中斷,在進(jìn)行事務(wù)操作時(shí)需要保證數(shù)據(jù)一致性,保證事務(wù)的任何操作都不會(huì)使得數(shù)據(jù)違反數(shù)據(jù)庫(kù)定義的約束、觸發(fā)器等規(guī)則。

事務(wù)的隔離性

事務(wù)隔離性的本質(zhì)就是如何正確處理多個(gè)并發(fā)事務(wù)的讀寫(xiě)沖突和寫(xiě)寫(xiě)沖突,因?yàn)樵诜植际绞聞?wù)控制中,可能會(huì)出現(xiàn)提交不同步的現(xiàn)象,這個(gè)時(shí)候就有可能出現(xiàn)“部分已經(jīng)提交”的事務(wù)。

此時(shí)并發(fā)應(yīng)用訪問(wèn)數(shù)據(jù)如果沒(méi)有加以控制,有可能出現(xiàn)“臟讀”問(wèn)題。

三、分布式系統(tǒng)的一致性

前面介紹到的分布式事務(wù)的難點(diǎn)涉及的問(wèn)題,最終影響是導(dǎo)致數(shù)據(jù)出現(xiàn)不一致,下面對(duì)分布式系統(tǒng)的一致性問(wèn)題進(jìn)行理論分析,后面將基于這些理論進(jìn)行分布式方案的介紹。

可用性和一致性的沖突:CAP 理論

還不理解“分布式事務(wù)”?這篇給你講清楚!

CAP 定理又被稱(chēng)作布魯爾定理,是加州大學(xué)的計(jì)算機(jī)科學(xué)家布魯爾在 2000 年提出的一個(gè)猜想。

2002 年,麻省理工學(xué)院的賽斯·吉爾伯特和南希·林奇發(fā)表了布魯爾猜想的證明,使之成為分布式計(jì)算領(lǐng)域公認(rèn)的一個(gè)定理。

布魯爾在提出 CAP 猜想時(shí)并沒(méi)有具體定義 Consistency、Availability、Partition Tolerance 這 3 個(gè)詞的含義,不同資料的具體定義也有差別。

為了更好地解釋?zhuān)旅孢x擇Robert Greiner的文章《CAP Theorem》作為參考基礎(chǔ):

  • http://robertgreiner.com/about/
  • http://robertgreiner.com/2014/08/cap-theorem-revisited/

CAP 理論的定義

在一個(gè)分布式系統(tǒng)(指互相連接并共享數(shù)據(jù)的節(jié)點(diǎn)的集合)中,當(dāng)涉及讀寫(xiě)操作時(shí),只能保證一致性(Consistence)、可用性(Availability)、分區(qū)容錯(cuò)性(Partition Tolerance)三者中的兩個(gè),另外一個(gè)必須被犧牲。

Consistency、Availability、Partition Tolerance 具體解釋如下:

C - Consistency 一致性:A read is guaranteed to return the most recent write for a given client.

對(duì)某個(gè)指定的客戶端來(lái)說(shuō),讀操作保證能夠返回***的寫(xiě)操作結(jié)果。

這里并不是強(qiáng)調(diào)同一時(shí)刻擁有相同的數(shù)據(jù),對(duì)于系統(tǒng)執(zhí)行事務(wù)來(lái)說(shuō),在事務(wù)執(zhí)行過(guò)程中,系統(tǒng)其實(shí)處于一個(gè)不一致的狀態(tài),不同的節(jié)點(diǎn)的數(shù)據(jù)并不完全一致。

一致性強(qiáng)調(diào)客戶端讀操作能夠獲取***的寫(xiě)操作結(jié)果,是因?yàn)槭聞?wù)在執(zhí)行過(guò)程中,客戶端是無(wú)法讀取到未提交的數(shù)據(jù)的。

只有等到事務(wù)提交后,客戶端才能讀取到事務(wù)寫(xiě)入的數(shù)據(jù),而如果事務(wù)失敗則會(huì)進(jìn)行回滾,客戶端也不會(huì)讀取到事務(wù)中間寫(xiě)入的數(shù)據(jù)。

A - Availability 可用性:A non-failing node will return a reasonable response within a reasonable amount of time (no error or timeout).

非故障的節(jié)點(diǎn)在合理的時(shí)間內(nèi)返回合理的響應(yīng)(不是錯(cuò)誤和超時(shí)的響應(yīng))。

這里強(qiáng)調(diào)的是合理的響應(yīng),不能超時(shí),不能出錯(cuò)。注意并沒(méi)有說(shuō)“正確”的結(jié)果,例如,應(yīng)該返回 100 但實(shí)際上返回了 90,肯定是不正確的結(jié)果,但可以是一個(gè)合理的結(jié)果。

P - Partition Tolerance 分區(qū)容忍性:The system will continue to function when network partitions occur.

當(dāng)出現(xiàn)網(wǎng)絡(luò)分區(qū)后,系統(tǒng)能夠繼續(xù)“履行職責(zé)”。

這里網(wǎng)絡(luò)分區(qū)是指:一個(gè)分布式系統(tǒng)里面,節(jié)點(diǎn)組成的網(wǎng)絡(luò)本來(lái)應(yīng)該是連通的。

然而可能因?yàn)橐恍┕收?節(jié)點(diǎn)間網(wǎng)絡(luò)連接斷開(kāi)、節(jié)點(diǎn)宕機(jī)),使得有些節(jié)點(diǎn)之間不連通了,整個(gè)網(wǎng)絡(luò)就分成了幾塊區(qū)域,數(shù)據(jù)就散布在了這些不連通的區(qū)域中。

一致性、可用性、分區(qū)容忍性的選擇

雖然 CAP 理論定義是三個(gè)要素中只能取兩個(gè),但放到分布式環(huán)境下來(lái)思考,我們會(huì)發(fā)現(xiàn)必須選擇 P(分區(qū)容忍)要素,因?yàn)榫W(wǎng)絡(luò)本身無(wú)法做到 100% 可靠,有可能出故障,所以分區(qū)是一個(gè)必然的現(xiàn)象。

如果我們選擇了 CA(一致性 + 可用性) 而放棄了 P(分區(qū)容忍性),那么當(dāng)發(fā)生分區(qū)現(xiàn)象時(shí),為了保證 C(一致性),系統(tǒng)需要禁止寫(xiě)入。

當(dāng)有寫(xiě)入請(qǐng)求時(shí),系統(tǒng)返回 error(例如,當(dāng)前系統(tǒng)不允許寫(xiě)入),這又和 A(可用性) 沖突了,因?yàn)?A(可用性)要求返回 no error 和 no timeout。

因此,分布式系統(tǒng)理論上不可能選擇 CA (一致性 + 可用性)架構(gòu),只能選擇 CP(一致性 + 分區(qū)容忍性) 或者 AP (可用性 + 分區(qū)容忍性)架構(gòu),在一致性和可用性做折中選擇。

①CP - Consistency + Partition Tolerance (一致性 + 分區(qū)容忍性)

還不理解“分布式事務(wù)”?這篇給你講清楚!

如上圖所示,因?yàn)?Node1 節(jié)點(diǎn)和 Node2 節(jié)點(diǎn)連接中斷導(dǎo)致分區(qū)現(xiàn)象,Node1 節(jié)點(diǎn)的數(shù)據(jù)已經(jīng)更新到 y,但是 Node1 和 Node2 之間的復(fù)制通道中斷,數(shù)據(jù) y 無(wú)法同步到 Node2,Node2 節(jié)點(diǎn)上的數(shù)據(jù)還是舊數(shù)據(jù) x。

這時(shí)客戶端 C 訪問(wèn) Node2 時(shí),Node2 需要返回 error,提示客戶端 “系統(tǒng)現(xiàn)在發(fā)生了錯(cuò)誤”,這種處理方式違背了可用性(Availability)的要求,因此 CAP 三者只能滿足 CP。

②AP - Availability + Partition Tolerance (可用性 + 分區(qū)容忍性)

還不理解“分布式事務(wù)”?這篇給你講清楚!

同樣是 Node2 節(jié)點(diǎn)上的數(shù)據(jù)還是舊數(shù)據(jù) x,這時(shí)客戶端 C 訪問(wèn) Node2 時(shí),Node2 將當(dāng)前自己擁有的數(shù)據(jù) x 返回給客戶端了。

而實(shí)際上當(dāng)前***的數(shù)據(jù)已經(jīng)是 y 了,這就不滿足一致性(Consistency)的要求了,因此 CAP 三者只能滿足 AP。

注意:這里 Node2 節(jié)點(diǎn)返回 x,雖然不是一個(gè)“正確”的結(jié)果,但是一個(gè)“合理”的結(jié)果,因?yàn)?x 是舊的數(shù)據(jù),并不是一個(gè)錯(cuò)亂的值,只是不是***的數(shù)據(jù)。

值得補(bǔ)充的是,CAP 理論告訴我們分布式系統(tǒng)只能選擇 AP 或者 CP,但實(shí)際上并不是說(shuō)整個(gè)系統(tǒng)只能選擇 AP 或者 CP。

在 CAP 理論落地實(shí)踐時(shí),我們需要將系統(tǒng)內(nèi)的數(shù)據(jù)按照不同的應(yīng)用場(chǎng)景和要求進(jìn)行分類(lèi),每類(lèi)數(shù)據(jù)選擇不同的策略(CP 還是 AP),而不是直接限定整個(gè)系統(tǒng)所有數(shù)據(jù)都是同一策略。

另外,只能選擇 CP 或者 AP 是指系統(tǒng)發(fā)生分區(qū)現(xiàn)象時(shí)無(wú)法同時(shí)保證 C(一致性)和 A(可用性),但不是意味著什么都不做,當(dāng)分區(qū)故障解決后,系統(tǒng)還是要保持保證 CA。

CAP 理論的延伸:BASE 理論

還不理解“分布式事務(wù)”?這篇給你講清楚!

BASE 是指基本可用(Basically Available)、軟狀態(tài)( Soft State)、最終一致性( Eventual Consistency)。

它的核心思想是即使無(wú)法做到強(qiáng)一致性(CAP 的一致性就是強(qiáng)一致性),但應(yīng)用可以采用適合的方式達(dá)到最終一致性。

BA - Basically Available 基本可用

分布式系統(tǒng)在出現(xiàn)故障時(shí),允許損失部分可用性,即保證核心可用。

這里的關(guān)鍵詞是“部分”和“核心”,實(shí)際實(shí)踐上,哪些是核心需要根據(jù)具體業(yè)務(wù)來(lái)權(quán)衡。

例如登錄功能相對(duì)注冊(cè)功能更加核心,注冊(cè)不了最多影響流失一部分用戶,如果用戶已經(jīng)注冊(cè)但無(wú)法登錄,那就意味著用戶無(wú)法使用系統(tǒng),造成的影響范圍更大。

S - Soft State 軟狀態(tài)

允許系統(tǒng)存在中間狀態(tài),而該中間狀態(tài)不會(huì)影響系統(tǒng)整體可用性。這里的中間狀態(tài)就是 CAP 理論中的數(shù)據(jù)不一致。

E - Eventual Consistency 最終一致性

系統(tǒng)中的所有數(shù)據(jù)副本經(jīng)過(guò)一定時(shí)間后,最終能夠達(dá)到一致的狀態(tài)。

這里的關(guān)鍵詞是“一定時(shí)間” 和 “最終”,“一定時(shí)間”和數(shù)據(jù)的特性是強(qiáng)關(guān)聯(lián)的,不同業(yè)務(wù)不同數(shù)據(jù)能夠容忍的不一致時(shí)間是不同的。

例如支付類(lèi)業(yè)務(wù)是要求秒級(jí)別內(nèi)達(dá)到一致,因?yàn)橛脩魰r(shí)時(shí)關(guān)注;用戶發(fā)的***微博,可以容忍 30 分鐘內(nèi)達(dá)到一致的狀態(tài),因?yàn)橛脩舳虝r(shí)間看不到明星發(fā)的微博是無(wú)感知的。

而“最終”的含義就是不管多長(zhǎng)時(shí)間,最終還是要達(dá)到一致性的狀態(tài)。

BASE 理論本質(zhì)上是對(duì) CAP 的延伸和補(bǔ)充,更具體地說(shuō),是對(duì) CAP 中 AP 方案的一個(gè)補(bǔ)充: CAP 理論是忽略延時(shí)的,而實(shí)際應(yīng)用中延時(shí)是無(wú)法避免的。

這一點(diǎn)就意味著***的 CP 場(chǎng)景是不存在的,即使是幾毫秒的數(shù)據(jù)復(fù)制延遲,在這幾毫秒時(shí)間間隔內(nèi),系統(tǒng)是不符合 CP 要求的。

因此 CAP 中的 CP 方案,實(shí)際上也是實(shí)現(xiàn)了最終一致性,只是“一定時(shí)間”是指幾毫秒而已。

AP 方案中犧牲一致性只是指發(fā)生分區(qū)故障期間,而不是永遠(yuǎn)放棄一致性。

這一點(diǎn)其實(shí)就是 BASE 理論延伸的地方,分區(qū)期間犧牲一致性,但分區(qū)故障恢復(fù)后,系統(tǒng)應(yīng)該達(dá)到最終一致性。

數(shù)據(jù)一致性模型

前面介紹的 BASE 模型提過(guò)“強(qiáng)一致性”和“最終一致性”,下面對(duì)這些一致性模型展開(kāi)介紹。

分布式系統(tǒng)通過(guò)復(fù)制數(shù)據(jù)來(lái)提高系統(tǒng)的可靠性和容錯(cuò)性,并且將數(shù)據(jù)的不同的副本存放在不同的機(jī)器上,由于維護(hù)數(shù)據(jù)副本的一致性代價(jià)很高,因此許多系統(tǒng)采用弱一致性來(lái)提高性能。

下面介紹常見(jiàn)的一致性模型:

強(qiáng)一致性:要求無(wú)論更新操作是在哪個(gè)數(shù)據(jù)副本上執(zhí)行,之后所有的讀操作都要能獲得***的數(shù)據(jù)。

對(duì)于單副本數(shù)據(jù)來(lái)說(shuō),讀寫(xiě)操作是在同一數(shù)據(jù)上執(zhí)行的,容易保證強(qiáng)一致性。對(duì)多副本數(shù)據(jù)來(lái)說(shuō),則需要使用分布式事務(wù)協(xié)議。

弱一致性:在這種一致性下,用戶讀到某一操作對(duì)系統(tǒng)特定數(shù)據(jù)的更新需要一段時(shí)間,我們將這段時(shí)間稱(chēng)為"不一致性窗口"。

最終一致性:是弱一致性的一種特例,在這種一致性下系統(tǒng)保證用戶最終能夠讀取到某操作對(duì)系統(tǒng)特定數(shù)據(jù)的更新(讀取操作之前沒(méi)有該數(shù)據(jù)的其他更新操作)。

"不一致性窗口"的大小依賴(lài)于交互延遲、系統(tǒng)的負(fù)載,以及數(shù)據(jù)的副本數(shù)等。

系統(tǒng)選擇哪種一致性模型取決于應(yīng)用對(duì)一致性的需求,所選取的一致性模型還會(huì)影響到系統(tǒng)如何處理用戶的請(qǐng)求以及對(duì)副本維護(hù)技術(shù)的選擇等。

后面將基于上面介紹的一致性模型分別介紹分布式事務(wù)的解決方案。

柔性事務(wù)

柔性事務(wù)的概念

在電商等互聯(lián)網(wǎng)場(chǎng)景下,傳統(tǒng)的事務(wù)在數(shù)據(jù)庫(kù)性能和處理能力上都暴露出了瓶頸。在分布式領(lǐng)域基于 CAP 理論以及 BASE 理論,有人就提出了柔性事務(wù)的概念。

基于 BASE 理論的設(shè)計(jì)思想,柔性事務(wù)下,在不影響系統(tǒng)整體可用性的情況下(Basically Available 基本可用),允許系統(tǒng)存在數(shù)據(jù)不一致的中間狀態(tài)(Soft State 軟狀態(tài)),在經(jīng)過(guò)數(shù)據(jù)同步的延時(shí)之后,最終數(shù)據(jù)能夠達(dá)到一致。

并不是完全放棄了 ACID,而是通過(guò)放寬一致性要求,借助本地事務(wù)來(lái)實(shí)現(xiàn)最終分布式事務(wù)一致性的同時(shí)也保證系統(tǒng)的吞吐。

實(shí)現(xiàn)柔性事務(wù)的一些特性

下面介紹的是實(shí)現(xiàn)柔性事務(wù)的一些常見(jiàn)特性,這些特性在具體的方案中不一定都要滿足,因?yàn)椴煌姆桨敢蟛灰粯印?/p>

可見(jiàn)性(對(duì)外可查詢(xún)) :在分布式事務(wù)執(zhí)行過(guò)程中,如果某一個(gè)步驟執(zhí)行出錯(cuò),就需要明確的知道其他幾個(gè)操作的處理情況,這就需要其他的服務(wù)都能夠提供查詢(xún)接口,保證可以通過(guò)查詢(xún)來(lái)判斷操作的處理情況。

為了保證操作的可查詢(xún),需要對(duì)于每一個(gè)服務(wù)的每一次調(diào)用都有一個(gè)全局唯一的標(biāo)識(shí),可以是業(yè)務(wù)單據(jù)號(hào)(如訂單號(hào))、也可以是系統(tǒng)分配的操作流水號(hào)(如支付記錄流水號(hào))。除此之外,操作的時(shí)間信息也要有完整的記錄。

操作冪等性:冪等性,其實(shí)是一個(gè)數(shù)學(xué)概念。冪等函數(shù),或冪等方法,是指可以使用相同參數(shù)重復(fù)執(zhí)行,并能獲得相同結(jié)果的函數(shù)。

冪等操作的特點(diǎn)是其任意多次執(zhí)行所產(chǎn)生的影響均與一次執(zhí)行的影響相同。也就是說(shuō),同一個(gè)方法,使用同樣的參數(shù),調(diào)用多次產(chǎn)生的業(yè)務(wù)結(jié)果與調(diào)用一次產(chǎn)生的業(yè)務(wù)結(jié)果相同。

之所以需要操作冪等性,是因?yàn)闉榱吮WC數(shù)據(jù)的最終一致性,很多事務(wù)協(xié)議都會(huì)有很多重試的操作,如果一個(gè)方法不保證冪等,那么將無(wú)法被重試。

冪等操作的實(shí)現(xiàn)方式有多種,如在系統(tǒng)中緩存所有的請(qǐng)求與處理結(jié)果、檢測(cè)到重復(fù)操作后,直接返回上一次的處理結(jié)果等。

四、常見(jiàn)分布式事務(wù)解決方案

介紹完分布式系統(tǒng)的一致性相關(guān)理論,下面基于不同的一致性模型介紹分布式事務(wù)的常見(jiàn)解決方案,后面會(huì)再介紹各個(gè)方案的使用場(chǎng)景。

分布式事務(wù)的實(shí)現(xiàn)有許多種,其中較經(jīng)典是由 Tuxedo 提出的 XA 分布式事務(wù)協(xié)議,XA 協(xié)議包含二階段提交(2PC)和三階段提交(3PC)兩種實(shí)現(xiàn)。

2PC(二階段提交)方案:強(qiáng)一致性

方案簡(jiǎn)介

二階段提交協(xié)議(Two-phase Commit,即 2PC)是常用的分布式事務(wù)解決方案,即將事務(wù)的提交過(guò)程分為兩個(gè)階段來(lái)進(jìn)行處理:準(zhǔn)備階段和提交階段。事務(wù)的發(fā)起者稱(chēng)協(xié)調(diào)者,事務(wù)的執(zhí)行者稱(chēng)參與者。

在分布式系統(tǒng)里,每個(gè)節(jié)點(diǎn)都可以知曉自己操作的成功或者失敗,卻無(wú)法知道其他節(jié)點(diǎn)操作的成功或失敗。

當(dāng)一個(gè)事務(wù)跨多個(gè)節(jié)點(diǎn)時(shí),為了保持事務(wù)的原子性與一致性,而引入一個(gè)協(xié)調(diào)者來(lái)統(tǒng)一掌控所有參與者的操作結(jié)果,并指示它們是否要把操作結(jié)果進(jìn)行真正的提交或者回滾(rollback)。

二階段提交的算法思路可以概括為:參與者將操作成敗通知協(xié)調(diào)者,再由協(xié)調(diào)者根據(jù)所有參與者的反饋情報(bào)決定各參與者是否要提交操作還是中止操作。

核心思想就是對(duì)每一個(gè)事務(wù)都采用先嘗試后提交的處理方式,處理后所有的讀操作都要能獲得***的數(shù)據(jù),因此也可以將二階段提交看作是一個(gè)強(qiáng)一致性算法。

處理流程

簡(jiǎn)單一點(diǎn)理解,可以把協(xié)調(diào)者節(jié)點(diǎn)比喻為帶頭大哥,參與者理解比喻為跟班小弟,帶頭大哥統(tǒng)一協(xié)調(diào)跟班小弟的任務(wù)執(zhí)行。

階段 1:準(zhǔn)備階段

準(zhǔn)備階段有如下三個(gè)步驟:

  • 協(xié)調(diào)者向所有參與者發(fā)送事務(wù)內(nèi)容,詢(xún)問(wèn)是否可以提交事務(wù),并等待所有參與者答復(fù)。
  • 各參與者執(zhí)行事務(wù)操作,將 undo 和 redo 信息記入事務(wù)日志中(但不提交事務(wù))。
  • 如參與者執(zhí)行成功,給協(xié)調(diào)者反饋 yes,即可以提交;如執(zhí)行失敗,給協(xié)調(diào)者反饋 no,即不可提交。

階段 2:提交階段

如果協(xié)調(diào)者收到了參與者的失敗消息或者超時(shí),直接給每個(gè)參與者發(fā)送回滾(rollback)消息;否則,發(fā)送提交(commit)消息。

參與者根據(jù)協(xié)調(diào)者的指令執(zhí)行提交或者回滾操作,釋放所有事務(wù)處理過(guò)程中使用的鎖資源。(注意:必須在***階段釋放鎖資源) 接下來(lái)分兩種情況分別討論提交階段的過(guò)程。

還不理解“分布式事務(wù)”?這篇給你講清楚!

情況 1,當(dāng)所有參與者均反饋 yes,提交事務(wù),如上圖:

  • 協(xié)調(diào)者向所有參與者發(fā)出正式提交事務(wù)的請(qǐng)求(即 commit 請(qǐng)求)。
  • 參與者執(zhí)行 commit 請(qǐng)求,并釋放整個(gè)事務(wù)期間占用的資源。
  • 各參與者向協(xié)調(diào)者反饋 ack(應(yīng)答)完成的消息。
  • 協(xié)調(diào)者收到所有參與者反饋的 ack 消息后,即完成事務(wù)提交。

還不理解“分布式事務(wù)”?這篇給你講清楚!

情況 2,當(dāng)任何階段 1 一個(gè)參與者反饋 no,中斷事務(wù),如上圖:

  • 協(xié)調(diào)者向所有參與者發(fā)出回滾請(qǐng)求(即 rollback 請(qǐng)求)。
  • 參與者使用階段 1 中的 undo 信息執(zhí)行回滾操作,并釋放整個(gè)事務(wù)期間占用的資源。
  • 各參與者向協(xié)調(diào)者反饋 ack 完成的消息。
  • 協(xié)調(diào)者收到所有參與者反饋的 ack 消息后,即完成事務(wù)中斷。

方案總結(jié)

2PC 方案實(shí)現(xiàn)起來(lái)簡(jiǎn)單,實(shí)際項(xiàng)目中使用比較少,主要因?yàn)橐韵聠?wèn)題:

  • 性能問(wèn)題:所有參與者在事務(wù)提交階段處于同步阻塞狀態(tài),占用系統(tǒng)資源,容易導(dǎo)致性能瓶頸。
  • 可靠性問(wèn)題:如果協(xié)調(diào)者存在單點(diǎn)故障問(wèn)題,如果協(xié)調(diào)者出現(xiàn)故障,參與者將一直處于鎖定狀態(tài)。
  • 數(shù)據(jù)一致性問(wèn)題:在階段 2 中,如果發(fā)生局部網(wǎng)絡(luò)問(wèn)題,一部分事務(wù)參與者收到了提交消息,另一部分事務(wù)參與者沒(méi)收到提交消息,那么就導(dǎo)致了節(jié)點(diǎn)之間數(shù)據(jù)的不一致。

3PC(三階段提交)方案

方案簡(jiǎn)介

三階段提交協(xié)議,是二階段提交協(xié)議的改進(jìn)版本,與二階段提交不同的是,引入超時(shí)機(jī)制。同時(shí)在協(xié)調(diào)者和參與者中都引入超時(shí)機(jī)制。

三階段提交將二階段的準(zhǔn)備階段拆分為 2 個(gè)階段,插入了一個(gè) preCommit 階段,使得原先在二階段提交中,參與者在準(zhǔn)備之后,由于協(xié)調(diào)者發(fā)生崩潰或錯(cuò)誤,而導(dǎo)致參與者處于無(wú)法知曉是否提交或者中止的“不確定狀態(tài)”所產(chǎn)生的可能相當(dāng)長(zhǎng)的延時(shí)的問(wèn)題得以解決。

處理流程

階段 1:canCommit

協(xié)調(diào)者向參與者發(fā)送 commit 請(qǐng)求,參與者如果可以提交就返回 yes 響應(yīng)(參與者不執(zhí)行事務(wù)操作),否則返回 no 響應(yīng):

  • 協(xié)調(diào)者向所有參與者發(fā)出包含事務(wù)內(nèi)容的 canCommit 請(qǐng)求,詢(xún)問(wèn)是否可以提交事務(wù),并等待所有參與者答復(fù)。
  • 參與者收到 canCommit 請(qǐng)求后,如果認(rèn)為可以執(zhí)行事務(wù)操作,則反饋 yes 并進(jìn)入預(yù)備狀態(tài),否則反饋 no。

階段 2:preCommit

協(xié)調(diào)者根據(jù)階段 1 canCommit 參與者的反應(yīng)情況來(lái)決定是否可以進(jìn)行基于事務(wù)的 preCommit 操作。根據(jù)響應(yīng)情況,有以下兩種可能。

還不理解“分布式事務(wù)”?這篇給你講清楚!

情況 1:階段 1 所有參與者均反饋 yes,參與者預(yù)執(zhí)行事務(wù),如上圖:

  • 協(xié)調(diào)者向所有參與者發(fā)出 preCommit 請(qǐng)求,進(jìn)入準(zhǔn)備階段。
  • 參與者收到 preCommit 請(qǐng)求后,執(zhí)行事務(wù)操作,將 undo 和 redo 信息記入事務(wù)日志中(但不提交事務(wù))。
  • 各參與者向協(xié)調(diào)者反饋 ack 響應(yīng)或 no 響應(yīng),并等待最終指令。

還不理解“分布式事務(wù)”?這篇給你講清楚!

情況 2:階段 1 任何一個(gè)參與者反饋 no,或者等待超時(shí)后協(xié)調(diào)者尚無(wú)法收到所有參與者的反饋,即中斷事務(wù),如上圖:

  • 協(xié)調(diào)者向所有參與者發(fā)出 abort 請(qǐng)求。
  • 無(wú)論收到協(xié)調(diào)者發(fā)出的 abort 請(qǐng)求,或者在等待協(xié)調(diào)者請(qǐng)求過(guò)程中出現(xiàn)超時(shí),參與者均會(huì)中斷事務(wù)。

階段 3:do Commit

該階段進(jìn)行真正的事務(wù)提交,也可以分為以下兩種情況。

還不理解“分布式事務(wù)”?這篇給你講清楚!還不理解“分布式事務(wù)”?這篇給你講清楚!

情況 1:階段 2 所有參與者均反饋 ack 響應(yīng),執(zhí)行真正的事務(wù)提交,如上圖:

  • 如果協(xié)調(diào)者處于工作狀態(tài),則向所有參與者發(fā)出 do Commit 請(qǐng)求。
  • 參與者收到 do Commit 請(qǐng)求后,會(huì)正式執(zhí)行事務(wù)提交,并釋放整個(gè)事務(wù)期間占用的資源。
  • 各參與者向協(xié)調(diào)者反饋 ack 完成的消息。
  • 協(xié)調(diào)者收到所有參與者反饋的 ack 消息后,即完成事務(wù)提交。

還不理解“分布式事務(wù)”?這篇給你講清楚! 還不理解“分布式事務(wù)”?這篇給你講清楚!

情況 2:階段 2 任何一個(gè)參與者反饋 no,或者等待超時(shí)后協(xié)調(diào)者尚無(wú)法收到所有參與者的反饋,即中斷事務(wù),如上圖:

  • 如果協(xié)調(diào)者處于工作狀態(tài),向所有參與者發(fā)出 abort 請(qǐng)求。
  • 參與者使用階段 1 中的 undo 信息執(zhí)行回滾操作,并釋放整個(gè)事務(wù)期間占用的資源。
  • 各參與者向協(xié)調(diào)者反饋 ack 完成的消息。
  • 協(xié)調(diào)者收到所有參與者反饋的 ack 消息后,即完成事務(wù)中斷。

注意:進(jìn)入階段 3 后,無(wú)論協(xié)調(diào)者出現(xiàn)問(wèn)題,或者協(xié)調(diào)者與參與者網(wǎng)絡(luò)出現(xiàn)問(wèn)題,都會(huì)導(dǎo)致參與者無(wú)法接收到協(xié)調(diào)者發(fā)出的 do Commit 請(qǐng)求或 abort 請(qǐng)求。此時(shí),參與者都會(huì)在等待超時(shí)之后,繼續(xù)執(zhí)行事務(wù)提交。

方案總結(jié)

優(yōu)點(diǎn):相比二階段提交,三階段提交降低了阻塞范圍,在等待超時(shí)后協(xié)調(diào)者或參與者會(huì)中斷事務(wù)。避免了協(xié)調(diào)者單點(diǎn)問(wèn)題,階段 3 中協(xié)調(diào)者出現(xiàn)問(wèn)題時(shí),參與者會(huì)繼續(xù)提交事務(wù)。

缺點(diǎn):數(shù)據(jù)不一致問(wèn)題依然存在,當(dāng)在參與者收到 preCommit 請(qǐng)求后等待 do commite 指令時(shí),此時(shí)如果協(xié)調(diào)者請(qǐng)求中斷事務(wù),而協(xié)調(diào)者無(wú)法與參與者正常通信,會(huì)導(dǎo)致參與者繼續(xù)提交事務(wù),造成數(shù)據(jù)不一致。

TCC 事務(wù):最終一致性

方案簡(jiǎn)介

TCC(Try-Confirm-Cancel)的概念,最早是由 Pat Helland 于 2007 年發(fā)表的一篇名為《Life beyond Distributed Transactions:an Apostate’s Opinion》的論文提出。

TCC 是服務(wù)化的二階段編程模型,其 Try、Confirm、Cancel 3 個(gè)方法均由業(yè)務(wù)編碼實(shí)現(xiàn):

  • Try 操作作為一階段,負(fù)責(zé)資源的檢查和預(yù)留。
  • Confirm 操作作為二階段提交操作,執(zhí)行真正的業(yè)務(wù)。
  • Cancel 是預(yù)留資源的取消。

TCC 事務(wù)的 Try、Confirm、Cancel 可以理解為 SQL 事務(wù)中的 Lock、Commit、Rollback。

處理流程

為了方便理解,下面以電商下單為例進(jìn)行方案解析,這里把整個(gè)過(guò)程簡(jiǎn)單分為扣減庫(kù)存,訂單創(chuàng)建 2 個(gè)步驟,庫(kù)存服務(wù)和訂單服務(wù)分別在不同的服務(wù)器節(jié)點(diǎn)上。

①Try 階段

從執(zhí)行階段來(lái)看,與傳統(tǒng)事務(wù)機(jī)制中業(yè)務(wù)邏輯相同。但從業(yè)務(wù)角度來(lái)看,卻不一樣。

TCC 機(jī)制中的 Try 僅是一個(gè)初步操作,它和后續(xù)的確認(rèn)一起才能真正構(gòu)成一個(gè)完整的業(yè)務(wù)邏輯,這個(gè)階段主要完成:

  • 完成所有業(yè)務(wù)檢查( 一致性 ) 。
  • 預(yù)留必須業(yè)務(wù)資源( 準(zhǔn)隔離性 ) 。
  • Try 嘗試執(zhí)行業(yè)務(wù)。

TCC 事務(wù)機(jī)制以初步操作(Try)為中心的,確認(rèn)操作(Confirm)和取消操作(Cancel)都是圍繞初步操作(Try)而展開(kāi)。

因此,Try 階段中的操作,其保障性是***的,即使失敗,仍然有取消操作(Cancel)可以將其執(zhí)行結(jié)果撤銷(xiāo)。

還不理解“分布式事務(wù)”?這篇給你講清楚!

假設(shè)商品庫(kù)存為 100,購(gòu)買(mǎi)數(shù)量為 2,這里檢查和更新庫(kù)存的同時(shí),凍結(jié)用戶購(gòu)買(mǎi)數(shù)量的庫(kù)存,同時(shí)創(chuàng)建訂單,訂單狀態(tài)為待確認(rèn)。

②Confirm / Cancel 階段

根據(jù) Try 階段服務(wù)是否全部正常執(zhí)行,繼續(xù)執(zhí)行確認(rèn)操作(Confirm)或取消操作(Cancel)。

Confirm 和 Cancel 操作滿足冪等性,如果 Confirm 或 Cancel 操作執(zhí)行失敗,將會(huì)不斷重試直到執(zhí)行完成。

Confirm:當(dāng) Try 階段服務(wù)全部正常執(zhí)行, 執(zhí)行確認(rèn)業(yè)務(wù)邏輯操作

還不理解“分布式事務(wù)”?這篇給你講清楚!

這里使用的資源一定是 Try 階段預(yù)留的業(yè)務(wù)資源。在 TCC 事務(wù)機(jī)制中認(rèn)為,如果在 Try 階段能正常的預(yù)留資源,那 Confirm 一定能完整正確的提交。

Confirm 階段也可以看成是對(duì) Try 階段的一個(gè)補(bǔ)充,Try+Confirm 一起組成了一個(gè)完整的業(yè)務(wù)邏輯。

Cancel:當(dāng) Try 階段存在服務(wù)執(zhí)行失敗, 進(jìn)入 Cancel 階段

還不理解“分布式事務(wù)”?這篇給你講清楚!

Cancel 取消執(zhí)行,釋放 Try 階段預(yù)留的業(yè)務(wù)資源,上面的例子中,Cancel 操作會(huì)把凍結(jié)的庫(kù)存釋放,并更新訂單狀態(tài)為取消。

方案總結(jié)

TCC 事務(wù)機(jī)制相對(duì)于傳統(tǒng)事務(wù)機(jī)制(X/Open XA),TCC 事務(wù)機(jī)制相比于上面介紹的 XA 事務(wù)機(jī)制,有以下優(yōu)點(diǎn):

  • 性能提升:具體業(yè)務(wù)來(lái)實(shí)現(xiàn)控制資源鎖的粒度變小,不會(huì)鎖定整個(gè)資源。
  • 數(shù)據(jù)最終一致性:基于 Confirm 和 Cancel 的冪等性,保證事務(wù)最終完成確認(rèn)或者取消,保證數(shù)據(jù)的一致性。
  • 可靠性:解決了 XA 協(xié)議的協(xié)調(diào)者單點(diǎn)故障問(wèn)題,由主業(yè)務(wù)方發(fā)起并控制整個(gè)業(yè)務(wù)活動(dòng),業(yè)務(wù)活動(dòng)管理器也變成多點(diǎn),引入集群。

缺點(diǎn): TCC 的 Try、Confirm 和 Cancel 操作功能要按具體業(yè)務(wù)來(lái)實(shí)現(xiàn),業(yè)務(wù)耦合度較高,提高了開(kāi)發(fā)成本。

本地消息表:最終一致性

方案簡(jiǎn)介

本地消息表的方案最初是由 eBay 提出,核心思路是將分布式事務(wù)拆分成本地事務(wù)進(jìn)行處理。

方案通過(guò)在事務(wù)主動(dòng)發(fā)起方額外新建事務(wù)消息表,事務(wù)發(fā)起方處理業(yè)務(wù)和記錄事務(wù)消息在本地事務(wù)中完成,輪詢(xún)事務(wù)消息表的數(shù)據(jù)發(fā)送事務(wù)消息,事務(wù)被動(dòng)方基于消息中間件消費(fèi)事務(wù)消息表中的事務(wù)。

這樣設(shè)計(jì)可以避免”業(yè)務(wù)處理成功 + 事務(wù)消息發(fā)送失敗",或"業(yè)務(wù)處理失敗 + 事務(wù)消息發(fā)送成功"的棘手情況出現(xiàn),保證 2 個(gè)系統(tǒng)事務(wù)的數(shù)據(jù)一致性。

處理流程

下面把分布式事務(wù)***開(kāi)始處理的事務(wù)方稱(chēng)為事務(wù)主動(dòng)方,在事務(wù)主動(dòng)方之后處理的業(yè)務(wù)內(nèi)的其他事務(wù)稱(chēng)為事務(wù)被動(dòng)方。

為了方便理解,下面繼續(xù)以電商下單為例進(jìn)行方案解析,這里把整個(gè)過(guò)程簡(jiǎn)單分為扣減庫(kù)存,訂單創(chuàng)建 2 個(gè)步驟。

庫(kù)存服務(wù)和訂單服務(wù)分別在不同的服務(wù)器節(jié)點(diǎn)上,其中庫(kù)存服務(wù)是事務(wù)主動(dòng)方,訂單服務(wù)是事務(wù)被動(dòng)方。

事務(wù)的主動(dòng)方需要額外新建事務(wù)消息表,用于記錄分布式事務(wù)的消息的發(fā)生、處理狀態(tài)。

整個(gè)業(yè)務(wù)處理流程如下:

還不理解“分布式事務(wù)”?這篇給你講清楚!

步驟1:事務(wù)主動(dòng)方處理本地事務(wù)。

事務(wù)主動(dòng)方在本地事務(wù)中處理業(yè)務(wù)更新操作和寫(xiě)消息表操作。上面例子中庫(kù)存服務(wù)階段在本地事務(wù)中完成扣減庫(kù)存和寫(xiě)消息表(圖中 1、2)。

步驟 2:事務(wù)主動(dòng)方通過(guò)消息中間件,通知事務(wù)被動(dòng)方處理事務(wù)通知事務(wù)待消息。

消息中間件可以基于 Kafka、RocketMQ 消息隊(duì)列,事務(wù)主動(dòng)方主動(dòng)寫(xiě)消息到消息隊(duì)列,事務(wù)消費(fèi)方消費(fèi)并處理消息隊(duì)列中的消息。

上面例子中,庫(kù)存服務(wù)把事務(wù)待處理消息寫(xiě)到消息中間件,訂單服務(wù)消費(fèi)消息中間件的消息,完成新增訂單(圖中 3 - 5)。

步驟 3:事務(wù)被動(dòng)方通過(guò)消息中間件,通知事務(wù)主動(dòng)方事務(wù)已處理的消息。

上面例子中,訂單服務(wù)把事務(wù)已處理消息寫(xiě)到消息中間件,庫(kù)存服務(wù)消費(fèi)中間件的消息,并將事務(wù)消息的狀態(tài)更新為已完成(圖中 6 - 8)。

為了數(shù)據(jù)的一致性,當(dāng)處理錯(cuò)誤需要重試,事務(wù)發(fā)送方和事務(wù)接收方相關(guān)業(yè)務(wù)處理需要支持冪等。

具體保存一致性的容錯(cuò)處理如下:

  1. 當(dāng)步驟 1 處理出錯(cuò),事務(wù)回滾,相當(dāng)于什么都沒(méi)發(fā)生。
  2. 當(dāng)步驟 2、步驟 3 處理出錯(cuò),由于未處理的事務(wù)消息還是保存在事務(wù)發(fā)送方,事務(wù)發(fā)送方可以定時(shí)輪詢(xún)?yōu)槌瑫r(shí)消息數(shù)據(jù),再次發(fā)送到消息中間件進(jìn)行處理。事務(wù)被動(dòng)方消費(fèi)事務(wù)消息重試處理。
  3. 如果是業(yè)務(wù)上的失敗,事務(wù)被動(dòng)方可以發(fā)消息給事務(wù)主動(dòng)方進(jìn)行回滾。
  4. 如果多個(gè)事務(wù)被動(dòng)方已經(jīng)消費(fèi)消息,事務(wù)主動(dòng)方需要回滾事務(wù)時(shí)需要通知事務(wù)被動(dòng)方回滾。

方案總結(jié)

方案的優(yōu)點(diǎn)如下:

  • 從應(yīng)用設(shè)計(jì)開(kāi)發(fā)的角度實(shí)現(xiàn)了消息數(shù)據(jù)的可靠性,消息數(shù)據(jù)的可靠性不依賴(lài)于消息中間件,弱化了對(duì) MQ 中間件特性的依賴(lài)。
  • 方案輕量,容易實(shí)現(xiàn)。

缺點(diǎn)如下:

  • 與具體的業(yè)務(wù)場(chǎng)景綁定,耦合性強(qiáng),不可公用。
  • 消息數(shù)據(jù)與業(yè)務(wù)數(shù)據(jù)同庫(kù),占用業(yè)務(wù)系統(tǒng)資源。
  • 業(yè)務(wù)系統(tǒng)在使用關(guān)系型數(shù)據(jù)庫(kù)的情況下,消息服務(wù)性能會(huì)受到關(guān)系型數(shù)據(jù)庫(kù)并發(fā)性能的局限。

MQ 事務(wù):最終一致性

方案簡(jiǎn)介

基于 MQ 的分布式事務(wù)方案其實(shí)是對(duì)本地消息表的封裝,將本地消息表基于 MQ 內(nèi)部,其他方面的協(xié)議基本與本地消息表一致。

處理流程

下面主要基于 RocketMQ 4.3 之后的版本介紹 MQ 的分布式事務(wù)方案。

在本地消息表方案中,保證事務(wù)主動(dòng)方發(fā)寫(xiě)業(yè)務(wù)表數(shù)據(jù)和寫(xiě)消息表數(shù)據(jù)的一致性是基于數(shù)據(jù)庫(kù)事務(wù),RocketMQ 的事務(wù)消息相對(duì)于普通 MQ,相對(duì)于提供了 2PC 的提交接口,方案如下:

正常情況:事務(wù)主動(dòng)方發(fā)消息

還不理解“分布式事務(wù)”?這篇給你講清楚!

這種情況下,事務(wù)主動(dòng)方服務(wù)正常,沒(méi)有發(fā)生故障,發(fā)消息流程如下:

  • 圖中 1:發(fā)送方向 MQ 服務(wù)端(MQ Server)發(fā)送 half 消息。
  • 圖中 2:MQ Server 將消息持久化成功之后,向發(fā)送方 ack 確認(rèn)消息已經(jīng)發(fā)送成功。
  • 圖中 3:發(fā)送方開(kāi)始執(zhí)行本地事務(wù)邏輯。
  • 圖中 4:發(fā)送方根據(jù)本地事務(wù)執(zhí)行結(jié)果向 MQ Server 提交二次確認(rèn)(commit 或是 rollback)。
  • 圖中 5:MQ Server 收到 commit 狀態(tài)則將半消息標(biāo)記為可投遞,訂閱方最終將收到該消息;MQ Server 收到 rollback 狀態(tài)則刪除半消息,訂閱方將不會(huì)接受該消息。

異常情況:事務(wù)主動(dòng)方消息恢復(fù)

還不理解“分布式事務(wù)”?這篇給你講清楚!

在斷網(wǎng)或者應(yīng)用重啟等異常情況下,圖中 4 提交的二次確認(rèn)超時(shí)未到達(dá) MQ Server,此時(shí)處理邏輯如下:

  • 圖中 5:MQ Server 對(duì)該消息發(fā)起消息回查。
  • 圖中 6:發(fā)送方收到消息回查后,需要檢查對(duì)應(yīng)消息的本地事務(wù)執(zhí)行的最終結(jié)果。
  • 圖中 7:發(fā)送方根據(jù)檢查得到的本地事務(wù)的最終狀態(tài)再次提交二次確認(rèn)。
  • 圖中 8:MQ Server基于 commit/rollback 對(duì)消息進(jìn)行投遞或者刪除。

介紹完 RocketMQ 的事務(wù)消息方案后,由于前面已經(jīng)介紹過(guò)本地消息表方案,這里就簡(jiǎn)單介紹 RocketMQ 分布式事務(wù):

還不理解“分布式事務(wù)”?這篇給你講清楚!

事務(wù)主動(dòng)方基于 MQ 通信通知事務(wù)被動(dòng)方處理事務(wù),事務(wù)被動(dòng)方基于 MQ 返回處理結(jié)果。

如果事務(wù)被動(dòng)方消費(fèi)消息異常,需要不斷重試,業(yè)務(wù)處理邏輯需要保證冪等。

如果是事務(wù)被動(dòng)方業(yè)務(wù)上的處理失敗,可以通過(guò) MQ 通知事務(wù)主動(dòng)方進(jìn)行補(bǔ)償或者事務(wù)回滾。

方案總結(jié)

相比本地消息表方案,MQ 事務(wù)方案優(yōu)點(diǎn)是:

  • 消息數(shù)據(jù)獨(dú)立存儲(chǔ) ,降低業(yè)務(wù)系統(tǒng)與消息系統(tǒng)之間的耦合。
  • 吞吐量由于使用本地消息表方案。

缺點(diǎn)是:

  • 一次消息發(fā)送需要兩次網(wǎng)絡(luò)請(qǐng)求(half 消息 + commit/rollback 消息) 。
  • 業(yè)務(wù)處理服務(wù)需要實(shí)現(xiàn)消息狀態(tài)回查接口。

Saga 事務(wù):最終一致性

方案簡(jiǎn)介

Saga 事務(wù)源于 1987 年普林斯頓大學(xué)的 Hecto 和 Kenneth 發(fā)表的如何處理 long lived transaction(長(zhǎng)活事務(wù))論文。

Saga 事務(wù)核心思想是將長(zhǎng)事務(wù)拆分為多個(gè)本地短事務(wù),由 Saga 事務(wù)協(xié)調(diào)器協(xié)調(diào),如果正常結(jié)束那就正常完成,如果某個(gè)步驟失敗,則根據(jù)相反順序一次調(diào)用補(bǔ)償操作。

處理流程

Saga 事務(wù)基本協(xié)議如下:

  • 每個(gè) Saga 事務(wù)由一系列冪等的有序子事務(wù)(sub-transaction) Ti 組成。
  • 每個(gè) Ti 都有對(duì)應(yīng)的冪等補(bǔ)償動(dòng)作 Ci,補(bǔ)償動(dòng)作用于撤銷(xiāo) Ti 造成的結(jié)果。

可以看到,和 TCC 相比,Saga 沒(méi)有“預(yù)留”動(dòng)作,它的 Ti 就是直接提交到庫(kù)。

下面以下單流程為例,整個(gè)操作包括:創(chuàng)建訂單、扣減庫(kù)存、支付、增加積分。

還不理解“分布式事務(wù)”?這篇給你講清楚!

Saga 的執(zhí)行順序有兩種,如上圖:

  • 事務(wù)正常執(zhí)行完成:T1, T2, T3, ..., Tn,例如:扣減庫(kù)存(T1),創(chuàng)建訂單(T2),支付(T3),依次有序完成整個(gè)事務(wù)。
  • 事務(wù)回滾:T1, T2, ..., Tj, Cj,..., C2, C1,其中 0 < j < n,例如:扣減庫(kù)存(T1),創(chuàng)建訂單(T2),支付(T3,支付失敗),支付回滾(C3),訂單回滾(C2),恢復(fù)庫(kù)存(C1)。

Saga 定義了兩種恢復(fù)策略:

還不理解“分布式事務(wù)”?這篇給你講清楚!

向前恢復(fù)(forward recovery):對(duì)應(yīng)于上面***種執(zhí)行順序,適用于必須要成功的場(chǎng)景,發(fā)生失敗進(jìn)行重試,執(zhí)行順序是類(lèi)似于這樣的:T1, T2, ..., Tj(失敗), Tj(重試),..., Tn,其中j是發(fā)生錯(cuò)誤的子事務(wù)(sub-transaction)。該情況下不需要Ci。

還不理解“分布式事務(wù)”?這篇給你講清楚!

向后恢復(fù)(backward recovery):對(duì)應(yīng)于上面提到的第二種執(zhí)行順序,其中 j 是發(fā)生錯(cuò)誤的子事務(wù)(sub-transaction),這種做法的效果是撤銷(xiāo)掉之前所有成功的子事務(wù),使得整個(gè) Saga 的執(zhí)行結(jié)果撤銷(xiāo)。

Saga 事務(wù)常見(jiàn)的有兩種不同的實(shí)現(xiàn)方式:

①命令協(xié)調(diào)(Order Orchestrator):中央?yún)f(xié)調(diào)器負(fù)責(zé)集中處理事件的決策和業(yè)務(wù)邏輯排序。

中央?yún)f(xié)調(diào)器(Orchestrator,簡(jiǎn)稱(chēng) OSO)以命令/回復(fù)的方式與每項(xiàng)服務(wù)進(jìn)行通信,全權(quán)負(fù)責(zé)告訴每個(gè)參與者該做什么以及什么時(shí)候該做什么。

還不理解“分布式事務(wù)”?這篇給你講清楚!

以電商訂單的例子為例:

  • 事務(wù)發(fā)起方的主業(yè)務(wù)邏輯請(qǐng)求 OSO 服務(wù)開(kāi)啟訂單事務(wù)
  • OSO 向庫(kù)存服務(wù)請(qǐng)求扣減庫(kù)存,庫(kù)存服務(wù)回復(fù)處理結(jié)果。
  • OSO 向訂單服務(wù)請(qǐng)求創(chuàng)建訂單,訂單服務(wù)回復(fù)創(chuàng)建結(jié)果。
  • OSO 向支付服務(wù)請(qǐng)求支付,支付服務(wù)回復(fù)處理結(jié)果。
  • 主業(yè)務(wù)邏輯接收并處理 OSO 事務(wù)處理結(jié)果回復(fù)。

中央?yún)f(xié)調(diào)器必須事先知道執(zhí)行整個(gè)訂單事務(wù)所需的流程(例如通過(guò)讀取配置)。如果有任何失敗,它還負(fù)責(zé)通過(guò)向每個(gè)參與者發(fā)送命令來(lái)撤銷(xiāo)之前的操作來(lái)協(xié)調(diào)分布式的回滾。

基于中央?yún)f(xié)調(diào)器協(xié)調(diào)一切時(shí),回滾要容易得多,因?yàn)閰f(xié)調(diào)器默認(rèn)是執(zhí)行正向流程,回滾時(shí)只要執(zhí)行反向流程即可。

②事件編排(Event Choreography0):沒(méi)有中央?yún)f(xié)調(diào)器(沒(méi)有單點(diǎn)風(fēng)險(xiǎn))時(shí),每個(gè)服務(wù)產(chǎn)生并觀察其他服務(wù)的事件,并決定是否應(yīng)采取行動(dòng)。

在事件編排方法中,***個(gè)服務(wù)執(zhí)行一個(gè)事務(wù),然后發(fā)布一個(gè)事件。該事件被一個(gè)或多個(gè)服務(wù)進(jìn)行監(jiān)聽(tīng),這些服務(wù)再執(zhí)行本地事務(wù)并發(fā)布(或不發(fā)布)新的事件。

當(dāng)***一個(gè)服務(wù)執(zhí)行本地事務(wù)并且不發(fā)布任何事件時(shí),意味著分布式事務(wù)結(jié)束,或者它發(fā)布的事件沒(méi)有被任何 Saga 參與者聽(tīng)到都意味著事務(wù)結(jié)束。

還不理解“分布式事務(wù)”?這篇給你講清楚!

以電商訂單的例子為例:

事務(wù)發(fā)起方的主業(yè)務(wù)邏輯發(fā)布開(kāi)始訂單事件。

  • 庫(kù)存服務(wù)監(jiān)聽(tīng)開(kāi)始訂單事件,扣減庫(kù)存,并發(fā)布庫(kù)存已扣減事件。
  • 訂單服務(wù)監(jiān)聽(tīng)?zhēng)齑嬉芽蹨p事件,創(chuàng)建訂單,并發(fā)布訂單已創(chuàng)建事件。
  • 支付服務(wù)監(jiān)聽(tīng)訂單已創(chuàng)建事件,進(jìn)行支付,并發(fā)布訂單已支付事件。
  • 主業(yè)務(wù)邏輯監(jiān)聽(tīng)訂單已支付事件并處理。

事件/編排是實(shí)現(xiàn) Saga 模式的自然方式,它很簡(jiǎn)單,容易理解,不需要太多的代碼來(lái)構(gòu)建。如果事務(wù)涉及 2 至 4 個(gè)步驟,則可能是非常合適的。

方案總結(jié)

命令協(xié)調(diào)設(shè)計(jì)的優(yōu)點(diǎn)如下:

  • 服務(wù)之間關(guān)系簡(jiǎn)單,避免服務(wù)之間的循環(huán)依賴(lài)關(guān)系,因?yàn)?Saga 協(xié)調(diào)器會(huì)調(diào)用 Saga 參與者,但參與者不會(huì)調(diào)用協(xié)調(diào)器。
  • 程序開(kāi)發(fā)簡(jiǎn)單,只需要執(zhí)行命令/回復(fù)(其實(shí)回復(fù)消息也是一種事件消息),降低參與者的復(fù)雜性。
  • 易維護(hù)擴(kuò)展,在添加新步驟時(shí),事務(wù)復(fù)雜性保持線性,回滾更容易管理,更容易實(shí)施和測(cè)試。

命令協(xié)調(diào)設(shè)計(jì)缺點(diǎn)如下:

  • 中央?yún)f(xié)調(diào)器容易處理邏輯容易過(guò)于復(fù)雜,導(dǎo)致難以維護(hù)。
  • 存在協(xié)調(diào)器單點(diǎn)故障風(fēng)險(xiǎn)。

事件/編排設(shè)計(jì)優(yōu)點(diǎn)如下:

  • 避免中央?yún)f(xié)調(diào)器單點(diǎn)故障風(fēng)險(xiǎn)。
  • 當(dāng)涉及的步驟較少服務(wù)開(kāi)發(fā)簡(jiǎn)單,容易實(shí)現(xiàn)。

事件/編排設(shè)計(jì)缺點(diǎn)如下:

  • 服務(wù)之間存在循環(huán)依賴(lài)的風(fēng)險(xiǎn)。
  • 當(dāng)涉及的步驟較多,服務(wù)間關(guān)系混亂,難以追蹤調(diào)測(cè)。

值得補(bǔ)充的是,由于 Saga 模型中沒(méi)有 Prepare 階段,因此事務(wù)間不能保證隔離性。

當(dāng)多個(gè) Saga 事務(wù)操作同一資源時(shí),就會(huì)產(chǎn)生更新丟失、臟數(shù)據(jù)讀取等問(wèn)題,這時(shí)需要在業(yè)務(wù)層控制并發(fā),例如:在應(yīng)用層面加鎖,或者應(yīng)用層面預(yù)先凍結(jié)資源。

五、總結(jié)

各方案使用場(chǎng)景

還不理解“分布式事務(wù)”?這篇給你講清楚!

介紹完分布式事務(wù)相關(guān)理論和常見(jiàn)解決方案后,最終的目的在實(shí)際項(xiàng)目中運(yùn)用,因此,總結(jié)一下各個(gè)方案的常見(jiàn)的使用場(chǎng)景:

  • 2PC/3PC:依賴(lài)于數(shù)據(jù)庫(kù),能夠很好的提供強(qiáng)一致性和強(qiáng)事務(wù)性,但相對(duì)來(lái)說(shuō)延遲比較高,比較適合傳統(tǒng)的單體應(yīng)用,在同一個(gè)方法中存在跨庫(kù)操作的情況,不適合高并發(fā)和高性能要求的場(chǎng)景。
  • TCC:適用于執(zhí)行時(shí)間確定且較短,實(shí)時(shí)性要求高,對(duì)數(shù)據(jù)一致性要求高,比如互聯(lián)網(wǎng)金融企業(yè)最核心的三個(gè)服務(wù):交易、支付、賬務(wù)。
  • 本地消息表/MQ 事務(wù):都適用于事務(wù)中參與方支持操作冪等,對(duì)一致性要求不高,業(yè)務(wù)上能容忍數(shù)據(jù)不一致到一個(gè)人工檢查周期,事務(wù)涉及的參與方、參與環(huán)節(jié)較少,業(yè)務(wù)上有對(duì)賬/校驗(yàn)系統(tǒng)兜底。
  • Saga 事務(wù):由于 Saga 事務(wù)不能保證隔離性,需要在業(yè)務(wù)層控制并發(fā),適合于業(yè)務(wù)場(chǎng)景事務(wù)并發(fā)操作同一資源較少的情況。

Saga 相比缺少預(yù)提交動(dòng)作,導(dǎo)致補(bǔ)償動(dòng)作的實(shí)現(xiàn)比較麻煩,例如業(yè)務(wù)是發(fā)送短信,補(bǔ)償動(dòng)作則得再發(fā)送一次短信說(shuō)明撤銷(xiāo),用戶體驗(yàn)比較差。Saga 事務(wù)較適用于補(bǔ)償動(dòng)作容易處理的場(chǎng)景。

分布式事務(wù)方案設(shè)計(jì)

本文介紹的偏向于原理,業(yè)界已經(jīng)有不少開(kāi)源的或者收費(fèi)的解決方案,篇幅所限,就不再展開(kāi)介紹。

實(shí)際運(yùn)用理論時(shí)進(jìn)行架構(gòu)設(shè)計(jì)時(shí),許多人容易犯“手里有了錘子,看什么都覺(jué)得像釘子”的錯(cuò)誤,設(shè)計(jì)方案時(shí)考慮的問(wèn)題場(chǎng)景過(guò)多,各種重試,各種補(bǔ)償機(jī)制引入系統(tǒng),導(dǎo)致系統(tǒng)過(guò)于復(fù)雜,落地遙遙無(wú)期。

  • 世界上解決一個(gè)計(jì)算機(jī)問(wèn)題最簡(jiǎn)單的方法:“恰好”不需要解決它!

—— 阿里中間件技術(shù)專(zhuān)家沈詢(xún)

有些問(wèn)題,看起來(lái)很重要,但實(shí)際上我們可以通過(guò)合理的設(shè)計(jì)或者將問(wèn)題分解來(lái)規(guī)避。

設(shè)計(jì)分布式事務(wù)系統(tǒng)也不是需要考慮所有異常情況,不必過(guò)度設(shè)計(jì)各種回滾,補(bǔ)償機(jī)制。

如果硬要把時(shí)間花在解決問(wèn)題本身,實(shí)際上不僅效率低下,而且也是一種浪費(fèi)。

如果系統(tǒng)要實(shí)現(xiàn)回滾流程的話,有可能系統(tǒng)復(fù)雜度將大大提升,且很容易出現(xiàn) Bug,估計(jì)出現(xiàn) Bug 的概率會(huì)比需要事務(wù)回滾的概率大很多。

在設(shè)計(jì)系統(tǒng)時(shí),我們需要衡量是否值得花這么大的代價(jià)來(lái)解決這樣一個(gè)出現(xiàn)概率非常小的問(wèn)題,可以考慮當(dāng)出現(xiàn)這個(gè)概率很小的問(wèn)題,能否采用人工解決的方式,這也是大家在解決疑難問(wèn)題時(shí)需要多多思考的地方。

參考資料:

  • technology-talk —— 事務(wù)
  • MySQL 中事務(wù)的實(shí)現(xiàn)
  • 分布式一致性算法 2PC 和 3PC
  • 分布式開(kāi)放消息系統(tǒng)(RocketMQ)的原理與實(shí)踐
  • RocketMQ 事務(wù)消息入門(mén)介紹
  • Saga 分布式事務(wù)解決方案與實(shí)踐 —— 姜寧
  • 分布式事務(wù) Saga 模式
  • 從一筆金幣充值去思考分布式事務(wù) 

關(guān)于作者,陳彩華(caison),從事服務(wù)端開(kāi)發(fā),善于系統(tǒng)設(shè)計(jì)、優(yōu)化重構(gòu)、線上問(wèn)題排查工作,主要開(kāi)發(fā)語(yǔ)言是 Java,微信號(hào):hua1881375。

【51CTO原創(chuàng)稿件,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文作者和出處為51CTO.com】

還不理解“分布式事務(wù)”?這篇給你講清楚!

責(zé)任編輯:未麗燕 來(lái)源: 51CTO技術(shù)棧
相關(guān)推薦

2019-01-31 09:20:36

架構(gòu)容錯(cuò)架構(gòu)分布式容錯(cuò)

2021-07-07 10:28:09

分布式架構(gòu)系統(tǒng)

2019-04-26 14:12:19

MySQL數(shù)據(jù)庫(kù)隔離級(jí)別

2020-11-10 09:17:03

Redis

2024-04-08 08:40:32

RBACJenkins配置

2022-07-20 06:55:10

TCC分布式事務(wù)微服務(wù)

2022-11-24 17:34:04

TCC分布式

2020-07-29 09:21:34

Docker集群部署隔離環(huán)境

2021-07-05 22:22:24

協(xié)議MQTT

2020-07-29 10:04:36

Kubernetes容器

2024-02-19 00:00:00

后管系統(tǒng)權(quán)限

2019-10-21 08:51:41

分布式事務(wù)CAPAP

2019-07-07 08:18:10

MySQL索引數(shù)據(jù)庫(kù)

2022-01-05 09:27:24

讀擴(kuò)散寫(xiě)擴(kuò)散feed

2022-06-27 08:21:05

Seata分布式事務(wù)微服務(wù)

2021-10-29 11:30:31

補(bǔ)碼二進(jìn)制反碼

2010-09-26 09:26:20

2021-08-20 16:13:40

機(jī)器學(xué)習(xí)人工智能計(jì)算機(jī)

2022-06-21 08:27:22

Seata分布式事務(wù)

2024-06-28 09:07:19

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)