一文看懂分布式事務(wù)

本地事務(wù)

事務(wù)Transaction由一組SQL組成,具有四個(gè)ACID特性。

ACID

1. Atomicity 原子性,構(gòu)成事務(wù)的一組SQL,要么全部生效,要么全不生效,不會(huì)出現(xiàn)部分生效的情況

2. Consistency 一致性,數(shù)據(jù)庫(kù)經(jīng)過(guò)事務(wù)操作后從一種狀態(tài)轉(zhuǎn)變?yōu)榱硪粋€(gè)狀態(tài)??梢哉f(shuō)原子性是從行為上描述,而一致性是從結(jié)果上描述

3. Isolation 隔離性,事務(wù)操作的數(shù)據(jù)對(duì)象 相對(duì)于 其他事務(wù)操作的數(shù)據(jù)對(duì)象相互隔離,互不影響

4. Durability 持久性,事務(wù)提交后,其結(jié)果就是永久性的,即使發(fā)生宕機(jī)(非磁盤(pán)損壞)

事務(wù)實(shí)現(xiàn)

對(duì)于MySQL數(shù)據(jù)庫(kù)(InnoDB存儲(chǔ)引擎)而言,隔離性是通過(guò)不同粒度的鎖機(jī)制來(lái)實(shí)現(xiàn)事務(wù)間的隔離;原子性、一致性和持久性通過(guò)redo log重做日志和undo log回滾日志來(lái)保證的。

1. redo log,當(dāng)數(shù)據(jù)庫(kù)對(duì)數(shù)據(jù)做修改的時(shí)候,需要把數(shù)據(jù)頁(yè)從磁盤(pán)讀到buffer pool中,然后在buffer pool中進(jìn)行修改,那么這個(gè)時(shí)候buffer pool中的數(shù)據(jù)頁(yè)就與磁盤(pán)上的數(shù)據(jù)頁(yè)內(nèi)容不一致,稱(chēng)buffer pool的數(shù)據(jù)頁(yè)為dirty page臟數(shù)據(jù),如果這個(gè)時(shí)候發(fā)生非正常的DB服務(wù)重啟,那么這些數(shù)據(jù)還沒(méi)在內(nèi)存,并沒(méi)有同步到磁盤(pán)文件中(注意,同步到磁盤(pán)文件是個(gè)隨機(jī)IO),也就是會(huì)發(fā)生數(shù)據(jù)丟失,如果這個(gè)時(shí)候,能夠在有一個(gè)文件,當(dāng)buffer pool中的data page變更結(jié)束后,把相應(yīng)修改記錄記錄到這個(gè)文件(注意,記錄日志是順序IO),那么當(dāng)DB服務(wù)發(fā)生crash的情況,恢復(fù)DB的時(shí)候,也可以根據(jù)這個(gè)文件的記錄內(nèi)容,重新應(yīng)用到磁盤(pán)文件,數(shù)據(jù)保持一致。

2. undo log,undo日志用于存放數(shù)據(jù)被修改前的值,如果修改出現(xiàn)異常,可以使用undo日志來(lái)實(shí)現(xiàn)回滾操作,保證事務(wù)的一致性。另外InnoDB MVCC事務(wù)特性也是基于undo日志實(shí)現(xiàn)的。undo日志分為insert undo log(insert語(yǔ)句產(chǎn)生的日志,事務(wù)提交后直接刪除)和update undo log(delete和update語(yǔ)句產(chǎn)生的日志,由于該undo log可能提供MVVC機(jī)制使用,所以不能再事務(wù)提交時(shí)刪除)。

問(wèn)題引入

CAP理論


CAP原則又稱(chēng)CAP定理,指的是在一個(gè)分布式系統(tǒng)中,一致性(Consistency)、可用性(Availability)、分區(qū)容錯(cuò)性(Partition tolerance)。CAP原則指的是,這三個(gè)要素最多只能同時(shí)實(shí)現(xiàn)兩點(diǎn),不可能三者兼顧。但由于在分布式系統(tǒng)中,分區(qū)容錯(cuò)性必然存在,所以只能在一致性和可用性妥協(xié)。

傳統(tǒng)的DBMS,如MySQL其實(shí)CA組合,在主從架構(gòu)下,讀寫(xiě)分離的情況下,是犧牲一定的一致性的(主從延遲)。

