Seata原理淺析

fuxing.發表於2024-05-11

前言

Seata是阿里開源的分散式事務解決方案,本文將詳細介紹 Seata 的事務模式、原理以及使用。瞭解之前需清楚什麼是分散式事務


一、什麼是 Seata

Seata 是一款開源的分散式事務解決方案,致力於提供高效能和簡單易用的分散式事務服務。Seata 將為使用者提供了XA、AT、TCC 和 SAGA 事務模式,為使用者打造一站式的分散式解決方案。

Seata 的幾種角色:

角色 說明
TC Transaction Coordinator,事務協調者,用來協調全域性和各個分支事務(不同服務)的狀態, 驅動它們的回滾或提交。
TM Transaction Manager,事務管理者,業務層中用來開啟/提交/回滾一個整體事務(在呼叫服務的方法中用註解開啟事務)。
RM Resource Manager,資源管理者,管理分支事務,與 TC 進行協調註冊分支事務,並且彙報分支事務的狀態,驅動分支事務的提交或回滾。

簡單流程圖:

image.png

二、事務模式

1. XA 模式

Seata 的 XA 模式大體與 2PC 事務相似。

1.1 流程介紹

image.png

第一階段:

  1. RM 註冊分支事務到 TC;
  2. RM 執行分支業務的 SQL 但不提交
  3. RM 報告執行狀態到 TC;

第二階段:

  1. TC 檢測檢測各分支事務狀態,判斷整體事務提交或回滾;
  2. RM 接受 TC 的指令,進行統一的提交或回滾操作。

1.2 XA 優缺點

優點:

  1. 事務強一致性,滿足 ACID 原則;
  2. 實現簡單,無程式碼入侵。

缺點:

  1. 一階段鎖定資源,二階段結束才釋放,效能較差;
  2. 依賴關係型資料庫實現事務;

2. AT 模式

Auto Transaction,基於 XA 演進而來,需要資料庫支援,如果是 MySQL,則需要5.6以上版本才支援XA協議。

是一種無侵入的分散式事務解決方案,該模式下,使用者只需關注自己的業務 SQL,Seata 框架會在第一階段攔截並解析 SQL,生成 undo log,並自動生成事務二階段的提交和回滾操作。

AT 模式下,是利用快照實現資料回滾,屬於弱一致。

2.1 流程介紹

image.png

第一階段:

  1. RM 註冊分支事務到 TC;
  2. 記錄 undo log(資料快照);
  3. RM 執行分支業務的 SQL 並提交
  4. RM 報告執行狀態到 TC;

第二階段:

  1. TC 檢測檢測各分支事務狀態,判斷整體事務提交或回滾;
  2. RM 接受 TC 的指令,進行統一的提交或回滾操作。
    1. 提交時,非同步刪除相應分支的 undo log;
    2. 回滾時,根據 undo log 生成補償回滾的 SQL,執行分支回滾並返回結果給 TC;

例如,一個分支業務需要對account餘額表中的money進行扣減 10 元,則需要進行如下流程:

image.png

2.2 髒寫問題

如下圖所示,併發事務之間,可能會產生髒寫導致資料修改被覆蓋。

image.png

如何解決髒寫,Seata 透過全域性鎖來管理事務,持有全域性鎖的事務才有執行 SQL 的權利,這裡全域性鎖只針對交由 Seata 管理的事務

如下圖,簡單流程大致如下:

  1. 一階段本地事務提交前,需要確保先拿到全域性鎖 ;
  2. 拿不到全域性鎖 ,不能提交本地事務。
  3. 拿不到全域性鎖會重試,次數有限,超出限制將放棄,並回滾本地事務,釋放本地鎖。

image.png

2.3 資料快照

那麼非 Seata 事務於 Seata 事務併發修改資料時如何處理?

RM 在第一階段將分支事務註冊到 TC 時,會在 undo log 儲存兩個資料快照,分別是:

  • before-image:資料修改前的快照
  • after-image:資料修改後的快照

當發生異常時,before-image用來做資料回滾,after-image來判斷修改後資料於當前資料是否相同,相同則透過before-image做資料回滾,不同則說明被其他非 Seata 事務修改過,記錄異常,人工介入。

具體流程見下圖。

image.png

2.4 髒讀問題

與髒寫類似,是指在全域性事務未提交前,被其它業務讀到已提交的分支事務的資料,本質上 Seata 預設的全域性事務是讀未提交

那麼怎麼避免髒讀現象呢?

  1. 業務查詢時要使用@GlobalTransactional@GlobalLock來修飾查詢方法的呼叫;
  2. 查詢語句須使用select for update語句。

