![](http://image109.360doc.com/DownloadImg/2020/05/2810/191526531_1_20200528103719800)
阿里妹導(dǎo)讀:分布式事務(wù)中涉及的參與者分布在異步網(wǎng)絡(luò)中,,參與者通過(guò)網(wǎng)絡(luò)通信來(lái)達(dá)到分布式一致性,網(wǎng)絡(luò)通信不可避免出現(xiàn)失敗,、超時(shí)的情況,,因此分布式事務(wù)的實(shí)現(xiàn)比本地事務(wù)面臨更多的困難。本文歸納總結(jié)五種分布式事務(wù)解決方案,,并剖析其特點(diǎn),。較長(zhǎng),同學(xué)們可收藏后再看,。 文末福利:Java 程序員學(xué)習(xí)清單,。 事務(wù)是一組不可分組的操作集合,這些操作要么都成功執(zhí)行,,要么都取消執(zhí)行,。最典型的需要事務(wù)的場(chǎng)景是銀行賬戶間的轉(zhuǎn)賬:假如 A 賬戶要給 B 賬戶轉(zhuǎn)賬 100 元,,那么 A 賬戶要扣減 100 元,B 賬戶要增加 100 元,,這兩個(gè)賬戶的數(shù)據(jù)變更都成功才可算作轉(zhuǎn)賬成功,。更嚴(yán)格來(lái)說(shuō),可以用 ACID 四個(gè)特性表述事務(wù):Atomicity:原子性,,事務(wù)中的所有操作要么都成功執(zhí)行,,要么都取消執(zhí)行,不能存在部分執(zhí)行,,部分不執(zhí)行的狀態(tài),。
Consistency:一致性,舉個(gè)例子簡(jiǎn)單的理解就是,,A,、B 兩個(gè)賬戶各有 100 元,無(wú)論兩個(gè)賬戶并發(fā)相互轉(zhuǎn)賬多少次,,兩個(gè)賬戶的資金總額依然是 200 元,。 單體數(shù)據(jù)庫(kù)不涉及網(wǎng)絡(luò)交互,,所以在多表之間實(shí)現(xiàn)事務(wù)是比較簡(jiǎn)單的,,這種事務(wù)我們稱之為本地事務(wù)。但是單體數(shù)據(jù)庫(kù)的性能達(dá)到瓶頸的時(shí)候,,就需要分庫(kù)(分物理實(shí)例),,就會(huì)出現(xiàn)跨庫(kù)(數(shù)據(jù)庫(kù)實(shí)例)的事務(wù)需求;隨著企業(yè)應(yīng)用的規(guī)模越來(lái)越大,,企業(yè)會(huì)進(jìn)一步進(jìn)行服務(wù)化改造,,以滿足業(yè)務(wù)增長(zhǎng)的需求;當(dāng)前微服務(wù)架構(gòu)越來(lái)越流行,,跨服務(wù)的事務(wù)場(chǎng)景也會(huì)越來(lái)越多,。這些都是分布式事務(wù)的需求。分布式事務(wù)是指是指事務(wù)的發(fā)起者,、參與者、數(shù)據(jù)資源服務(wù)器以及事務(wù)管理器分別位于分布式系統(tǒng)的不同節(jié)點(diǎn)之上,。概括起來(lái),,分布式事務(wù)有三種場(chǎng)景:![](http://image109.360doc.com/DownloadImg/2020/05/2810/191526531_2_20200528103719972) 分布式事務(wù)中涉及的參與者分布在異步網(wǎng)絡(luò)中,,參與者通過(guò)網(wǎng)絡(luò)通信來(lái)達(dá)到分布式一致性,網(wǎng)絡(luò)通信不可避免出現(xiàn)失敗,、超時(shí)的情況,,因此分布式事務(wù)的實(shí)現(xiàn)比本地事務(wù)面臨更多的困難。下面介紹幾種常見(jiàn)的分布式事務(wù)解決方案,。最早的分布式事務(wù)產(chǎn)品可能是 AT&T 在 20 世紀(jì) 80 年代推出的 Tuxedo (Transactions for Unix, Extended for Distributed Operations),,Tuxedo 最早是為了電信領(lǐng)域的 OLTP 系統(tǒng)研發(fā)的分布式事務(wù)中間件,后來(lái)標(biāo)準(zhǔn)化組織 X/Open 吸收采納了 Tuxedo 的設(shè)計(jì)思想和一些接口,,推出了分布式事務(wù)規(guī)范:XA Specification,。XA 規(guī)范中定義了分布式事務(wù)處理模型,這個(gè)模型中包含四個(gè)核心角色:RM (Resource Managers):資源管理器,,提供數(shù)據(jù)資源的操作,、管理接口,保證數(shù)據(jù)的一致性和完整性,。最有代表性的就是數(shù)據(jù)庫(kù)管理系統(tǒng),,當(dāng)然有的文件系統(tǒng)、MQ 系統(tǒng)也可以看作 RM,。
AP (Application Program):應(yīng)用程序,,按照業(yè)務(wù)規(guī)則調(diào)用 RM 接口來(lái)完成對(duì)業(yè)務(wù)模型數(shù)據(jù)的變更,當(dāng)數(shù)據(jù)的變更涉及多個(gè) RM 且要保證事務(wù)時(shí),,AP 就會(huì)通過(guò) TM 來(lái)定義事務(wù)的邊界,,TM 負(fù)責(zé)協(xié)調(diào)參與事務(wù)的各個(gè) RM 一同完成一個(gè)全局事務(wù)。 下圖是 XA 規(guī)范中定義的事務(wù)模型圖,,其中:發(fā)起分布式事務(wù)的 TM 實(shí)例稱之為 root 節(jié)點(diǎn),其他的 TM 實(shí)例可以統(tǒng)稱為事務(wù)的參與者,。事務(wù)發(fā)起者負(fù)責(zé)開(kāi)啟整個(gè)全局事務(wù),,事務(wù)參與者各自負(fù)責(zé)執(zhí)行自己的事務(wù)分支。如果TM實(shí)例發(fā)起了對(duì)其他 TM 實(shí)例的服務(wù)調(diào)用,,那么發(fā)起者就被成為 Superior,,被調(diào)用這就被稱之為 Subordinate 節(jié)點(diǎn)。![](http://image109.360doc.com/DownloadImg/2020/05/2810/191526531_3_2020052810372066) 圖源:《Distributed Transaction Processing:Reference Model, Version 3》 Page 32,Figure 3-2XA 規(guī)范中分布式事務(wù)是構(gòu)建在 RM 本地事務(wù)(此時(shí)本地事務(wù)被看作分支事務(wù))的基礎(chǔ)上的,,TM 負(fù)責(zé)協(xié)調(diào)這些分支事務(wù)要么都成功提交,、要么都回滾。XA 規(guī)范把分布式事務(wù)處理過(guò)程劃分為兩個(gè)階段,,所以又叫兩階段提交協(xié)議(two phrase commit):TM 記錄事務(wù)開(kāi)始日志,,并詢問(wèn)各個(gè) RM 是否可以執(zhí)行提交準(zhǔn)備操作,。 RM 收到指令后,評(píng)估自己的狀態(tài),,嘗試執(zhí)行本地事務(wù)的預(yù)備操作:預(yù)留資源,,為資源加鎖、執(zhí)行操作等,,但是并不提交事務(wù),,并等待 TM 的后續(xù)指令。如果嘗試失敗則告知 TM 本階段執(zhí)行失敗并且回滾自己的操作,,然后不再參與本次事務(wù)(以 MySQL 為例,,這個(gè)階段會(huì)完成資源的加鎖,redo log 和 undo log 的寫入),。TM 收集 RM 的響應(yīng),,記錄事務(wù)準(zhǔn)備完成日志。這個(gè)階段根據(jù)上個(gè)階段的協(xié)調(diào)結(jié)果發(fā)起事務(wù)的提交或者回滾操作,。如果所有 RM 在上一個(gè)步驟都返回執(zhí)行成功,,那么:如果有 RM 在上一個(gè)步驟中返回執(zhí)行失敗或者超時(shí)沒(méi)有應(yīng)答,,則 TM 按照?qǐng)?zhí)行失敗處理,那么:![](http://image109.360doc.com/DownloadImg/2020/05/2810/191526531_4_20200528103720238) 針對(duì)部分場(chǎng)景,XA 規(guī)范還定義了如下優(yōu)化措施:如果 RM 在階段1完成后,長(zhǎng)時(shí)間等不到階段 2 的指令,,那么其可以自動(dòng)提交或者回滾本地事務(wù)。這叫做 Heuristic Completion,,注意這種場(chǎng)景有可能會(huì)破壞事務(wù)的一致性,產(chǎn)生異常,。 XA 規(guī)范中詳細(xì)定義了各個(gè)核心組件之間的交互接口,,以 TM 和 RM 的交互接口為例,如下圖,,一次完整的全局事務(wù),,TM 和 RM 之間的交互還是比較頻繁的:![](http://image109.360doc.com/DownloadImg/2020/05/2810/191526531_5_20200528103720425) 事務(wù)的執(zhí)行過(guò)程中,宕機(jī)和網(wǎng)絡(luò)超時(shí)都有可能發(fā)生,針對(duì)這些異常場(chǎng)景,,不同 XA 規(guī)范的實(shí)現(xiàn),對(duì)異常處理做法可能不同,可參考如下:XA 兩階段提交協(xié)議設(shè)計(jì)上是要像本地事務(wù)一樣實(shí)現(xiàn)事務(wù)的 ACID 四個(gè)特性:XA 是出現(xiàn)最早的分布式事務(wù)規(guī)范,,主流數(shù)據(jù)庫(kù) Oracle,、MySQL、SQLServer 等都支持 XA 規(guī)范,,J2EE 中的 JTA 規(guī)范也是參照 XA 規(guī)范編寫的,,與 XA 規(guī)范兼容。XA 是在資源管理層面實(shí)現(xiàn)的分布式事務(wù)模型,,對(duì)業(yè)務(wù)的入侵度較低,。XA 兩階段提交協(xié)議可以覆蓋分布式事務(wù)的三種場(chǎng)景,,但是全局事務(wù)的執(zhí)行過(guò)程中,RM 一直持有資源的鎖,,如果參與的 RM 過(guò)多,,尤其是跨服務(wù)的場(chǎng)景下,網(wǎng)絡(luò)通信的次數(shù)和時(shí)間會(huì)急劇變多,,所以阻塞的時(shí)間更長(zhǎng),,系統(tǒng)的吞吐能力變得很差,事務(wù)死鎖出現(xiàn)的概率也會(huì)變大,,所以并不適合微服務(wù)架構(gòu)場(chǎng)景中的跨服務(wù)的分布式事務(wù)模式,。每一個(gè) TM 域來(lái)說(shuō),由于 TM 是單點(diǎn),,存在單點(diǎn)故障風(fēng)險(xiǎn),,如果 TM 在階段1之后掛掉,會(huì)導(dǎo)致參與的 RM 長(zhǎng)時(shí)間收不到階段 2 的請(qǐng)求而長(zhǎng)期持有資源的鎖,,影響業(yè)務(wù)的吞吐能力,。同時(shí)一次完整的全局事務(wù),TM 和 RM 之間的交互多達(dá) 8 次,,太繁瑣,非常影響系統(tǒng)的處理性能,。XA 兩階段協(xié)議可能會(huì)造成腦裂的異常,,假如 TM 在階段 2 通知 RM 提交事務(wù)時(shí),如果指令發(fā)出后就宕機(jī)了,,而只有部分 RM 收到了提交請(qǐng)求,,那么當(dāng) TM 恢復(fù)的時(shí)候,就無(wú)法協(xié)調(diào)本次事務(wù)所有的 RM 本地事務(wù)的一致性了,。XA 要處理的異常場(chǎng)景非常多,,對(duì)框架的實(shí)現(xiàn)有一定的挑戰(zhàn),開(kāi)源的實(shí)現(xiàn),,可以參考:Atomikos,,Bitronix。針對(duì) XA 兩階段提交中的問(wèn)題,,有人提出了三階段提交的改進(jìn)方案,,三階段提交方案主要解決了單點(diǎn)故障問(wèn)題,并在 RM 側(cè)也引入了超時(shí)機(jī)制,,以避免資源的長(zhǎng)時(shí)間鎖定,。但是三階段提交方案依然無(wú)法避免腦裂的異常情況出現(xiàn),實(shí)際應(yīng)用案例很少,,感興趣的同學(xué)可以自行找相關(guān)資料了解,。TCC (Try,、Commit、Cancel) 是一種補(bǔ)償型事務(wù),,該模型要求應(yīng)用的每個(gè)服務(wù)提供 try,、confirm、cancel 三個(gè)接口,,它的核心思想是通過(guò)對(duì)資源的預(yù)留(提供中間態(tài)),,盡早釋放對(duì)資源的加鎖,如果事務(wù)可以提交,,則完成對(duì)預(yù)留資源的確認(rèn),,如果事務(wù)要回滾,則釋放預(yù)留的資源,。TCC 也是一種兩階段提交協(xié)議,,可以看作 2PC/XA 的一種變種,,但是不會(huì)長(zhǎng)時(shí)間持有資源鎖。TCC 模型將事務(wù)的提交劃分為兩個(gè)階段:完成業(yè)務(wù)檢查(一致性),、預(yù)留業(yè)務(wù)資源(準(zhǔn)隔離性),,即 TCC 中的 try,。如果 try 階段所有業(yè)務(wù)資源都預(yù)留成功,則執(zhí)行 confirm 操作,,否則執(zhí)行 cancel 操作:![](http://image109.360doc.com/DownloadImg/2020/05/2810/191526531_6_20200528103720597) TCC 模式中,,事務(wù)的發(fā)起者和參與者都需要記錄事務(wù)日志,事務(wù)的發(fā)起者需要記錄全局事務(wù)和各個(gè)分支事務(wù)的狀態(tài)和信息,;事務(wù)的參與者需要記錄分支事務(wù)的狀態(tài),。TCC 事務(wù)在執(zhí)行過(guò)程中的任意環(huán)節(jié),均可能發(fā)生宕機(jī),、重啟,、網(wǎng)絡(luò)中斷等異常情況,此時(shí)事務(wù)處于非原子狀態(tài)和非最終一致?tīng)顟B(tài),,此時(shí)就需要根據(jù)主事務(wù)記錄和分支事務(wù)記錄的日志,,去完成剩余分支事務(wù)的提交或者回滾,使整個(gè)分布式事務(wù)內(nèi)所有參展達(dá)到最終一致的狀態(tài),,實(shí)現(xiàn)事務(wù)的原子性,。我們以一個(gè)簡(jiǎn)單的電商系統(tǒng)為例,,小明在淘寶上花 100 元買了一本書,獲贈(zèng) 10 個(gè)積分,,產(chǎn)品上有如下幾個(gè)操作:這幾個(gè)動(dòng)作需要作為一個(gè)事務(wù)執(zhí)行,,要同時(shí)成功或者同時(shí)撤銷。如果采用 TCC 事務(wù)模式,,那么各個(gè)系統(tǒng)需要改造為如下?tīng)顟B(tài):try:創(chuàng)建一個(gè)訂單,,狀態(tài)顯示為“待支付” confirm:更新訂單的狀態(tài)為“已完成” cancel:更新訂單的狀態(tài)為“已取消”
try:假設(shè)小明賬戶中有 1000 元,凍結(jié)小明賬戶中的 100 元,,此時(shí)小明看到的余額依然是 1000 元,。 confirm:將賬戶余額變?yōu)?900 元,并清除凍結(jié)記錄,。 concel:清除凍結(jié)記錄,。
try:假設(shè)庫(kù)存中還生 10 本書,凍結(jié)其中的一本書,,現(xiàn)實(shí)庫(kù)存依然有 10 本書,。 confirm:將剩余庫(kù)存更新為 9 本書,并清除凍結(jié)記錄,。 cancel:清除凍結(jié)記錄,。
try:假設(shè)小明原因積分 3000 分,給小明賬戶預(yù)增加 10 積分,,賬戶顯示的積分依然是 3000 分,。 confirm:將賬戶積分更新為 3010,并清除預(yù)增加記錄,。 cancel:清除預(yù)增加記錄。 TCC 事務(wù)具備事務(wù)的四個(gè)特性:原子性:事務(wù)發(fā)起方協(xié)調(diào)各個(gè)分支事務(wù)全部提交或者全部回滾,。 一致性:TCC 事務(wù)提供最終一致性,。 隔離型:通過(guò) try 預(yù)分配資源的方式來(lái)實(shí)現(xiàn)數(shù)據(jù)的隔離。 持久性:交由各個(gè)分支事務(wù)來(lái)實(shí)現(xiàn),。 TCC 事務(wù)模型對(duì)業(yè)務(wù)方侵入較大,,需要業(yè)務(wù)方把功能的實(shí)現(xiàn)上由一個(gè)接口拆分為三個(gè),開(kāi)發(fā)成本較高,。同時(shí) TCC 事務(wù)為了解決異步網(wǎng)絡(luò)中的通信失敗或超時(shí)帶來(lái)的異常情況,,要求業(yè)務(wù)方在設(shè)計(jì)實(shí)現(xiàn)上要遵循三個(gè)策略:保持冪等性:原因是異常發(fā)生在階段 2 時(shí),,比如網(wǎng)絡(luò)超時(shí),,則會(huì)重復(fù)調(diào)用參與方的 confirm/cancel 方法,,因此需要這兩個(gè)方法實(shí)現(xiàn)上保證冪等性。
防止資源懸掛:原因網(wǎng)絡(luò)異常導(dǎo)致兩個(gè)階段無(wú)法保證嚴(yán)格的順序執(zhí)行,,出現(xiàn)參與方側(cè) try 請(qǐng)求比 cancel 請(qǐng)求更晚到達(dá)的情況,,cancel 會(huì)執(zhí)行空回滾而確保事務(wù)的正確性,但是此時(shí) try 方法也不可以再被執(zhí)行,。 TCC 事務(wù)將分布式事務(wù)從資源層提到業(yè)務(wù)層來(lái)實(shí)現(xiàn),,可以讓業(yè)務(wù)靈活選擇資源的鎖定粒度,并且全局事務(wù)執(zhí)行過(guò)程中不會(huì)一直持有鎖,,所以系統(tǒng)的吞吐量比 2PC/XA 模式要高很多,。支持 TCC 事務(wù)的開(kāi)源框架有:ByteTCC、Himly,、TCC-transaction,。Saga 并不是一個(gè)新概念,其相關(guān)論文在 1987 年就發(fā)布了,,和 XA 兩階段提交規(guī)范出現(xiàn)的時(shí)間差不多,。Saga 和 TCC 一樣,也是一種補(bǔ)償事務(wù),,但是它沒(méi)有 try 階段,,而是把分布式事務(wù)看作一組本地事務(wù)構(gòu)成的事務(wù)鏈。事務(wù)鏈中的每一個(gè)正向事務(wù)操作,,都對(duì)應(yīng)一個(gè)可逆的事務(wù)操作,。Saga 事務(wù)協(xié)調(diào)器負(fù)責(zé)按照順序執(zhí)行事務(wù)鏈中的分支事務(wù),分支事務(wù)執(zhí)行完畢,,即釋放資源,。如果某個(gè)分支事務(wù)失敗了,則按照反方向執(zhí)行事務(wù)補(bǔ)償操作,。假如一個(gè) Saga 的分布式事務(wù)鏈有 n 個(gè)分支事務(wù)構(gòu)成,,[T1,T2,...,Tn],那么該分布式事務(wù)的執(zhí)行情況有三種:T1,T2,...,Tn:n 個(gè)事務(wù)全部執(zhí)行成功了,。
T1,T2,...,Ti,Ci,...,C2,C1:執(zhí)行到第 i (i<=n) 個(gè)事務(wù)的時(shí)候失敗了,,則按照 i->1 的順序依次調(diào)用補(bǔ)償操作。如果補(bǔ)償失敗了,,就一直重試,。補(bǔ)償操作可以優(yōu)化為并行執(zhí)行。
T1,T2,...,Ti (失敗),Ti (重試),Ti (重試),...,Tn:適用于事務(wù)必須成功的場(chǎng)景,,如果發(fā)生失敗了就一直重試,,不會(huì)執(zhí)行補(bǔ)償操作。
![](http://image109.360doc.com/DownloadImg/2020/05/2810/191526531_7_20200528103720800) 假如國(guó)慶節(jié)小明要出去玩,,從北京出發(fā),,先去倫敦,,在倫敦游玩三天,再去巴黎,,在巴黎游玩三天,,然后再返回北京。整個(gè)行程中涉及不同航空公司的機(jī)票預(yù)訂以及倫敦和巴黎當(dāng)?shù)氐木频觐A(yù)訂,,小明的計(jì)劃是如果任何一張機(jī)票或酒店預(yù)訂不上,,就取消本次出行計(jì)劃。假如綜合旅游出行服務(wù)平臺(tái)提供這種一鍵下單的功能,,那么這就是一個(gè)長(zhǎng)事務(wù),,用 Saga 模式編排服務(wù)的話,就如下圖所示:任何一個(gè)環(huán)節(jié)失敗的話,,就通過(guò)補(bǔ)償操作取消前面的行程預(yù)訂,。![](http://image109.360doc.com/DownloadImg/2020/05/2810/191526531_8_20200528103720957) Saga 事務(wù)是可以保障事務(wù)的三個(gè)特性:但是 Saga 不保證事務(wù)隔離性的,,本地事務(wù)提交后變更就對(duì)其他事務(wù)可見(jiàn)了。其他事務(wù)如果更改了已經(jīng)提交成功的數(shù)據(jù),,可能會(huì)導(dǎo)致補(bǔ)償操作失敗,。比如扣款失敗,但是錢已經(jīng)花掉了,,業(yè)務(wù)設(shè)計(jì)上需要考慮這種場(chǎng)景并從業(yè)務(wù)設(shè)計(jì)上規(guī)避這種問(wèn)題,。Saga 事務(wù)和 TCC 事務(wù)一樣,對(duì)業(yè)務(wù)實(shí)現(xiàn)要求高,,要求業(yè)務(wù)設(shè)計(jì)實(shí)現(xiàn)上遵循三個(gè)策略:雖然 Saga 和 TCC 都是補(bǔ)償事務(wù),,但是由于提交階段不同,所以兩者也是有不同的:Saga 模式非常適合于業(yè)務(wù)流程長(zhǎng)的長(zhǎng)事務(wù)的場(chǎng)景,,實(shí)現(xiàn)上對(duì)業(yè)務(wù)侵入低,所以非常適合微服務(wù)架構(gòu)的場(chǎng)景,。同時(shí) Saga 采用的是一階段提交模式,,不會(huì)對(duì)資源長(zhǎng)時(shí)間加鎖,不存在“木桶效應(yīng)”,,所以采用這種模式架構(gòu)的系統(tǒng)性能高,、吞吐高。阿里巴巴的 Seata 開(kāi)源項(xiàng)目和華為的 ServiceComb 開(kāi)源項(xiàng)目都支持 Saga 模式,。基于消息的分布式事務(wù)模式核心思想是通過(guò)消息系統(tǒng)來(lái)通知其他事務(wù)參與方自己事務(wù)的執(zhí)行狀態(tài),。消息系統(tǒng)的引入更有效的將事務(wù)參與方解耦,各個(gè)參與方可以異步執(zhí)行,。該種模式的難點(diǎn)在于解決本地事務(wù)執(zhí)行和消息發(fā)送的一致性:兩者要同時(shí)執(zhí)行成功或者同時(shí)取消執(zhí)行,。普通消息是無(wú)法解決本地事務(wù)執(zhí)行和消息發(fā)送的一致性問(wèn)題的。因?yàn)橄l(fā)送是一個(gè)網(wǎng)絡(luò)通信的過(guò)程,,發(fā)送消息的過(guò)程就有可能出現(xiàn)發(fā)送失敗,、或者超時(shí)的情況。超時(shí)有可能發(fā)送成功了,,有可能發(fā)送失敗了,,消息的發(fā)送方是無(wú)法確定的,所以此時(shí)消息發(fā)送方無(wú)論是提交事務(wù)還是回滾事務(wù),,都有可能不一致性出現(xiàn),。解決這個(gè)問(wèn)題,需要引入事務(wù)消息,,事務(wù)消息和普通消息的區(qū)別在于事務(wù)消息發(fā)送成功后,,處于 prepared 狀態(tài),不能被訂閱者消費(fèi),,等到事務(wù)消息的狀態(tài)更改為可消費(fèi)狀態(tài)后,,下游訂閱者才可以監(jiān)聽(tīng)到次消息。本地事務(wù)和事務(wù)消息的發(fā)送的處理流程如下:事務(wù)發(fā)起者如果沒(méi)有收到 ACK 消息,,則取消本地事務(wù)的執(zhí)行;如果收到了 ACK 消息,,則執(zhí)行本地事務(wù),,并給 MQ 系統(tǒng)再發(fā)送一個(gè)消息,通知本地事務(wù)的執(zhí)行情況,。
MQ 系統(tǒng)收到消息通知后,,根據(jù)本地事務(wù)的執(zhí)行情況更改事務(wù)消息的狀態(tài),如果成功執(zhí)行,,則將消息更改為“可消費(fèi)”并擇機(jī)下發(fā)給訂閱者,;如果事務(wù)執(zhí)行失敗,則刪除該事務(wù)消息,。
本地事務(wù)執(zhí)行完畢后,,發(fā)給 MQ 的通知消息有可能丟失了。所以支持事務(wù)消息的 MQ 系統(tǒng)有一個(gè)定時(shí)掃描邏輯,,掃描出狀態(tài)仍然是“待發(fā)送”狀態(tài)的消息,,并向消息的發(fā)送方發(fā)起詢問(wèn),詢問(wèn)這條事務(wù)消息的最終狀態(tài)如何并根據(jù)結(jié)果更新事務(wù)消息的狀態(tài),。因此事務(wù)的發(fā)起方需要給 MQ 系統(tǒng)提供一個(gè)事務(wù)消息狀態(tài)查詢接口,。
下游參與者收到消息后,執(zhí)行本地事務(wù),,本地事務(wù)如果執(zhí)行成功,,則給 MQ 系統(tǒng)發(fā)送 ACK 消息;如果執(zhí)行失敗,,則不發(fā)送 ACK 消息,,MQ 系統(tǒng)會(huì)持續(xù)推送給消息。
![](http://image109.360doc.com/DownloadImg/2020/05/2810/191526531_9_2020052810372182) 基于事務(wù)消息的模式對(duì) MQ 系統(tǒng)要求較高,,并不是所有 MQ 系統(tǒng)都支持事務(wù)消息的,,RocketMQ 是目前為數(shù)不多的支持事務(wù)小的 MQ 系統(tǒng)。如果所依賴的 MQ 系統(tǒng)不支持事務(wù)消息,,那么可以采用本地消息的分布式模式,。該種模式的核心思想是事務(wù)的發(fā)起方維護(hù)一個(gè)本地消息表,業(yè)務(wù)執(zhí)行和本地消息表的執(zhí)行處在同一個(gè)本地事務(wù)中,。業(yè)務(wù)執(zhí)行成功,,則同時(shí)記錄一條“待發(fā)送”狀態(tài)的消息到本地消息表中。系統(tǒng)中啟動(dòng)一個(gè)定時(shí)任務(wù)定時(shí)掃描本地消息表中狀態(tài)為“待發(fā)送”的記錄,,并將其發(fā)送到 MQ 系統(tǒng)中,,如果發(fā)送失敗或者超時(shí),則一直發(fā)送,,知道發(fā)送成功后,,從本地消息表中刪除該記錄。后續(xù)的消費(fèi)訂閱流程則與基于事務(wù)消息的模式雷同,。![](http://image109.360doc.com/DownloadImg/2020/05/2810/191526531_10_20200528103721207) 基于消息的分布式事務(wù)模式對(duì) ACID 特性的支持如下:基于消息的分布式事務(wù)可以將分布式系統(tǒng)之間更有效的解耦,各個(gè)事務(wù)參與方之間的調(diào)用不再是同步調(diào)用,。對(duì) MQ 系統(tǒng)的要求較高,,對(duì)業(yè)務(wù)實(shí)現(xiàn)也有一定的侵入性,要么提供事務(wù)消息狀態(tài)查詢接口,,要么需要維護(hù)本地消息表,。并且原則上只接受下游分支事務(wù)的成功,不接受事務(wù)的回滾,,如果失敗就要一直重試,,適用于對(duì)最終一致性敏感度較低的業(yè)務(wù)場(chǎng)景,例如跨企業(yè)的系統(tǒng)間的調(diào)用,,適用的場(chǎng)景有限,。最大努力通知型的分布式事務(wù)解決方案,也是基于 MQ 系統(tǒng)的一種解決方案,,但是不要求 MQ 消息可靠,。假設(shè)小明通過(guò)聯(lián)通的網(wǎng)上營(yíng)業(yè)廳為手機(jī)充話費(fèi),充值方式選擇支付寶支付,。整個(gè)操作的流程如下:支付寶驗(yàn)明確認(rèn)小明的支付后,,從小明的賬戶中扣除 50 元,,并向聯(lián)通的賬戶中增加 50 元。執(zhí)行完畢后向 MQ 系統(tǒng)發(fā)送一條消息,,消息的內(nèi)容標(biāo)識(shí)支付是否成功,,消息發(fā)送允許失敗,。
如果消息發(fā)送成功,那么支付寶的通知服務(wù)會(huì)訂閱到該消息,,并調(diào)用聯(lián)通的接口通知本次支付的結(jié)果,。如果此時(shí)聯(lián)通的服務(wù)掛掉了,導(dǎo)致通知失敗了,,則會(huì)按照 5min,、10min、30min,、1h,、...、24h 等遞增的時(shí)間間隔,,間隔性重復(fù)調(diào)用聯(lián)通的接口,,直到調(diào)用成功或者達(dá)到預(yù)訂的時(shí)間窗口上限后,則不再通知,。這就是盡最大努力通知的含義,。
如果聯(lián)通服務(wù)恢復(fù)正常,收到了支付寶的通知,,如果支付成功,,則給賬戶充值;如果支付失敗,,則取消充值,。執(zhí)行完畢后給支付寶通知服務(wù)確認(rèn)響應(yīng),確認(rèn)響應(yīng)允許失敗,,支付寶系統(tǒng)會(huì)繼續(xù)重試,。所以聯(lián)通的充值接口需要保持冪等性。
如果聯(lián)通服務(wù)故障時(shí)間很久,,恢復(fù)正常后,,已超出支付寶通知服務(wù)的時(shí)間窗口,則聯(lián)通掃描“支付中”的訂單,,主動(dòng)向支付寶發(fā)起請(qǐng)求,,核驗(yàn)訂單的支付結(jié)果。 最大努力通知型方案本質(zhì)是通過(guò)引入定期校驗(yàn)機(jī)制來(lái)對(duì)最終一致性做兜底,,對(duì)業(yè)務(wù)侵入性較低,、對(duì) MQ 系統(tǒng)要求較低,實(shí)現(xiàn)比較簡(jiǎn)單,,適合于對(duì)最終一致性敏感度比較低,、業(yè)務(wù)鏈路較短的場(chǎng)景,比如跨平臺(tái),、跨企業(yè)的系統(tǒng)間的業(yè)務(wù)交互,。阿里巴巴有兩個(gè)分布式事務(wù)中間件可選擇:螞蟻金服團(tuán)隊(duì)開(kāi)發(fā)的 XTS,,金融云產(chǎn)品名稱為 DTX。 阿里巴巴中間件團(tuán)隊(duì)開(kāi)發(fā)的 TXC,。 XTS 和 TXC 的功能差不多,,都支持 TCC 事務(wù)模式,也都提供了對(duì)業(yè)務(wù)入侵度較低的分布式事務(wù)方案,,目前這兩個(gè)團(tuán)隊(duì)?wèi)?yīng)該是在共建開(kāi)源版的分布式事務(wù)中間件 Seata。此處我們介紹一下 Seata,。簡(jiǎn)單說(shuō)一下 Seata (Simple Extensible Autonomous Transaction Architecture) 的歷史:Seata 支持 TCC 模式,、Saga 模式,。但是 Seata 對(duì) TCC 模式的支持提供了一種對(duì)業(yè)務(wù)入侵度為0的解決方案,這種方案叫做 AT (Automatic Transaction) 模式,。下面我們重點(diǎn)說(shuō)一下 AT 模式的運(yùn)行機(jī)制:各個(gè)分支事務(wù)在運(yùn)行時(shí),,Seata Client 通過(guò)對(duì) SQL 執(zhí)行的代理和攔截,通過(guò)解析 SQL 定位到行記錄,,記錄下 SQL 執(zhí)行前后的行數(shù)據(jù)快照,,beforeImage 和 afterImage 共同構(gòu)成了回滾日志,回滾日志記錄在獨(dú)立的表中,?;貪L日志的寫入和業(yè)務(wù)數(shù)據(jù)的更改在在同一個(gè)本地事務(wù)中提交。
如果決議是提交事務(wù),,則 Seata Client 異步清理回滾日志,;如果決議是回滾事務(wù),,則 Seata Client 根據(jù)回滾日志進(jìn)行補(bǔ)償操作,補(bǔ)償前會(huì)對(duì)比當(dāng)前數(shù)據(jù)快照和 afterImage 是否一致,,如果不一致則回滾失敗,,需要人工介入。
![](http://pubimage.360doc.com/wz/default.gif) AT 模式通過(guò)自動(dòng)生成回滾日志的方式,,使得業(yè)務(wù)方接入成本低,,對(duì)業(yè)務(wù)入侵度很低,但是應(yīng)用 AT 模式也有一些限制:全局事務(wù)默認(rèn)的隔離級(jí)別是讀未提交,,但是通過(guò) SELECT...FOR UPDATE 等語(yǔ)句,,可以實(shí)現(xiàn)讀已提交的隔離級(jí)別。通過(guò)全局排它寫鎖,,可以做到的隔離級(jí)別介于讀未提交和讀已提交之間,。 單體數(shù)據(jù)庫(kù)事務(wù)很容易滿足事務(wù)的 ACID 四個(gè)特性,提供強(qiáng)一致性保證,,但是分布式事務(wù)要完全遵循 ACID 特性會(huì)比較困難,。為了追求分布式系統(tǒng)的高可用和高吞吐,分布式事務(wù)的解決方案一般提供的是最終一致性,。我們把提供強(qiáng)一致性的事務(wù)稱之為剛性事務(wù),,把提供最終一致性的事務(wù)稱之為柔性事務(wù)。剛性事務(wù)可以完全滿足 ACID 四個(gè)特性,,柔性事務(wù)對(duì)事務(wù)的 ACID 特性的支持情況如下:柔性事務(wù)一般遵循的是分布式領(lǐng)域中的 BASE 理論:BA:Basic Availability,,基本業(yè)務(wù)可用性。 S:Soft state,,柔性狀態(tài),。 E:Eventual consistency,最終一致性,。 BASE 理論,,是對(duì) CAP 理論的延伸,,是對(duì) CAP 中的一致性和可用性進(jìn)行一個(gè)權(quán)衡的結(jié)果,理論的核心思想就是:我們無(wú)法做到強(qiáng)一致,,但每個(gè)應(yīng)用都可以根據(jù)自身的業(yè)務(wù)特點(diǎn),,采用適當(dāng)?shù)姆绞絹?lái)使系統(tǒng)達(dá)到最終一致性。CAP 理論告訴我們一個(gè)分布式系統(tǒng)無(wú)法同時(shí)滿足一致性, 可用性, 分區(qū)容錯(cuò)性,,所以在設(shè)計(jì)上對(duì)這三點(diǎn)做取舍,。剛性事務(wù)追求強(qiáng)一致性,所以犧牲了高可用性,;柔性事務(wù)通過(guò)犧牲一致性換來(lái)了系統(tǒng)的高可用性,。在系統(tǒng)選擇分布式方案時(shí),可以根據(jù)對(duì)一致性的要求進(jìn)行選擇,,業(yè)務(wù)上有強(qiáng)一致性要求的場(chǎng)景時(shí),優(yōu)先考慮 XA 規(guī)范的兩階段提交,;業(yè)務(wù)上只需要最終一致性的場(chǎng)景時(shí),,可以在根據(jù)具體場(chǎng)景在柔性事務(wù)方案中進(jìn)行選擇。參考 [1]分布式事務(wù)中間件TXC(http://mw./product-txc.html) [2]彈力設(shè)計(jì)之補(bǔ)償事務(wù)(https://www.jianshu.com/p/8095001d79bb) [3]分布式事務(wù)中間件ServiceComb (http://servicecomb./cn/docs/distributed-transactions-saga-implementation/) [4]深入理解兩階段提交(https://sq./blog/article/165554812476866560)[5]Seata(https:///zh-cn/) [6]TCC事務(wù)原理 (https://www.cnblogs.com/jajian/p/10014145.html) [7]TCC事務(wù)異常場(chǎng)景(https://blog.csdn.net/dm_vincent/article/details/92432059 [8]Compensating Transaction Pattern (https://docs.microsoft.com/en-us/azure/architecture/patterns/compensating-transaction) [9]基于消息的分布式事務(wù)(https://www.jianshu.com/p/04bad986a4a2) [10]分布式事務(wù)概述(http://www./api/tutorials/distributed_transaction/383) [11]初識(shí)Open/X XA (https://www.jianshu.com/p/6c1fd2420274) [12]DTP: XA Specification (https://pubs./onlinepubs/009680699/toc.pdf) [13]DTP Model (https://pubs./onlinepubs/009249599/toc.pdf)
|