Base理論:

1. base available,基本可用,分布式系統(tǒng)在出現(xiàn)故障時(shí),允許損失部分可用功能,保證核心功能可用

2. soft state,軟狀態(tài),允許系統(tǒng)中存在中間狀態(tài),這個(gè)狀態(tài)不影響系統(tǒng)可用性

3. eventually consistent最終一致性,系統(tǒng)的中間狀態(tài)經(jīng)過(guò)短暫的時(shí)間后到達(dá)一致?tīng)顟B(tài)

如何解決

場(chǎng)景舉例

考慮這樣一種業(yè)務(wù)場(chǎng)景,系統(tǒng)A調(diào)用系統(tǒng)B的退款服務(wù)進(jìn)行退款,系統(tǒng)A更改內(nèi)部退款狀態(tài),接著調(diào)用系統(tǒng)C的短信服務(wù)通知用戶(hù)。

在這樣的一個(gè)場(chǎng)景下,由于網(wǎng)絡(luò)不可靠的必然存在,存在A、B、C三個(gè)系統(tǒng)之間一致性的問(wèn)題。

本地表

針對(duì)上述場(chǎng)景,設(shè)計(jì)兩張表:退款記錄表和短信發(fā)送記錄表以及相應(yīng)的補(bǔ)償Job。

具體實(shí)現(xiàn)過(guò)程:

1. 新增退款記錄表,狀態(tài)為處理中

2. 調(diào)用系統(tǒng)B的退款服務(wù)進(jìn)行退款