這樣在執行 SQL 前會檢查全域性鎖是否存在,只有當全域性鎖完成之後,才能繼續執行 SQL,這樣就防止了髒讀。

不過,AT 事務模式下讀已提交的成本很高,對於非必要場景還是要儘量避免使用。

傳統的讀已提交不需要本地鎖,但這裡卻需要select for update語句,查詢多出了加鎖和競爭的開銷,另外還要持鎖呼叫 TC 的lockQuery介面以判斷全域性鎖情況。

2.5 AT 優缺點

優點:

  1. 一階段直接完成事務提交,釋放資料庫資源,效能比較好;
  2. 利用全域性鎖實現讀寫隔離;
  3. 沒有程式碼入侵,框架自動完成回滾或提交。

缺點:

  1. 兩階段之間屬於軟狀態,屬於最終一直;
  2. 資料快照會影響效能,但比 XA 模式要好很多;

3. TCC 模式

關於什麼是 TCC 模式及原理,詳情見什麼是分散式事務

TCC 與 AT 模式很相似,每階段都是獨立事務,不同的是 TCC 透過人工編碼來實現資料恢復。

3.1 流程介紹

image.png

TCC 每個階段是做什麼的:

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

TCC 不存在資源阻塞的問題,因為每個方法都直接進行事務的提交,一旦出現異常透過則Cancel來進行回滾補償,這也就是常說的補償性事務

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

image.png

空回滾和業務懸掛

什麼是空回滾?

分支事務Try操作阻塞時,可能導致全域性事務超時觸發Cancel操作。在Try未執行時先執行了Cancel,這時的Cancel理論上不應該回滾,這時就需要空回滾

image.png

什麼是業務懸掛?

對於已經空回滾的業務,這時如果執行緒不再阻塞,繼續執行Try,但不可能ConfirmCancel,這就是業務懸掛,需要避免空回滾後的Try操作。

如何解決空回滾和業務懸掛?

回滾時需要在執行Cancel操作時,判斷有沒有執行Try操作。相應的,在執行Try時判斷有沒有該事務是否回滾過。

這裡,我們假設需要在凍結金額的時候進行事務操作。為了實現空回滾,防止業務懸掛,以及冪等性要求。我們必須在資料庫記錄凍結金額的同時,記錄當前事務 ID 和執行狀態,凍結金額表如下設計:

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 '事務狀態, O:try, 1:confirm, 2:cancel',
  PRIMARY KEY ('xid') USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

表欄位設計完成後,執行如下的業務邏輯即可避免空回滾和業務懸掛。

image.png

3.2 TCC 優缺點

優點:

  1. 一階段直接完成事務提交,釋放資料庫資源,效能比較好;
  2. 相比 AT,無需生成快照和使用全域性鎖,效能最好;
  3. 不依賴資料庫事務,依賴補償操作,可用於非事務型資料庫。

缺點:

  1. 程式碼入侵,每個階段都需要編寫對應的業務程式碼;
  2. 軟狀態,屬於最終一致;
  3. 需要考慮ConfirmCancel的失敗情況,做好冪等處理。

4. Saga 模式

關於什麼是 Saga 模式及原理,詳情見什麼是分散式事務

Saga 模式是 Seata 提供的長事務解決方案。也分為兩個階段:

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

image.png

優點:

  1. 事務參與者可以基於事件驅動實現非同步呼叫,吞吐高;
  2. 一階段直接提交本地事務,無鎖,效能好;
  3. 程式碼入侵較 TCC 低,實現簡單。

缺點:

  1. 軟狀態持續時間不確定,時效性差;
  2. 沒有鎖和事務隔離,可能會有髒寫。

三、程式碼實現

具體程式碼使用,可參考 Seata 官方文件

這裡需要注意每個模式需要的準備工作不同,如AT模式下就需要準備如下幾點:

  1. lock_table 匯入 Seata 資料庫,就是 TC 服務關聯的資料庫;
  2. undo_log 匯入業務相關的資料庫;
  3. 修改事務模式。

四、對比總結

對比維度 XA AT TCC Saga
資料一致性 強一致性 弱一致性 最終一致性 最終一致性
隔離性 完全隔離 基於全域性鎖 基於資源預留 無隔離
程式碼入侵
效能 較低
依賴本地事務 依賴 依賴 不依賴 不依賴
場景 一致性,隔離性要求高的業務場景。 繼續關係型資料庫的大多分散式事務的場景均適合。 對效能要求高,且有非關係型資料庫參與的事務。 業務流程較長,資料時效性要求較低的場景。

參考:

[1] B站黑馬. Seata從入門到進階.

相關文章