及時獲取有趣有料的技術文章
本地事務
事務 Transaction 由一組 SQL 組成,具有四個 ACID 特性:
Atomicity:原子性,構成事務的一組SQL,要麼全部生效,要麼全不生效,不會出現部分生效的情況。Consistency:一致性,資料庫經過事務操作後從一種狀態轉變為另一個狀態。可以說原子性是從行為上描述,而一致性是從結果上描述。Isolation:隔離性,事務操作的數據對象相對於其他事務操作的數據對象相互隔離,互不影響。Durability:持久性,事務提交後,其結果就是永久性的,即使發生宕機(非磁碟損壞)。
事務實現
對於 MySQL 資料庫(InnoDB 存儲引擎)而言,隔離性是通過不同粒度的鎖機制來實現事務間的隔離。
原子性、一致性和持久性通過 redo log 重做日誌和 undo log 回滾日誌來保證的。
redo log:當資料庫對數據做修改的時候,需要把數據頁從磁碟讀到 buffer pool 中,然後在 buffer pool 中進行修改。
那麼這個時候 buffer pool 中的數據頁就與磁碟上的數據頁內容不一致,稱 buffer pool 的數據頁為 dirty page 髒數據。
如果這個時候發生非正常的 DB 服務重啟,那麼這些數據還沒在內存,並沒有同步到磁碟文件中(注意,同步到磁碟文件是個隨機 IO),也就是會發生數據丟失。
如果這個時候,能夠在有一個文件,當 buffer pool 中的 data page 變更結束後,把相應修改記錄記錄到這個文件(注意,記錄日誌是順序 IO)。
那麼當 DB 服務發生 crash 的情況,恢復 DB 的時候,也可以根據這個文件的記錄內容,重新應用到磁碟文件,數據保持一致。
undo log:undo 日誌用於存放數據被修改前的值,如果修改出現異常,可以使用 undo 日誌來實現回滾操作,保證事務的一致性。另外 InnoDB MVCC 事務特性也是基於 undo 日誌實現的。
undo 日誌分為 insert undo log(insert 語句產生的日誌,事務提交後直接刪除)和 update undo log(delete 和 update 語句產生的日誌,由於該 undo log 可能提供 MVVC 機制使用,所以不能再事務提交時刪除)。
問題引入
CAP 理論
CAP 原則又稱 CAP 定理,指的是在一個分布式系統中的一致性(Consistency)、可用性(Availability)、分區容錯性(Partition tolerance)。
CAP 原則指的是,這三個要素最多只能同時實現兩點,不可能三者兼顧。但由於在分布式系統中,分區容錯性必然存在,所以只能在一致性和可用性妥協。
傳統的 DBMS,如 MySQL 其實 CA 組合,在主從架構下,讀寫分離的情況下,是犧牲一定的一致性的(主從延遲)。
Base 理論:
base available,基本可用,分布式系統在出現故障時,允許損失部分可用功能,保證核心功能可用。soft state,軟狀態,允許系統中存在中間狀態,這個狀態不影響系統可用性。eventually consistent,最終一致性,系統的中間狀態經過短暫的時間後到達一致狀態。
如何解決
場景舉例
考慮這樣一種業務場景,系統 A 調用系統 B 的退款服務進行退款,系統 A 更改內部退款狀態,接著調用系統 C 的簡訊服務通知用戶。
在這樣的一個場景下,由於網絡不可靠的必然存在,存在 A、B、C 三個系統之間一致性的問題。
本地表
針對上述場景,設計兩張表:退款記錄表和簡訊發送記錄表以及相應的補償 Job。
具體實現過程:
新增退款記錄表,狀態為處理中。調用系統 B 的退款服務進行退款。更新退款記錄狀態為對應的狀態(成功/失敗)。如果退款成功,則新增簡訊發送記錄,記錄狀態為待發送。調用系統 C 的簡訊服務,發送簡訊。更新簡訊發送記錄為已發送。
退款補償 Job,查詢退款記錄表中處理中的記錄,調用系統 B 的退款服務,退款成功處理:
新增簡訊發送記錄,記錄狀態為待發送。調用系統 C 的簡訊服務,發送簡訊。更新簡訊發送記錄為已發送。
簡訊通知補償 Job,查詢簡訊發送記錄中待發送的記錄,調用系統 C 的簡訊服務:
調用系統 C 的簡訊服務,發送簡訊。更新簡訊發送記錄為已發送。
注意:
系統 B 和系統 C 需要根據調用方傳的 uuid 支持冪等。系統 A、B、C 會出現短暫的不一致,但最終一致。
事務消息
可以將其視為兩階段提交消息實現,以確保分布式系統中的最終一致性。事務性消息可確保本地事務的執行和消息的發送可以原子方式執行。
但是由於事務消息異步的特性,調用方拿不到消費方的處理結果,適用於不關心對方的返回結果/對方負責保證處理成功。
針對上述場景,增加兩個事務消息的方式解決一致性問題,系統 A 通過發送事務消息的方式與系統 B 和系統 C 進行交互。
具體實現過程:
發送退款的事務消息。新增退款記錄,狀態為:處理中。Commit 退款事務消息。
提供 MQ 事務 callback:
退款 callback 查詢:有退款記錄且為處理中則 Commit;其他則 Rollback。發送簡訊 callback 查詢:有退款記錄且成功則 Commit;其他則 Rollback。
退款同步 Job,查詢退款記錄表中處理中的記錄,調用系統 B 的退款查詢接口同步狀態,其中退款成功處理:
發送簡訊的事務消息更新退款記錄為成功Commit 簡訊事務消息
相關理論
二階段提交
二階段提交是解決分布式事務問題的重要理論基礎,但也存在著明顯的問題:
阻塞問題,參與者將協議消息發送給協調器後,它將阻塞直到收到提交或回滾,只能依賴協調者的超時機制。協調者單點問題,如果協調者出現故障,則某些參與者將一直無法收到提交或回滾的消息。
為了解決二階段提交出現的問題,又有了三階段提交(Three-phase commit):
解決阻塞問題:將 2PC 中的第一階段一分為二,提供了一個 CanCommit 階段,此階段並不鎖定資源,這樣可以大幅降低阻塞概率。解決單點問題:在參與者這邊也引入了超時機制。
DTP Model
X/Open 分布式事務處理 DTP(Distributed Transaction Processing)模型是一種軟體體系架構,已經成為事實上的事務模型組件的行為標準。
它允許多個應用程式共享由多個資源管理器提供的資源,並允許其工作被協調為全局事務:
ApplicationProgram(AP),應用程式定義了事務邊界並指定構成事務的操作。ResourceManager(RM),資源管理器用來管理我們需要訪問的共享資源,我們可以將它理解為關係資料庫、文件存儲系統、消息隊列、印表機等。TransactionManager(TM),事務管理器是一個獨立的組件,他為事務分配標識符並監視事務的執行情況,負責事務完成和故障恢復。CommunicationResourceManager(CRM),通信資源管理器控制一個或多個 TM domain 之間分布式應用的通信。
XA Specification:XA 規範是 X/Open 關於分布式事務處理(DTP)的規範。規範描述了全局的事務管理器與局部的資源管理器之間的接口。
XA 規範的目的是允許多個資源(如資料庫,應用伺服器,消息隊列,等等)在同一事務中訪問,這樣可以使 ACID 屬性跨越應用程式而保持有效。
XA 使用兩階段提交來保證所有資源同時提交或回滾任何特定的事務。
XA 規範描述了資源管理器要支持事務性訪問所必需做的事情。
TCC
Saga
在 Saga 模式下,分布式事務內有多個參與者,每一個參與者都是一個衝正補償服務,需要用戶根據業務場景實現其正向操作和逆向回滾操作。
分布式事務執行過程中,依次執行各參與者的正向操作,如果所有正向操作均執行成功,那麼分布式事務提交。
如果任何一個正向操作執行失敗,那麼分布式事務會去退回去執行前面各參與者的逆向回滾操作,回滾已提交的參與者,使分布式事務回到初始狀態。
Saga 模式下分布式事務通常是由事件驅動的,各個參與者之間是異步執行的,Saga 模式是一種長事務解決方案。
Saga 模式的優勢是:
一階段提交本地資料庫事務,無鎖,高性能。參與者可以採用事務驅動異步執行,高吞吐。補償服務即正向服務的「反向」,易於理解,易於實現。
缺點:Saga 模式由於一階段已經提交本地資料庫事務,且沒有進行「預留」動作,所以不能保證隔離性。
開源項目
Seata
Seata 是一款開源的分布式事務解決方案,致力於在微服務架構下提供高性能和簡單易用的分布式事務服務。支持 AT、TCC、Saga、XA 四種模式,對微服務框架支持友好。
如下圖所示,Seata 中有三大模塊,分別是 TM、RM 和 TC。其中 TM 和 RM 是作為 Seata 的客戶端與業務系統集成在一起,TC 作為 Seata 的服務端獨立部署:
TC:事務協調者,維護全局和分支事務的狀態,驅動全局事務提交或回滾。TM:事務管理器,定義全局事務的範圍:開始全局事務、提交或回滾全局事務。RM:資源管理器,管理分支事務處理的資源,與 TC 交談以註冊分支事務和報告分支事務的狀態,並驅動分支事務提交或回滾。
在 Seata 中,分布式事務的執行流程:
TM 開啟分布式事務(TM 向 TC 註冊全局事務記錄)。按業務場景,編排資料庫、服務等事務內資源(RM 向 TC 匯報資源準備狀態 )。TM 結束分布式事務,事務一階段結束(TM 通知 TC 提交/回滾分布式事務)。TC 匯總事務信息,決定分布式事務是提交還是回滾。TC 通知所有 RM 提交/回滾資源,事務二階段結束。
①AT 模式
AT 模式是一種無侵入的分布式事務解決方案。
在 AT 模式下,用戶只需關注自己的「業務 SQL」,用戶的 「業務 SQL」 作為一階段,Seata 框架會自動生成事務的二階段提交和回滾操作。
一階段:業務數據和回滾日誌記錄在同一個本地事務中提交,釋放本地鎖和連接資源。二階段:提交異步化,非常快速地完成。回滾通過一階段的回滾日誌進行反向補償。
在一階段,Seata 會攔截「業務 SQL」,首先解析 SQL 語義,找到「業務 SQL」要更新的業務數據,在業務數據被更新前,將其保存成「before image」,然後執行「業務 SQL」更新業務數據,在業務數據更新之後,再將其保存成「after image」,最後生成行鎖。
以上操作全部在一個資料庫事務內完成,這樣保證了一階段操作的原子性。
②TCC 模式
一個分布式的全局事務,整體是兩階段提交的模型。全局事務是由若干分支事務組成的,分支事務要滿足兩階段提交的模型要求,即需要每個分支事務都具備自己的:
一階段 prepare 行為。二階段 commit 或 rollback 行為。
TCC 模式,不依賴於底層數據資源的事務支持:
一階段 prepare 行為:調用自定義的 prepare 邏輯。二階段 commit 行為:調用自定義的 commit 邏輯。二階段 rollback 行為:調用自定義的 rollback 邏輯。
所謂 TCC 模式,是指支持把 自定義 的分支事務納入到全局事務的管理中。
③Saga 模式
目前 Seata 提供的 Saga 模式是基於狀態機引擎來實現的,機制是:
通過狀態圖來定義服務調用的流程並生成 json 狀態語言定義文件。狀態圖中一個節點可以是調用一個服務,節點可以配置它的補償節點。狀態圖 json 由狀態機引擎驅動執行,當出現異常時狀態引擎反向執行已成功節點對應的補償節點將事務回滾 (異常發生時是否進行補償也可由用戶自定義決定)。可以實現服務編排需求,支持單項選擇、並發、子流程、參數轉換、參數映射、服務執行狀態判斷、異常捕獲等功能。
狀態機引擎原理:
圖中的狀態圖是先執行 stateA,再執行 stateB,然後執行 stateC。"狀態"的執行是基於事件驅動的模型,stateA 執行完成後,會產生路由消息放入 EventQueue,事件消費端從 EventQueue 取出消息,執行 stateB。在整個狀態機啟動時會調用 Seata Server 開啟分布式事務,並生產 xid,然後記錄"狀態機實例"啟動事件到本地資料庫。當執行到一個"狀態"時會調用 Seata Server 註冊分支事務,並生產 branchId,然後記錄"狀態實例"開始執行事件到本地資料庫。當一個"狀態"執行完成後會記錄"狀態實例"執行結束事件到本地資料庫,然後調用 Seata Server 上報分支事務的狀態。當整個狀態機執行完成, 會記錄"狀態機實例"執行完成事件到本地資料庫,然後調用 Seata Server 提交或回滾分布式事務。
作者:VectorJin
出處:https://juejin.im/post/5e066c9ff265da33b0718f89