3. 更新退款記錄狀態(tài)為對(duì)應(yīng)的狀態(tài)(成功/失?。?/p>

4. 如果退款成功,則新增短信發(fā)送記錄,記錄狀態(tài)為待發(fā)送

5. 調(diào)用系統(tǒng)C的短信服務(wù),發(fā)送短信

6. 更新短信發(fā)送記錄為已發(fā)送

? 退款補(bǔ)償Job,查詢(xún)退款記錄表中處理中的記錄,調(diào)用系統(tǒng)B的退款服務(wù),退款成功處理:

1. 新增短信發(fā)送記錄,記錄狀態(tài)為待發(fā)送

2. 調(diào)用系統(tǒng)C的短信服務(wù),發(fā)送短信

3. 更新短信發(fā)送記錄為已發(fā)送

? ?短信通知補(bǔ)償Job,查詢(xún)短信發(fā)送記錄中待發(fā)送的記錄,調(diào)用系統(tǒng)C的短信服務(wù):

1. 調(diào)用系統(tǒng)C的短信服務(wù),發(fā)送短信

2. 更新短信發(fā)送記錄為已發(fā)送

? ?注意:

1. 系統(tǒng)B和系統(tǒng)C需要根據(jù)調(diào)用方傳的uuid支持冪等

2. 系統(tǒng)A、B、C會(huì)出現(xiàn)短暫的不一致,但最終一致

事務(wù)消息

可以將其視為兩階段提交消息實(shí)現(xiàn),以確保分布式系統(tǒng)中的最終一致性。事務(wù)性消息可確保本地事務(wù)的執(zhí)行和消息的發(fā)送可以原子方式執(zhí)行。

但是由于事務(wù)消息異步的特性,調(diào)用方拿不到消費(fèi)方的處理結(jié)果,適用于不關(guān)心對(duì)方的返回結(jié)果/對(duì)方負(fù)責(zé)保證處理成功。

針對(duì)上述場(chǎng)景,增加兩個(gè)事務(wù)消息的方式解決一致性問(wèn)題,系統(tǒng)A通過(guò)發(fā)送事務(wù)消息的方式與系統(tǒng)B和系統(tǒng)C進(jìn)行交互。

? 具體實(shí)現(xiàn)過(guò)程:

1. 發(fā)送退款的事務(wù)消息

2. 新增退款記錄,狀態(tài)為:處理中

3. Commit退款事務(wù)消息

? 提供MQ事務(wù)callback:

1. 退款callback查詢(xún):

? ? ? <1?有退款記錄且為處理中則Commit

? ? ? <2?其他則Rollback

2. 發(fā)送短信callback查詢(xún)

? ? ? <1 有退款記錄且成功則Commit

? ? ? <2 其他則Rollback

退款同步Job,查詢(xún)退款記錄表中處理中的記錄,調(diào)用系統(tǒng)B的退款查詢(xún)接口同步狀態(tài),其中退款成功處理:

? ? 1. 發(fā)送短信的事務(wù)消息

? ? 2. 更新退款記錄為成功

? ??3. Commit短信事務(wù)消息

相關(guān)理論

二階段提交

二階段提交是解決分布式事務(wù)問(wèn)題的重要理論基礎(chǔ),但也存在著明顯的問(wèn)題:

1. 阻塞問(wèn)題,參與者將協(xié)議消息發(fā)送給協(xié)調(diào)器后,它將阻塞直到收到提交或回滾,只能依賴(lài)協(xié)調(diào)者的超時(shí)機(jī)制

2. 協(xié)調(diào)者單點(diǎn)問(wèn)題,如果協(xié)調(diào)者出現(xiàn)故障,則某些參與者將一直無(wú)法收到提交或回滾的消息。

為了解決二階段提交出現(xiàn)的問(wèn)題,又有了三階段提交(Three-phase commit):

1. 解決阻塞問(wèn)題:將2PC中的第一階段一分為二,提供了一個(gè)CanCommit階段,此階段并不鎖定資源,這樣可以大幅降低了阻塞概率

2. 解決單點(diǎn)問(wèn)題:在參與者這邊也引入了超時(shí)機(jī)制

DTP Model

X / Open分布式事務(wù)處理DTP(Distributed Transaction Processing)模型是一種軟件體系架構(gòu),已經(jīng)成為事實(shí)上的事務(wù)模型組件的行為標(biāo)準(zhǔn)。它允許多個(gè)應(yīng)用程序共享由多個(gè)資源管理器提供的資源,并允許其工作被協(xié)調(diào)為全局事務(wù)。

1. ApplicationProgram(AP),應(yīng)用程序定義了事務(wù)邊界并指定構(gòu)成事務(wù)的操作

2. ResourceManager(RM),資源管理器用來(lái)管理我們需要訪問(wèn)的共享資源,我們可以將它理解為關(guān)系數(shù)據(jù)庫(kù)、文件存儲(chǔ)系統(tǒng)、消息隊(duì)列、打印機(jī)等

3. TransactionManagger(TM),事務(wù)管理器是一個(gè)獨(dú)立的組件,他為事務(wù)分配標(biāo)識(shí)符并監(jiān)視事務(wù)的執(zhí)行情況,負(fù)責(zé)事務(wù)完成和故障恢復(fù)

4. CommunicationResourceManager(CRM),通信資源管理器控制一個(gè)或多個(gè) TM domain 之間分布式應(yīng)用的通信。

? XA Specification

? XA規(guī)范是X/Open關(guān)于分布式事務(wù)處理(DTP)的規(guī)范。規(guī)范描述了全局的事務(wù)管理器與局部的資源管理器之間的接口。XA規(guī)范的目的是允許多個(gè)資源(如數(shù)據(jù)庫(kù),應(yīng)用服務(wù)器,消息隊(duì)列,等等)在同一事務(wù)中訪問(wèn),這樣可以使ACID屬性跨越應(yīng)用程序而保持有效。XA使用兩階段提交來(lái)保證所有資源同時(shí)提交或回滾任何特定的事務(wù)。

? XA規(guī)范描述了資源管理器要支持事務(wù)性訪問(wèn)所必需做的事情。

TCC

Saga

在Saga模式下,分布式事務(wù)內(nèi)有多個(gè)參與者,每一個(gè)參與者都是一個(gè)沖正補(bǔ)償服務(wù),需要用戶(hù)根據(jù)業(yè)務(wù)場(chǎng)景實(shí)現(xiàn)其正向操作和逆向回滾操作。

分布式事務(wù)執(zhí)行過(guò)程中,依次執(zhí)行各參與者的正向操作,如果所有正向操作均執(zhí)行成功,那么分布式事務(wù)提交。如果任何一個(gè)正向操作執(zhí)行失敗,那么分布式事務(wù)會(huì)去退回去執(zhí)行前面各參與者的逆向回滾操作,回滾已提交的參與者,使分布式事務(wù)回到初始狀態(tài)。

Saga模式下分布式事務(wù)通常是由事件驅(qū)動(dòng)的,各個(gè)參與者之間是異步執(zhí)行的,Saga模式是一種長(zhǎng)事務(wù)解決方案。

? Saga模式的優(yōu)勢(shì)是:

1. 一階段提交本地?cái)?shù)據(jù)庫(kù)事務(wù),無(wú)鎖,高性能;

