本地事務
事務Transaction由一組SQL組成,具有四個ACID特性
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) 資源管理器用來管理我們需要訪問的共享資源,我們可以將它理解為關聯式資料庫、檔案儲存系統、訊息佇列、印表機等
TransactionManagger(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提交或回滾分散式事務