本地事務(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ù)