1.SEATA是什么:
Seata 是一款開源的分布式事務解決方案,致力於提供高性能和簡單易用的分布式事務服務。Seata 為用戶提供了 AT、TCC、SAGA 和 XA 事務模式,為用戶打造一站式的分布式解決方案。
2、SEATA整體框架:
Seata 中有三大模塊,分別是 TM、RM 和 TC。其中 TM 和 RM 是作為 Seata 的客戶端與業務系統集成在一起,TC 作為 Seata 的服務端獨立部署。
角色划分:
TM:事務管理器,開啟、 提交、回滾分布式事務
RM: 資源管理器,注冊、 匯報、執⾏資源
TC : 事務管理器服務功能,存儲事務日志、補償異常事務等、集中管理事務全局鎖(全局行鎖),seata服務端
事務執行整體流程:
- TM 開啟分布式事務(TM 向 TC 注冊全局事務記錄);
- 按業務場景,編排數據庫、服務等事務內資源(RM 向 TC 匯報資源准備狀態 );
- TM 結束分布式事務,事務一階段結束(TM 通知 TC 提交/回滾分布式事務);
- TC 匯總事務信息,決定分布式事務是提交還是回滾;
- TC 通知所有 RM 提交/回滾 資源,事務二階段結束;
3、AT模式介紹
AT 模式是一種無侵入的分布式事務解決方案。在 AT 模式下,用戶只需關注自己的“業務 SQL”,用戶的 “業務 SQL” 作為一階段,Seata 框架會自動生成事務的二階段提交和回滾操作。
1、 整體機制:
兩階段提交協議的演變:
一階段:業務數據和回滾日志記錄在同一個本地事務中提交,釋放本地鎖和連接資源。
二階段:
- 提交異步化,非常快速地完成。
- 回滾通過一階段的回滾日志進行反向補償。
2、詳細流程:
一階段提交:
在一階段,Seata 會攔截“業務 SQL”,首先解析 SQL 語義,找到“業務 SQL”要更新的業務數據,在業務數據被更新前,將其保存成“before image”,然后執行“業務 SQL”更新業務數據,在業務數據更新之后,再將其保存成“after image”,最后生成行鎖。以上操作全部在一個數據庫事務內完成,這樣保證了一階段操作的原子性。
二階段提交:
二階段如果是提交的話,因為“業務 SQL”在一階段已經提交至數據庫, 所以 Seata 框架只需將一階段保存的快照數據和行鎖刪掉,完成數據清理即可。
二階段回滾:
二階段如果是回滾的話,Seata 就需要回滾一階段已經執行的“業務 SQL”,還原業務數據。回滾方式便是用“before image”還原業務數據;但在還原前要首先要校驗臟寫,對比“數據庫當前業務數據”和 “after image”,如果兩份數據完全一致就說明沒有臟寫,可以還原業務數據,如果不一致就說明有臟寫,出現臟寫就需要轉人工處理。
3、並發事務的隔離處理:
寫隔離:
正常提交:
tx1先開啟本地事務,拿到本地鎖; tx1更新操作 m = 1000-100 = 900; tx1拿到記錄的全局行鎖 ; tx1本地提交,釋放本地鎖 tx2開啟本地事務,拿到本地鎖; tx2更新操作 m = 900-100 = 800。 tx2嘗試拿該記錄的全局行鎖; tx2重試等待全局鎖 (tx1全局提交前,全局鎖被 tx1 持有) tx1全局提交,釋放全局鎖; tx2拿到記錄的全局行鎖; tx2本地提交,釋放本地鎖; tx2全局提交,釋放全局行鎖。
數據回滾:
tx1獲得全局鎖,二階段全局回滾,需獲取本地鎖; tx2持有本地鎖,等待全局行鎖。 tx1分支回滾失敗,一直重試; tx2等待全局行鎖超時; tx2回滾本地事務,釋放本地鎖; tx1獲取本地鎖,回滾成功。 tx1全局回滾,釋放全局行, 整個過程全局鎖一直被 tx1 持有,所以不會發生臟寫的問題。
讀隔離:
AT 模式默認全局隔離級別是讀未提交 。如果應用在特定場景下,必需全局讀已提交,Seata方式是通過 SELECT FOR UPDATE 語句代理。 SELECT FOR UPDATE 語句執行會自動申請全局行鎖,如果全局鎖被其他事務持有,則釋放本地鎖(回滾 SELECT FOR UPDATE 語句的本地執行)並重試。 這個過程中,查詢是被 block 住的,直到全局行鎖拿到,即讀取的相關數據是已提交的才返回。
4、適用場景:
分布式事務的業務邏輯中僅僅純數據庫操作,不包含其他中間件事務邏輯。
優勢:
改動及代碼侵入最小。由Seata來負責Commit和Rollback的自動化觸發或回滾操作。
劣勢:
1、如果事務中包含緩存存儲或發送EQ消息等不適合。
2、為了保證鏡像sql的可靠性,需要用戶對sql盡量做簡化, 建議做法:將多條SQL語句分解為多個事務中的原子步驟(對應SeataAt模式的分支Branch概念),如果單條SQL語句跨表,也分解成為多個事務中的原子步驟(盡量降低Seata存儲鏡前SQL結果時的風險)。
3、多次對DB的操作,以及全局行鎖的存在對並發處理性能有影響。
4、在二階段未回滾前,都是commit狀態,在回滾前,其他線程出現臟讀,出現臟寫需要人工處理。
4、TCC模式介紹
該模式由螞蟻金服貢獻。TCC 模式需要用戶根據自己的業務場景實現 Try、Confirm 和 Cancel 三個操作;事務發起方在一階段執行 Try 方式,在二階段提交執行 Confirm 方法,二階段回滾執行 Cancel 方法。
整體流程圖:
TCC 三個方法描述:
- Try:資源的檢測和預留;
- Confirm:執行的業務操作提交;要求 Try 成功 Confirm 一定要能成功;
- Cancel:預留資源釋放;
TCC典型業務場景分析:
轉賬場景:A賬戶扣錢,B賬戶加錢;
賬戶 A 上有 100 元,要扣除其中的 30 元 :
如上圖所示,Try 方法作為一階段准備方法,需要做資源的檢查和預留。
在扣錢場景下,Try 要做的事情是就是檢查賬戶余額是否充足,預留轉賬資金,預留的方式就是凍結 A 賬戶的 轉賬資金。Try 方法執行之后,賬號 A 余額雖然還是 100,但是其中 30 元已經被凍結了,不能被其他事務使用。 二階段 Confirm 方法執行真正的扣錢操作。Confirm 會使用 Try 階段凍結的資金,執行賬號扣款。Confirm 方法執行之后,賬號 A 在一階段中凍結的 30 元已經被扣除,賬號 A 余額變成 70 元 。
如果二階段是回滾的話,就需要在 Cancel 方法內釋放一階段 Try 凍結的 30 元,使賬號 A 的回到初始狀態,100 元全部可用。
TCC 設計要點:
允許空回滾:
狀態: try未執行,收到cancel請求
原因:
Try超時(網絡丟包)---->分布式事務回滾,觸發cancel---->未收到try,收到cancel
解決方案:
Cancel 接口設計時需要允許空回滾。在 Try 接口因為丟包時沒有收到,事務管理器會觸發回滾,這時會觸發 Cancel 接口,這時 Cancel 執行時發現沒有對應的事務 xid 或主鍵時,需要返回回滾成功。讓事務服務管理器 認為已回滾。
防懸掛控制:
狀態:Cancel比Try先執行
原因:
Try超時(網絡擁堵)------> 分布式事務回滾,觸發cancel----->擁堵的Try到達
解決方案:
首先Cancel 接口設計時需要允許空回滾。在 Cancel 空回滾返回成功之前先記錄該條事務 xid 或業務主鍵,標識這條記錄已經回滾過,Try 接口先檢查這條事務xid或業務主鍵如果已經標記為回滾成功過,則不執行Try 的業務操作。
冪等處理:
Try、Confirm、Cancel三個方法均要保證冪等性。
TCC適用場景:
分布式事務的業務邏輯中除了數據庫操作外,包含其他中間件事務邏輯。
優勢:
1、用戶可以自己定義業務的補償邏輯,由業務層保證事務的一致性;
2、適合微服務化場景;
3、無 AT 模式的全局行鎖,TCC 性能會比 AT 模式高很多。
劣勢:
1、需要考慮如何將業務模型拆成 2 階段,實現成 TCC 的 3 個方法,並且保證 Try 成功 Confirm 一定能成功,Confirm失敗會不斷重試。
2、TCC 模式下開發者需要自行實現try,confirm,cancel接口,對業務代碼有一定的侵入性。
4、Seata的saga模式
Saga 模式介紹:
Saga 模式是Seata的長事務解決方案,由螞蟻金服主要貢獻。在 Saga 模式下,分布式事務內有多個參與者,每一個參與者都是一個沖正補償服務,需要用戶根據業務場景實現其正向操作和逆向回滾操作。
Saga模式機制:
分布式事務執行過程中,依次執行各參與者的正向操作,如果所有正向操作均執行成功,那么分布式事務提交。如果任何一個正向操作執行失敗,那么分布式事務會去退回去執行前面各參與者的逆向回滾操作,回滾已提交的參與者,使分布式事務回到初始狀態。
Saga 模式下分布式事務通常是由事件驅動的,各個參與者之間是異步執行的,Saga 模式是一種長事務解決方案。
Saga設計要點:
允許空補償:
狀態:原服務未執行,補償服務執行了。
原因:
原服務超時(丟包)---> Saga事務觸發回滾 ----> 未收到原服務的請求,先收到補償請求。
解決方案:允許空補償。
防懸掛控制
狀態:補償服務比原服務先執行。
原因:
原服務超時(網絡擁堵)-----> Saga事務回滾-----> 先進行補償操作以后,擁堵的原服務到達。
解決方案:允許空回滾,拒絕空回滾以后原服務的執行。
冪等控制:
原服務和補償服務支持冪等操作。
自定義事務恢復策略:
1、Saga事務不保證隔離性,在極端情況下會出現由於臟寫導致無法完成回滾補償操作,此時狀態機引擎可以“重試”繼續往前完成這個分布式事務。由於整個業務流程是由狀態機編排的,即使是事后恢復也可以繼續往前重試。
2、 用戶可以基於業務特點配置該流程的事務處理策略是優先“回滾”還是“重試”,當事務超時,seata會基於用戶配置的策略不斷進行重試。
使用建議:
由於 Saga 不保證隔離性,所以我們在業務設計的時候需要做到“寧可長款,不可短款”的原則,長款是指在出現差錯的時候站在我方的角度錢多了的情況,錢少了則是短款,因為如果長款可以給客戶退款,而短款則可能錢追不回來了,也就是說在業務設計的時候,一定是先扣客戶帳再入帳,如果因為隔離性問題造成覆蓋更新,也不會出現錢少了的情況。
適用場景:
1、長流程事務、不需馬上返回最終結果,只要保證最終一致性的場景,
2、對數據隔離性要求不高,對性能要求高的場景。
3、事務參與者可能是其它公司的服務或者是遺留系統的服務,無法進行改造和提供 TCC 要求的接口。
優勢:
事件驅動、無全局鎖、異步、高吞吐、性能高,補償易實現。
劣勢:
自己寫補償邏輯,沒有事務隔離性。
5.Seata XA模式
也是我們常說的二階段提交,XA要求數據庫本身提供對規范和協議的支持。XA也是對業務代碼無侵入性的
XA是全局一致性:在提交階段也會鎖定數據(與AT的區別)
優勢:
XA是由數據庫自身所支持的(鎖存儲在各個本地數據庫中),所以入侵性最小,使用成本最低
數據全局一致
缺點:
XA協議阻塞帶來性能下降的比較厲害,分支事務越多,性能越差。