2. 參與者可以采用事務(wù)驅(qū)動(dòng)異步執(zhí)行,高吞吐;

3. 補(bǔ)償服務(wù)即正向服務(wù)的“反向”,易于理解,易于實(shí)現(xiàn)。

? 缺點(diǎn):

1. Saga模式由于一階段已經(jīng)提交本地?cái)?shù)據(jù)庫(kù)事務(wù),且沒(méi)有進(jìn)行“預(yù)留”動(dòng)作,所以不能保證隔離性。

開(kāi)源項(xiàng)目

Seata

Seata是一款開(kāi)源的分布式事務(wù)解決方案,致力于在微服務(wù)架構(gòu)下提供高性能和簡(jiǎn)單易用的分布式事務(wù)服務(wù)。支持AT、TCC、SAGA、XA四種模式,對(duì)微服務(wù)框架支持友好。

如上圖所示,Seata中有三大模塊,分別是TM、RM和TC。 其中TM和RM是作為Seata的客戶(hù)端與業(yè)務(wù)系統(tǒng)集成在一起,TC作為Seata的服務(wù)端獨(dú)立部署。

1. TC - 事務(wù)協(xié)調(diào)者,維護(hù)全局和分支事務(wù)的狀態(tài),驅(qū)動(dòng)全局事務(wù)提交或回滾。

2. TM - 事務(wù)管理器,定義全局事務(wù)的范圍:開(kāi)始全局事務(wù)、提交或回滾全局事務(wù)。

3. RM - 資源管理器,管理分支事務(wù)處理的資源,與TC交談以注冊(cè)分支事務(wù)和報(bào)告分支事務(wù)的狀態(tài),并驅(qū)動(dòng)分支事務(wù)提交或回滾。

? 在Seata中,分布式事務(wù)的執(zhí)行流程:

1. TM開(kāi)啟分布式事務(wù)(TM向TC 注冊(cè)全局事務(wù)記錄);

2. 按業(yè)務(wù)場(chǎng)景,編排數(shù)據(jù)庫(kù)、服務(wù)等事務(wù)內(nèi)資源(RM向TC匯報(bào)資源準(zhǔn)備狀態(tài) );

3. TM結(jié)束分布式事務(wù),事務(wù)一階段結(jié)束(TM通知TC提交/回滾分布式事務(wù));

4. TC匯總事務(wù)信息,決定分布式事務(wù)是提交還是回滾;

5. TC通知所有 RM 提交/回滾 資源,事務(wù)二階段結(jié)束。

? AT模式

AT模式是一種無(wú)侵入的分布式事務(wù)解決方案。在AT模式下,用戶(hù)只需關(guān)注自己的“業(yè)務(wù) SQL”,用戶(hù)的 “業(yè)務(wù) SQL” 作為一階段,Seata 框架會(huì)自動(dòng)生成事務(wù)的二階段提交和回滾操作。

1. 一階段:業(yè)務(wù)數(shù)據(jù)和回滾日志記錄在同一個(gè)本地事務(wù)中提交,釋放本地鎖和連接資源。

2. 二階段:提交異步化,非??焖俚赝瓿??;貪L通過(guò)一階段的回滾日志進(jìn)行反向補(bǔ)償。

在一階段,Seata會(huì)攔截“業(yè)務(wù)SQL”,首先解析SQL語(yǔ)義,找到“業(yè)務(wù)SQL”要更新的業(yè)務(wù)數(shù)據(jù),在業(yè)務(wù)數(shù)據(jù)被更新前,將其保存成“before image”,然后執(zhí)行“業(yè)務(wù) SQL”更新業(yè)務(wù)數(shù)據(jù),在業(yè)務(wù)數(shù)據(jù)更新之后,再將其保存成“after image”,最后生成行鎖。以上操作全部在一個(gè)數(shù)據(jù)庫(kù)事務(wù)內(nèi)完成,這樣保證了一階段操作的原子性。

TCC模式?

