動態

詳情 返回 返回

【Spring開發】SpringCloud服務端高級框架第8篇:4.2.AT模式,4.3.TCC模式【附代碼文檔】 - 動態 詳情

🏆🏆🏆教程全知識點簡介:微服務保護、服務異步通信、消息中間件部署、分佈式事務、搜索引擎、緩存、數據同步以及相關組件的安裝配置等技術要點。在微服務保護方面,介紹了 Sentinel 的基礎知識,包括雪崩問題、超時處理、艙壁模式、斷路器機制,以及不同服務保護技術的對比;講解了流量控制(簇點鏈路、流控模式、熱點參數限流)、隔離與降級(FeignClient 整合 Sentinel、線程隔離)、授權規則(自定義異常結果)及規則持久化(規則管理模式與 pull 模式),並演示了基於 Nacos 的規則持久化改造。服務異步通信部分探討了消息可靠性(生產者消息確認、Return 回調、ConfirmCallback)、死信交換機、TTL 隊列等高級應用。RabbitMQ 部署指南涵蓋了單機部署、DelayExchange 插件安裝、集羣部署、鏡像模式等內容。分佈式事務部分介紹了 CAP 定理、BASE 理論、常見解決方案,Seata 的基礎與部署(TC 服務部署、Nacos 配置、數據庫表創建)、多種事務模式(XA 模式及優缺點、四種模式對比)和高可用架構。分佈式搜索引擎章節講解了 Elasticsearch 的原理(ELK 技術棧、倒排索引)、索引庫與文檔操作、RestAPI 與 RestClient 的使用、排序與高亮、酒店搜索案例(分頁、競價排名、ad標記、算分函數)、自動補全、數據同步(同步調用、監聽 binlog)、集羣搭建與腦裂問題、分片存儲測試,以及單點 ES、Kibana、IK 分詞器安裝。緩存部分介紹了 Redis 持久化(RDB 與 AOF 對比)、單機安裝 Redis、Redis 集羣、多級緩存(JVM 進程緩存、Caffeine)、請求參數處理、Tomcat 查詢、HTTP 工具與 CJSON 工具類、Redis 緩存查詢。數據同步與網關部分包括 Canal 安裝(開啓 MySQL 主從、設置權限)、OpenResty 安裝(開發庫、目錄結構、環境變量配置)及運行流程。

<!-- start:bj1 -->

📚📚倉庫code.zip 👉直接-->:   https://gitee.com/xiaoshuai112/Backend/blob/master/Spring/Spr...    🍅🍅

<!-- end:bj1 -->

✨ 本教程項目亮點

🧠 知識體系完整:覆蓋從基礎原理、核心方法到高階應用的全流程內容
💻 全技術鏈覆蓋:完整前後端技術棧,涵蓋開發必備技能
🚀 從零到實戰:適合 0 基礎入門到提升,循序漸進掌握核心能力
📚 豐富文檔與代碼示例:涵蓋多種場景,可運行、可複用
🛠 工作與學習雙參考:不僅適合系統化學習,更可作為日常開發中的查閲手冊
🧩 模塊化知識結構:按知識點分章節,便於快速定位和複習
📈 長期可用的技術積累:不止一次學習,而是能伴隨工作與項目長期參考

🎯🎯🎯全教程總章節


🚀🚀🚀本篇主要內容

4.2.AT模式

AT模式同樣是分階段提交的事務模型,不過缺彌補了XA模型中資源鎖定週期過長的缺陷。

4.2.1.Seata的AT模型

基本流程圖:

階段一RM的工作:

  • 註冊分支事務
  • 記錄undo-log(數據快照)
  • 執行業務sql並提交
  • 報告事務狀態

階段二提交時RM的工作:

  • 刪除undo-log即可

階段二回滾時RM的工作:

  • 根據undo-log恢復數據到更新前

4.2.2.流程梳理

用一個真實的業務來梳理下AT模式的原理。

比如,現在又一個數據庫表,記錄用户餘額:

id money
1 100

其中一個分支業務要執行的SQL為:

update tb_account set money = money - 10 where id = 1

AT模式下,當前分支事務執行流程如下:

一階段:

1)TM發起並註冊全局事務到TC

2)TM調用分支事務

3)分支事務準備執行業務SQL

4)RM攔截業務SQL,根據where條件查詢原始數據,形成快照。

{
    "id": 1, "money": 100
}

Apache Tomcat 文檔

5)RM執行業務SQL,提交本地事務,釋放數據庫鎖。此時 money = 90

6)RM報告本地事務狀態給TC

