1 背景知識
隨著業(yè)務(wù)的快速發(fā)展、業(yè)務(wù)復(fù)雜度越來越高,幾乎每個公司的系統(tǒng)都會從單體走向分布式,特別是轉(zhuǎn)向微服務(wù)架構(gòu)。
隨之而來就必然遇到分布式事務(wù)這個難題,這篇文章通過 seata 框架總結(jié)了分布式事務(wù)的幾種解決方案
1.1 ACID
關(guān)系型數(shù)據(jù)庫具有解決復(fù)雜事務(wù)場景的能力,關(guān)系型數(shù)據(jù)庫的事務(wù)滿足 ACID 的特性。
Atomicity:原子性(要么都做,要么都不做)
Consistency:一致性(數(shù)據(jù)庫只有一個狀態(tài),不存在未確定狀態(tài))
Isolation:隔離性(事務(wù)之間互不干擾)
Durability:永久性(事務(wù)一旦提交,數(shù)據(jù)庫記錄永久不變)
1.2 CAP
CAP 是指在一個分布式系統(tǒng)下, 包含三個要素:Consistency(一致性)、Availability(可用性)、Partition tolerance(分區(qū)容錯性),并且三者不可得兼。
C:Consistency,一致性,所有數(shù)據(jù)變動都是同步的。
A:Availability,可用性,即在可以接受的時間范圍內(nèi)正確地響應(yīng)用戶請求。
P:Partition tolerance,分區(qū)容錯性,即某節(jié)點或網(wǎng)絡(luò)分區(qū)故障時,系統(tǒng)仍能夠提供滿足一致性和可用性的服務(wù)。
1.3 BASE
BASE 理論主要是解決 CAP 理論中分布式系統(tǒng)的可用性和一致性不可兼得的問題。BASE 理論包含以下三個要素:
BA:Basically Available,基本可用。
S:Soft State,軟狀態(tài),狀態(tài)可以有一段時間不同步。
E:Eventually Consistent,最終一致,最終數(shù)據(jù)是一致的就可以了,而不是時時保持強一致。
2 實現(xiàn)模式
2.1 二段提交
第一階段(準備階段)
TM 通知所有參與事務(wù)的各個 RM,給每個 RM 發(fā)送 prepare 消息。
RM 接收到消息后進入準備階段后,要么直接返回失敗,要么創(chuàng)建并執(zhí)行本地事務(wù),寫本地事務(wù)日志(redo 和 undo 日志),但是不提交(此處只保留最后一步耗時最少的提交操作給第二階段執(zhí)行)。
第二階段(提交 / 回滾階段)
Seata 框架 基于兩階段提交模式,從設(shè)計上我們可以將整體分成三個大模塊,即 TM、RM、TC,具體解釋如下:
TM (Transaction Manager):全局事務(wù)管理器,控制全局事務(wù)邊界,負責(zé)全局事務(wù)開啟、全局提交、全局回滾。
RM (Resource Manager):資源管理器,控制分支事務(wù),負責(zé)分支注冊、狀態(tài)匯報,并接收事務(wù)協(xié)調(diào)器的指令,驅(qū)動分支(本地)事務(wù)的提交和回滾。
TC (Transaction Coordinator):事務(wù)協(xié)調(diào)器,維護全局事務(wù)的運行狀態(tài),負責(zé)協(xié)調(diào)并驅(qū)動全局事務(wù)的提交或回滾。
一個典型的分布式事務(wù)過程:
TM 向 TC 申請開啟一個全局事務(wù),全局事務(wù)創(chuàng)建成功并生成一個全局唯一的 XID。
XID 在微服務(wù)調(diào)用鏈路的上下文中傳播。
RM 向 TC 注冊分支事務(wù),將其納入 XID 對應(yīng)全局事務(wù)的管轄。
TM 向 TC 發(fā)起針對 XID 的全局提交或回滾決議。
TC 調(diào)度 XID 下管轄的全部分支事務(wù)完成提交或回滾請求。
2.2 XA
在 XA 模式下,每一個 XA 事務(wù)都是一個事務(wù)參與者。分布式事務(wù)開啟之后 首先在一階段執(zhí)行 “xa start”、“業(yè)務(wù) SQL”、“xa end” 和 “xa prepare” 完成 XA 事務(wù)的執(zhí)行和預(yù)提交; 二階段如果提交的話就執(zhí)行 “xa commit”,如果是回滾則執(zhí)行 “xa rollback”。這樣便能保證所有 XA 事務(wù)都提交或者都回滾。
無論 Phase2 的決議是 commit 還是 rollback,事務(wù)性資源的鎖都要保持到 Phase2 完成才釋放。
一個正常運行的業(yè)務(wù),大概率是 90% 以上的事務(wù)最終應(yīng)該是成功提交的,我們是否可以在 Phase1 就將本地事務(wù)提交呢?
這樣 90% 以上的情況下,可以省去 Phase2 持鎖的時間,整體提高效率。
分支事務(wù)中數(shù)據(jù)的本地鎖由本地事務(wù)管理,在分支事務(wù) Phase1 結(jié)束時釋放,這時候其他本地事務(wù)就能讀取到最新的數(shù)據(jù)。
- 同時,隨著本地事務(wù)結(jié)束,連接也得以釋放。
- 分支事務(wù)中數(shù)據(jù)的全局鎖在事務(wù)協(xié)調(diào)器管理,在決議 Phase2 全局提交時,全局鎖馬上可以釋放,注意這里是先釋放鎖,再進行分支事務(wù)的提交過程。
只有在決議全局回滾的情況下,全局鎖才被持有至分支的 Phase2 結(jié)束,即所有分支事務(wù)回滾結(jié)束。
這個設(shè)計,極大地減少了分支事務(wù)對資源(數(shù)據(jù)和連接)的鎖定時間,給整體并發(fā)和吞吐的提升提供了基礎(chǔ)。但是分布式事務(wù)的隔離級別變化了
XA 模式和 下面的 AT 模式一樣是一種對業(yè)務(wù)無侵入性的解決方案;但與 AT 模式不同的是,XA 模式將快照數(shù)據(jù)和行鎖等通過 XA 指令委托給了數(shù)據(jù)庫來完成,這樣 XA 模式實現(xiàn)更加輕量化
2.3 AT
AT 模式是一種無侵入的分布式事務(wù)解決方案。在 AT 模式下,用戶只需關(guān)注自己的 “業(yè)務(wù) SQL”,用戶的 “業(yè)務(wù) SQL” 就是全局事務(wù)一階段,Seata 框架會自動生成事務(wù)的二階段提交和回滾操作。
一階段
首先,應(yīng)用要使用 Seata 的 JDBC 數(shù)據(jù)源代理,也就是前面提到的 RM 概念,所有對 DB 的操作都是通過 Seata RM 代理完成。
在這層代理中,Seata 會自動控制 SQL 的執(zhí)行,提交,回滾。
Seata 代理會把業(yè)務(wù)數(shù)據(jù)在更新前后的數(shù)據(jù)鏡像 (beforeImage & afterImage) 組織成回滾日志,利用本地事務(wù)的 ACID 特性,將業(yè)務(wù)數(shù)據(jù)的更新和回滾日志的寫入在同一個本地事務(wù)中提交。
這樣,可以保證:任何提交的業(yè)務(wù)數(shù)據(jù)的更新一定有相應(yīng)的回滾日志存在。
然后,本地事務(wù)在提交之前,還需要通過 RM 向 TC 注冊本地分支,這個注冊過程中會根據(jù)剛才執(zhí)行的 SQL 拿到所有涉及到的數(shù)據(jù)主鍵,以 resourceId + tableName + rowPK 作為鎖的 key,向 TC 申請所有涉及數(shù)據(jù)的寫鎖,當獲得所有相關(guān)數(shù)據(jù)的寫鎖后,再執(zhí)行本地事務(wù)的 Commit 過程。
如果有任何一行數(shù)據(jù)的寫鎖沒有拿到的話,TC 會以 fastfail 的方式回復(fù)該 RM,RM 會以重試 + 超時機制重復(fù)該過程,直到超時。
完成本地事務(wù)后,RM 會向 TC 匯報本地事務(wù)的執(zhí)行情況,并完成業(yè)務(wù) RPC 的調(diào)用過程。
二階段
case1: 如果 TM 決議是全局提交,此時分支事務(wù)實際上已經(jīng)完成提交,TC 立刻釋放該全局事務(wù)的所有鎖,然后異步調(diào)用 RM 清理回滾日志,Phase2 可以非??焖俚赝瓿?。
case2: 如果決議是全局回滾,RM 收到協(xié)調(diào)器發(fā)來的回滾請求,通過 XID 和 Branch ID 找到相應(yīng)的回滾日志記錄,通過回滾記錄生成反向的更新 SQL 并執(zhí)行,以完成分支的回滾。
當分支回滾順利結(jié)束時,通知 TC 回滾完成,這時候 TC 才釋放該分支事務(wù)相關(guān)的所有鎖。
注:RM 在進行回滾時,會先跟 afterImage 進行比較:
- 如果一致:則執(zhí)行逆向 SQL
- 如果不一致:再跟 beforeImage 進行比較
- 如果一致:說明沒必要執(zhí)行回滾 SQL 了,數(shù)據(jù)已經(jīng)恢復(fù)了
- 如果不一致:說明出現(xiàn)了臟數(shù)據(jù),這時候就拋出異常,需要人工處理
2.4 TCC
TCC 模式需要用戶根據(jù)自己的業(yè)務(wù)場景實現(xiàn) Try、Confirm 和 Cancel 三個操作;事務(wù)發(fā)起方先在 TC 中注冊全局事務(wù),然后在一階段執(zhí)行 Try 方法,在二階段提交的話 TC 會去執(zhí)行各個 RM 的 Confirm 方法,二階段回滾則 TC 會去執(zhí)行各個 RM 的 Cancel 方法。
與 AT 模式一樣,Seata 會給實際方法的執(zhí)行加切面,該切面會攔截所有對 TCC 接口的調(diào)用。
在調(diào)用 Try 接口時,如果發(fā)現(xiàn)處在全局事務(wù)中,切面會先向 TC 注冊一個分支事務(wù),和 AT 不同的是 TCC 注冊分支事務(wù)是不加鎖的,注冊完成后去執(zhí)行原來的 RPC 調(diào)用。
當請求鏈路調(diào)用完成后,TC 通過分支事務(wù)的資源 ID 回調(diào)到正確的參與者去執(zhí)行對應(yīng) TCC 資源的 Confirm 或 Cancel 方法。
TCC 模式的整體框架相對于 AT 來說更加簡單,主要是掃描 TCC 接口,注冊資源,攔截接口調(diào)用,注冊分支事務(wù),最后回調(diào)二階段接口。
最核心的實際上是 TCC 接口的實現(xiàn)邏輯。
1)使用原則
從 TCC 模型的框架可以發(fā)現(xiàn),TCC 模型的核心在于 TCC 接口的設(shè)計。用
戶在接入 TCC 時,大部分工作都集中在如何實現(xiàn) TCC 服務(wù)上。
這就是 TCC 模式最主要的問題,對業(yè)務(wù)侵入比較大,要花很大的功夫來實現(xiàn) TCC 服務(wù)。
設(shè)計一套 TCC 接口最重要的是什么?
主要有兩點,第一點,需要將操作分成兩階段完成。TCC(Try-Confirm-Cancel)分布式事務(wù)模型相對于 XA 等傳統(tǒng)模型,其特征在于它不依賴 RM 對分布式事務(wù)的支持,而是通過對業(yè)務(wù)邏輯的分解來實現(xiàn)分布式事務(wù)。
TCC 分布式事務(wù)模型需要業(yè)務(wù)系統(tǒng)提供三段業(yè)務(wù)邏輯:
1. 初步操作 Try:完成所有業(yè)務(wù)檢查,預(yù)留必須的業(yè)務(wù)資源。
2. 確認操作 Confirm:真正執(zhí)行的業(yè)務(wù)邏輯,不做任何業(yè)務(wù)檢查,只使用 Try 階段預(yù)留的業(yè)務(wù)資源。因此,只要 Try 操作成功,Confirm 必須能成功。另外,Confirm 操作需滿足冪等性,保證一筆分布式事務(wù)能且只能成功一次。
3. 取消操作 Cancel:釋放 Try 階段預(yù)留的業(yè)務(wù)資源。同樣的,Cancel 操作也需要滿足冪等性。
因此,TCC 模型的隔離性思想就是通過業(yè)務(wù)的改造,在第一階段結(jié)束之后,從底層數(shù)據(jù)庫資源層面的加鎖過渡為上層業(yè)務(wù)層面的加鎖,釋放底層數(shù)據(jù)庫鎖資源,放寬分布式事務(wù)鎖協(xié)議,將鎖的粒度降到最低,以最大限度提高業(yè)務(wù)并發(fā)性能。
第二點,就是要根據(jù)自身的業(yè)務(wù)模型去控制并發(fā),Seata 框架本身僅提供兩階段原子提交協(xié)議,保證分布式事務(wù)原子性。事務(wù)的隔離需要交給業(yè)務(wù)邏輯來實現(xiàn)。隔離的本質(zhì)就是控制并發(fā),防止并發(fā)事務(wù)操作相同資源而引起的結(jié)果錯亂。例如:“賬戶 A 上有 100 元,事務(wù) T1 要扣除其中的 30 元,事務(wù) T2 也要扣除 30 元,出現(xiàn)并發(fā)”。
在第一階段 Try 操作中,需要先利用數(shù)據(jù)庫資源層面的加鎖,檢查賬戶可用余額,如果余額充足,則預(yù)留業(yè)務(wù)資源加到各自的凍結(jié)里,扣除本次交易金額,一階段結(jié)束后,雖然數(shù)據(jù)庫層面資源鎖被釋放了,但這筆資金被業(yè)務(wù)隔離,不允許除本事務(wù)之外的其它并發(fā)事務(wù)動用。
2)異??刂?/p>
空回滾 空回滾就是對于一個分布式事務(wù),在沒有調(diào)用 TCC 資源 Try 方法的情況下,調(diào)用了二階段的 Cancel 方法,Cancel 方法需要識別出這是一個空回滾,然后直接返回成功。
Cancel 要識別出空回滾,直接返回成功。那關(guān)鍵就是要識別出這個空回滾。思路很簡單就是需要知道一階段是否執(zhí)行,如果執(zhí)行了,那就是正?;貪L;如果沒執(zhí)行,那就是空回滾。因此,需要一張額外的事務(wù)控制表,其中有分布式事務(wù) ID 和分支事務(wù) ID,第一階段 Try 方法里會插入一條記錄,表示一階段執(zhí)行了。
Cancel 接口里讀取該記錄,如果該記錄存在,則正?;貪L;如果該記錄不存在,則是空回滾。 懸掛 懸掛就是對于一個分布式事務(wù),其二階段 Cancel 接口比 Try 接口先執(zhí)行。因為允許空回滾的原因,Cancel 接口認為 Try 接口沒執(zhí)行,空回滾直接返回成功,對于 Seata 框架來說,認為分布式事務(wù)的二階段接口已經(jīng)執(zhí)行成功,整個分布式事務(wù)就結(jié)束了。
但是這之后 Try 方法才真正開始執(zhí)行,預(yù)留業(yè)務(wù)資源,回想一下前面提到事務(wù)并發(fā)控制的業(yè)務(wù)加鎖,對于一個 Try 方法預(yù)留的業(yè)務(wù)資源,只有該分布式事務(wù)才能使用,然而 Seata 框架認為該分布式事務(wù)已經(jīng)結(jié)束,也就是說,當出現(xiàn)這種情況時,該分布式事務(wù)第一階段預(yù)留的業(yè)務(wù)資源就再也沒有人能夠處理了。
比如在 RPC 調(diào)用時,先注冊分支事務(wù),再執(zhí)行 RPC 調(diào)用,如果此時 RPC 調(diào)用的網(wǎng)絡(luò)發(fā)生擁堵,通常 RPC 調(diào)用是有超時時間的,RPC 超時以后,發(fā)起方就會通知 TC 回滾該分布式事務(wù),可能回滾完成后,RPC 請求才到達參與者,真正執(zhí)行,從而造成懸掛。
冪等
冪等就是對于同一個分布式事務(wù)的同一個分支事務(wù),重復(fù)去調(diào)用該分支事務(wù)的第二階段接口,因此,要求 TCC 的二階段 Confirm 和 Cancel 接口保證冪等,不會重復(fù)使用或者釋放資源。
如果冪等控制沒有做好,很有可能導(dǎo)致資損等嚴重問題。
解決思路 Try 方法主要需要考慮兩個問題,一個是 Try 方法需要能夠告訴二階段接口,已經(jīng)預(yù)留業(yè)務(wù)資源成功。第二個是需要檢查第二階段是否已經(jīng)執(zhí)行完成,如果已完成,則不再執(zhí)行 Confirm 方法。因為 Confirm 方法不允許空回滾,也就是說,Confirm 方法一定要在 Try 方法之后執(zhí)行。
因此,Confirm 方法只需要關(guān)注重復(fù)提交的問題。需要一張事務(wù)執(zhí)行記錄表,可以先鎖定事務(wù)記錄,如果事務(wù)記錄為空,則說明是一個空提交,不允許,終止執(zhí)行。如果事務(wù)記錄不為空,則繼續(xù)檢查狀態(tài)是否為初始化,如果是,則說明一階段正確執(zhí)行,那二階段正常執(zhí)行即可。
如果狀態(tài)是已提交,則認為是重復(fù)提交,直接返回成功即可;如果狀態(tài)是已回滾,也是一個異常,一個已回滾的事務(wù),不能重新提交,需要能夠攔截到這種異常情況,并報警。 Cancel 方法。因為 Cancel 方法允許空回滾,并且要在先執(zhí)行的情況下,讓 Try 方法感知到 Cancel 已經(jīng)執(zhí)行,所以和 Confirm 方法略有不同。
首先依然是鎖定事務(wù)記錄。如果事務(wù)記錄為空,則認為 Try 方法還沒執(zhí)行,即是空回滾??栈貪L的情況下,應(yīng)該先插入一條事務(wù)記錄,確保后續(xù)的 Try 方法不會再執(zhí)行。
如果插入成功,則說明 Try 方法還沒有執(zhí)行,空回滾繼續(xù)執(zhí)行。如果插入失敗,則認為 Try 方法正在執(zhí)行,等待 TC 的重試即可。
如果一開始讀取事務(wù)記錄不為空,則說明 Try 方法已經(jīng)執(zhí)行完畢,再檢查狀態(tài)是否為初始化,如果是,則還沒有執(zhí)行過其他二階段方法,正常執(zhí)行 Cancel 邏輯。
如果狀態(tài)為已回滾,則說明這是重復(fù)調(diào)用,允許冪等,直接返回成功即可。如果狀態(tài)為已提交,則同樣是一個異常,一個已提交的事務(wù),不能再次回滾
2.5 Saga
Saga 模式是 Seata 即將開源的長事務(wù)解決方案。在 Saga 模式下,分布式事務(wù)內(nèi)有多個參與者,每一個參與者都是一個沖正補償服務(wù),需要用戶根據(jù)業(yè)務(wù)場景實現(xiàn)其正向操作和逆向回滾操作。
分布式事務(wù)執(zhí)行過程中,依次執(zhí)行各參與者的正向操作,如果所有正向操作均執(zhí)行成功,那么分布式事務(wù)提交。如果任何一個正向操作執(zhí)行失敗,那么分布式事務(wù)會去退回去執(zhí)行前面各參與者的逆向回滾操作,回滾已提交的參與者,使分布式事務(wù)回到初始狀態(tài)。
Saga 正向服務(wù)與補償服務(wù)也需要業(yè)務(wù)開發(fā)者實現(xiàn)。有點像是 TCC 模式將 Try 過程和 Confirm 過程合并,所有參與者直接執(zhí)行 Try + Confirm,如果有人失敗了,就反向依次 Cancel。
由于該模式主要用于長事務(wù)場景,所以通常是由事件驅(qū)動的,各個參與者之間是異步執(zhí)行的。
Saga 模式適用于業(yè)務(wù)流程長且需要保證事務(wù)最終一致性的業(yè)務(wù)系統(tǒng),Saga 模式一階段就會提交本地事務(wù),無鎖、長流程情況下可以保證性能 Saga 模式的優(yōu)勢是:
一階段提交本地數(shù)據(jù)庫事務(wù),無鎖,高性能;
參與者可以采用事務(wù)驅(qū)動異步執(zhí)行,高吞吐;
補償服務(wù)即正向服務(wù)的 “反向”,易于理解,易于實現(xiàn);
缺點:Saga 模式由于一階段已經(jīng)提交本地數(shù)據(jù)庫事務(wù),且沒有進行 “預(yù)留” 動作,所以不能保證隔離性。
事務(wù)隔離 縱觀 Seata 提供的所有分支事務(wù)模式,除了 AT 模式和 XA 模式可以運行在讀已提交的隔離級別下,其他模式都是運行在讀未提交的級別下。
在有必要時,應(yīng)用需要通過業(yè)務(wù)邏輯的巧妙設(shè)定,來解決分布式事務(wù)隔離級別帶來的問題 AT 模式通過全局寫排他鎖,來保證事務(wù)間的寫隔離,將全局事務(wù)默認定義在讀未提交的隔離級別上,全局事務(wù)讀未提交,并不是說本地事務(wù)的 db 數(shù)據(jù)沒有正常提交,而是指全局事務(wù)二階段 commit | rollback 未真正處理完(即未釋放全局鎖),而且這時候其他事務(wù)會讀到一階段提交的內(nèi)容。
有些應(yīng)用如果需要達到全局的讀已提交,AT 也提供了相應(yīng)的機制來達到目的,那就是 select for update +@GlobalLock, 當執(zhí)行該命令時 RM 會去 TC 確認該鎖是否由他人占有,這樣如果有一個分布式事務(wù) T1 正在進行中時,另一個事務(wù) T2 會因為發(fā)現(xiàn)鎖沖突而阻塞后續(xù)代碼的執(zhí)行,當前面的分布式事務(wù) T1 結(jié)束時,釋放了相應(yīng)的資源鎖,T2 才能讀取到相應(yīng)的數(shù)據(jù),這樣就達到讀已提交的效果
2.6 消息組件
利用 MQ 組件實現(xiàn)的二階段提交。此方案涉及 3 個模塊:
上游應(yīng)用,執(zhí)行業(yè)務(wù)并發(fā)送 MQ 消息。
可靠消息服務(wù)和 MQ 消息組件,協(xié)調(diào)上下游消息的傳遞,并確保上下游數(shù)據(jù)的一致性。
下游應(yīng)用,監(jiān)聽 MQ 的消息并執(zhí)行自身業(yè)務(wù)。
上游應(yīng)用將本地業(yè)務(wù)執(zhí)行和消息發(fā)送綁定在同一個本地事務(wù)中,保證要么本地操作成功并發(fā)送 MQ 消息,要么兩步操作都失敗并回滾。
上游應(yīng)用發(fā)送待確認消息到可靠消息系統(tǒng)
可靠消息系統(tǒng)保存待確認消息并返回
上游應(yīng)用執(zhí)行本地業(yè)務(wù)
上游應(yīng)用通知可靠消息系統(tǒng)確認業(yè)務(wù)已執(zhí)行并發(fā)送消息。
可靠消息系統(tǒng)修改消息狀態(tài)為發(fā)送狀態(tài)并將消息投遞到 MQ 中間件。
下游應(yīng)用監(jiān)聽 MQ 消息組件并獲取消息
下游應(yīng)用根據(jù) MQ 消息體信息處理本地業(yè)務(wù)
下游應(yīng)用向 MQ 組件自動發(fā)送 ACK 確認消息被消費
下游應(yīng)用通知可靠消息系統(tǒng)消息被成功消費,可靠消息將該消息狀態(tài)更改為已完成。
異常處理 上游異常
可靠消息服務(wù)定時監(jiān)聽消息的狀態(tài),如果存在狀態(tài)為待確認并且超時的消息,則表示上游應(yīng)用和可靠消息交互中的步驟 4 或者 5 出現(xiàn)異常。
可靠消息查詢超時的待確認狀態(tài)的消息
向上游應(yīng)用查詢業(yè)務(wù)執(zhí)行的情況
業(yè)務(wù)未執(zhí)行,則刪除該消息,保證業(yè)務(wù)和可靠消息服務(wù)的一致性。業(yè)務(wù)已執(zhí)行,則修改消息狀態(tài)為已發(fā)送,并發(fā)送消息到 MQ 組件。
下游異常
可靠消息服務(wù)定時查詢狀態(tài)為已發(fā)送并超時的消息
可靠消息將消息重新投遞到 MQ 組件中
下游應(yīng)用監(jiān)聽消息,在滿足冪等性的條件下,重新執(zhí)行業(yè)務(wù)。
下游應(yīng)用通知可靠消息服務(wù)該消息已經(jīng)成功消費。
實際過程中,還需要引入人工干預(yù)功能。比如引入重發(fā)次數(shù)限制,超過重發(fā)次數(shù)限制的將消息修改為死亡消息,等待人工處理。
3 總結(jié)
3.1 sql 支持上
AT 其實就是一個自實現(xiàn)的 XA 事務(wù),其實可以知道,AT 在 sql 支持上遠不及 XA 模式,AT 需要做 sql 解析背后的實現(xiàn)只能自己解決,目前只能靠社區(qū)的貢獻者來提供解決方案,這是一個長期的關(guān)鍵性的問題,也有很多用戶選擇在 AT 模式上重寫 sql 來獲取 AT 模式的支持,sql 支持上 XA 是完勝的。
3.2 隔離性
AT 模式是通過解析 sql 獲取涉及的主鍵 id,生成行鎖。也就是 AT 模式的隔離靠的是全局鎖來保證的,粒度細至行級。鎖信息存儲在 seata server 側(cè)。XA 的隔離級別是由本地數(shù)據(jù)庫保證,鎖存儲在各個本地數(shù)據(jù)庫中。由于 XA 模式一旦執(zhí)行了 prepare 后,再也無法重入這個 XA 事務(wù)也無法跟其他 XA 事務(wù)共享鎖,因為 XA 協(xié)議僅僅是通過 XID 來 start 一個事務(wù),本身不存在分支事務(wù)的說法。也就是說他只管自己
3.3 入侵性
通過上面的信息可以發(fā)現(xiàn)誰更底層,入侵性則更小,所以由數(shù)據(jù)庫自身支持的 XA 模式來說,入侵性無疑最小,使用成本最低。XA 的 RM 實際是在數(shù)據(jù)庫,而 AT 則是以中間件層部署在應(yīng)用這一側(cè)的,不依賴數(shù)據(jù)庫本身的協(xié)議支持,這點對于微服務(wù)架構(gòu)來說是至關(guān)重要的。應(yīng)用層不需要為本地事務(wù)和分布式事務(wù)多類不同場景來適配多套不通的驅(qū)動
3.4 補償性事務(wù)的問題
本質(zhì)上 seata 框架支持了 3 大補償事務(wù)模式,AT, TCC,Saga 都是補償型的。補償型事務(wù)處理機制是構(gòu)建在事務(wù)資源之上的,事務(wù)資源本身對分布式事務(wù)是無感知的,事務(wù)資源對分布式事務(wù)無感知存在一個根本性問題,就是無法做到真正的全局一致性。
比如一條庫存記錄,處在補償型事務(wù)處理過程中,由 100 扣減為 50,此時倉庫管理員連接數(shù)據(jù)庫查看就會查詢到 50,之后事務(wù)異常回滾,庫存就會被補償回滾為 100,顯然倉庫管理員查詢到的 50 就是臟數(shù)據(jù)。那 XA 的價值是什么,與補償型事務(wù)不同,XA 協(xié)議要求事務(wù)資源本身提供對規(guī)范和協(xié)議的支持。
因為事務(wù)資源感知并參與分布式事務(wù)處理過程,所以事務(wù)資源可以保證從任意視角對數(shù)據(jù)的訪問有效隔離,比如上面 XA 事務(wù)處理過程中,中間態(tài)的 50 是不會被查詢到的(當然隔離級別要在讀已提交以上),以此來滿足全局一致性。
審核編輯:劉清
-
SQL
+關(guān)注
關(guān)注
1文章
764瀏覽量
44134 -
協(xié)調(diào)器
+關(guān)注
關(guān)注
0文章
29瀏覽量
15972 -
CAP
+關(guān)注
關(guān)注
0文章
16瀏覽量
2092
原文標題:基于Seata探尋分布式事務(wù)的實現(xiàn)方案
文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論