一個(gè)分布式的全局事務(wù),整體是 兩階段提交 的模型。全局事務(wù)是由若干分支事務(wù)組成的,分支事務(wù)要滿(mǎn)足 兩階段提交 的模型要求,即需要每個(gè)分支事務(wù)都具備自己的:

1. 一階段prepare 行為

2. 二階段commit或rollback行為

? ?TCC 模式,不依賴(lài)于底層數(shù)據(jù)資源的事務(wù)支持:

1. 一階段prepare行為:調(diào)用自定義的prepare邏輯。

2. 二階段commit行為:調(diào)用自定義的commit邏輯。

3. 二階段rollback行為:調(diào)用自定義的rollback邏輯。

? ?所謂 TCC 模式,是指支持把 自定義 的分支事務(wù)納入到全局事務(wù)的管理中。

? ?Saga模式

? ?目前SEATA提供的Saga模式是基于狀態(tài)機(jī)引擎來(lái)實(shí)現(xiàn)的,機(jī)制是:

1. 通過(guò)狀態(tài)圖來(lái)定義服務(wù)調(diào)用的流程并生成json狀態(tài)語(yǔ)言定義文件

2. 狀態(tài)圖中一個(gè)節(jié)點(diǎn)可以是調(diào)用一個(gè)服務(wù),節(jié)點(diǎn)可以配置它的補(bǔ)償節(jié)點(diǎn)

3. 狀態(tài)圖json由狀態(tài)機(jī)引擎驅(qū)動(dòng)執(zhí)行,當(dāng)出現(xiàn)異常時(shí)狀態(tài)引擎反向執(zhí)行已成功節(jié)點(diǎn)對(duì)應(yīng)的補(bǔ)償節(jié)點(diǎn)將事務(wù)回滾 (異常發(fā)生時(shí)是否進(jìn)行補(bǔ)償也可由用戶(hù)自定義決定)

4. 可以實(shí)現(xiàn)服務(wù)編排需求,支持單項(xiàng)選擇、并發(fā)、子流程、參數(shù)轉(zhuǎn)換、參數(shù)映射、服務(wù)執(zhí)行狀態(tài)判斷、異常捕獲等功能

我自己建了個(gè)群,對(duì) JAVA 開(kāi)發(fā)有興趣的朋友歡迎加入QQ群:322708204 進(jìn)行技術(shù)討論,里面資深架構(gòu)師會(huì)分享一些整理好的BATJ面試題:有Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化、分布式架構(gòu)等這些成為架構(gòu)師必備的知識(shí)體系。

狀態(tài)機(jī)引擎原理:

1. 圖中的狀態(tài)圖是先執(zhí)行stateA,再執(zhí)行stateB,然后執(zhí)行stateC

2. "狀態(tài)"的執(zhí)行是基于事件驅(qū)動(dòng)的模型,stateA執(zhí)行完成后,會(huì)產(chǎn)生路由消息放入EventQueue,事件消費(fèi)端從EventQueue取出消息,執(zhí)行stateB

3. 在整個(gè)狀態(tài)機(jī)啟動(dòng)時(shí)會(huì)調(diào)用Seata Server開(kāi)啟分布式事務(wù),并生產(chǎn)xid,然后記錄"狀態(tài)機(jī)實(shí)例"啟動(dòng)事件到本地?cái)?shù)據(jù)庫(kù)

4. 當(dāng)執(zhí)行到一個(gè)"狀態(tài)"時(shí)會(huì)調(diào)用Seata Server注冊(cè)分支事務(wù),并生產(chǎn)branchId,然后記錄"狀態(tài)實(shí)例"開(kāi)始執(zhí)行事件到本地?cái)?shù)據(jù)庫(kù)

5. 當(dāng)一個(gè)"狀態(tài)"執(zhí)行完成后會(huì)記錄"狀態(tài)實(shí)例"執(zhí)行結(jié)束事件到本地?cái)?shù)據(jù)庫(kù),然后調(diào)用Seata Server上報(bào)分支事務(wù)的狀態(tài)

6. 當(dāng)整個(gè)狀態(tài)機(jī)執(zhí)行完成, 會(huì)記錄"狀態(tài)機(jī)實(shí)例"執(zhí)行完成事件到本地?cái)?shù)據(jù)庫(kù),然后調(diào)用Seata Server提交或回滾分布式事務(wù)

原文鏈接:https://juejin.im/post/5e066c9ff265da33b0718f89

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容