二階段:

1)TM通知TC事務結束

2)TC檢查分支事務狀態

​ a)如果都成功,則立即刪除快照

​ b)如果有分支事務失敗,需要回滾。讀取快照數據({"id": 1, "money": 100}),將快照恢復到數據庫。此時數據庫再次恢復為100

流程圖:

Spring Security API 文檔

4.2.3.AT與XA的區別

簡述AT模式與XA模式最大的區別是什麼?

  • XA模式一階段不提交事務,鎖定資源;AT模式一階段直接提交,不鎖定資源。
  • XA模式依賴數據庫機制實現回滾;AT模式利用數據快照實現數據回滾。
  • XA模式強一致;AT模式最終一致

4.2.4.髒寫問題

在多線程併發訪問AT模式的分佈式事務時,有可能出現髒寫問題,如圖:

解決思路就是引入了全局鎖的概念。在釋放DB鎖之前,先拿到全局鎖。避免同一時刻有另外一個事務來操作當前數據。

Spark Java 文檔

4.2.5.優缺點

AT模式的優點:

  • 一階段完成直接提交事務,釋放數據庫資源,性能比較好
  • 利用全局鎖實現讀寫隔離
  • 沒有代碼侵入,框架自動完成回滾和提交

AT模式的缺點:

  • 兩階段之間屬於軟狀態,屬於最終一致
  • 框架的快照功能會影響性能,但比XA模式要好很多

4.2.6.實現AT模式

AT模式中的快照生成、回滾等動作都是由框架自動完成,沒有任何代碼侵入,因此實現非常簡單。

只不過,AT模式需要一個表來記錄全局鎖、另一張表來記錄數據快照undo_log。

Ehcache 文檔

1)導入數據庫表,記錄全局鎖

導入課前資料提供的Sql文件:seata-at.sql,其中lock_table導入到TC服務關聯的數據庫,undo_log表導入到微服務關聯的數據庫:

2)修改application.yml文件,將事務模式修改為AT模式即可:

seata:
  data-source-proxy-mode: AT # 默認就是AT

HikariCP 連接池

3)重啓服務並測試

4.3.TCC模式

TCC模式與AT模式非常相似,每階段都是獨立事務,不同的是TCC通過人工編碼來實現數據恢復。需要實現三個方法:

  • Try:資源的檢測和預留;
  • Confirm:完成資源操 務;要求 Try 成功 Confirm 一定要能成功。
  • Cancel:預留資源釋放,可以理解為try的反向操作。

4.3.1.流程分析

舉例,一個扣減用户餘額的業務。假設賬户A原來餘額是100,需要餘額扣減30元。

  • 階段一( Try ):檢查餘額是否充足,如果充足則凍結金額增加30元,可用餘額扣除30

初識餘額:

餘額充足,可以凍結:

此時,總金額 = 凍結金額 + 可用金額,數量依然是100不變。事務直接提交無需等待其它事務。

  • 階段二(Confirm):假如要提交(Confirm),則凍結金額扣減30

確認可以提交,不過之前可用金額已經扣減過了,這裏只要清除凍結金額就好了:

此時,總金額 = 凍結金額 + 可用金額 = 0 + 70 = 70元

  • 階段二(Canncel):如果要回滾(Cancel),則凍結金額扣減30,可用餘額增加30

需要回滾,那麼就要釋放凍結金額,恢復可用金額:

4.3.2.Seata的TCC模型

Seata中的TCC模型依然延續之前的事務架構,如圖:

Spring Boot 官方文檔

4.3.3.優缺點

TCC模式的每個階段是做什麼的?

  • Try:資源檢查和預留
  • Confirm:業務執行和提交
  • Cancel:預留資源的釋放

TCC的優點是什麼?

  • 一階段完成直接提交事務,釋放數據庫資源,性能好
  • 相比AT模型,無需生成快照,無需使用全局鎖,性能最強
  • 不依賴數據庫事務,而是依賴補償操作,可以用於非事務型數據庫

TCC的缺點是什麼?

  • 有代碼侵入,需要人為編寫try、Confirm和Cancel接口,太麻煩
  • 軟狀態,事務是最終一致
  • 需要考慮Confirm和Cancel的失敗情況,做好冪等處理

4.3.4.事務懸掛和空回滾

1)空回滾

當某分支事務的try階段阻塞時,可能導致全局事務超時而觸發二階段的cancel操作。在未執行try操作時先執行了cancel操作,這時cancel不能做回滾,就是空回滾

如圖:

執行cancel操作時,應當判斷try是否已經執行,如果尚未執行,則應該空回滾。

2)業務懸掛

對於已經空回滾的業務,之前被阻塞的try操作恢復,繼續執行try,就永遠不可能confirm或cancel ,事務一直處於中間狀態,這就是業務懸掛

執行try操作時,應當判斷cancel是否已經執行過了,如果已經執行,應當阻止空回滾後的try操作,避免懸掛

4.3.5.實現TCC模式

解決空回滾和業務懸掛問題,必須要記錄當前事務狀態,是在try、還是cancel?

1)思路分析

這裏 定義一張表:

CREATE TABLE `account_freeze_tbl` (
  `xid` varchar(128) NOT NULL,
  `user_id` varchar(255) DEFAULT NULL COMMENT '用户id',
  `freeze_money` int(11) unsigned DEFAULT '0' COMMENT '凍結金額',
  `state` int(1) DEFAULT NULL COMMENT '事務狀態,0:try,1:confirm,2:cancel',
  PRIMARY KEY (`xid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

Dozer 映射框架

其中:

  • xid:是全局事務id
  • freeze_money:用來記錄用户凍結金額
  • state:用來記錄事務狀態

那此時, 的業務開怎麼做呢?

  • Try業務:

    • 記錄凍結金額和事務狀態到account_freeze表
    • 扣減account表可用金額
  • Confirm業務

    • 根據xid刪除account_freeze表的凍結記錄
  • Cancel業務

    • 修改account_freeze表,凍結金額為0,state為2
    • 修改account表,恢復可用金額
  • 如何判斷是否空回滾?

    • cancel業務中,根據xid查詢account_freeze,如果為null則説明try還沒做,需要空回滾
  • 如何避免業務懸掛?

    • try業務中,根據xid查詢account_freeze ,如果已經存在則證明Cancel已經執行,拒絕執行try業務

接下來, 改造account-service,利用TCC實現餘額扣減功能。

2)聲明TCC接口

TCC的Try、Confirm、Cancel方法都需要在接口中基於註解來聲明,

在account-service項目中的cn.itcast.account.service包中新建一個接口,聲明TCC三個接口:

package cn.itcast.account.service;

import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;

@LocalTCC
public interface AccountTCCService {

    @TwoPhaseBusinessAction(name = "deduct", commitMethod = "confirm", rollbackMethod = "cancel")
    void deduct(@BusinessActionContextParam

## 4.4.SAGA模式

Saga 模式是 Seata 即將開源的長事務解決方案,將由螞蟻金服主要貢獻。

其理論基礎是Hector & Kenneth  在1987年發表的論文[Sagas](https://microservices.io/patterns/data/saga.html)。

Seata官網對於Saga的指南:https://seata.io/zh-cn/docs/user/saga.html

### 4.4.1.原理

在 Saga 模式下,分佈式事務內有多個參與者,每一個參與者都是一個衝正補償服務,需要用户根據業務場景實現其正向操作和逆向回滾操作。

分佈式事務執行過程中,依次執行各參與者的正向操作,如果所有正向操作均執行成功,那麼分佈式事務提交。如果任何一個正向操作執行失敗,那麼分佈式事務會去退回去執行前面各參與者的逆向回滾操作,回滾已提交的參與者,使分佈式事務回到初始狀態。

![](/img/bVdmscv)

Saga也分為兩個階段:

- 一階段:直接提交本地事務
- 二階段:成功則什麼都不做;失敗則通過編寫補償業務來回滾



### 4.4.2.優缺點



優點:

- 事務參與者可以基於事件驅動實現異步調用,吞吐高
- 一階段直接提交事務,無鎖,性能好
- 不用編寫TCC中的三個階段,實現簡單

缺點:

- 軟狀態持續時間不確定,時效性差
- 沒有鎖,沒有事務隔離,會有髒寫

## 4.5.四種模式對比

 從以下幾個方面來對比四種實現:

- 一致性:能否保證事務的一致性?強一致還是最終一致?
- 隔離性:事務之間的隔離性如何?
- 代碼侵入:是否需要對業務代碼改造?
- 性能:有無性能損耗?
- 場景:常見的業務場景



如圖:

![](/img/bVdmscx)





IntelliJ IDEA 文檔

JConsole 文檔

Spring IoC 容器


🚀✨ (未完待續)項目系列下一章

📚下一篇 將進入更精彩的環節!
🔔 記得收藏 & 關注,第一時間獲取更新!
🍅 一起見證整個系列逐步成型的全過程。

Add a new 評論

Some HTML is okay.