最近看了幾篇有關于分布式事務的博文,做了一下筆記,并總結出這篇文章。
圖片來自 Pexels
數據庫事務
數據庫事務(簡稱:事務),是數據庫管理系統執行過程中的一個邏輯單位,由一個有限的數據庫操作序列構成。
這些操作要么全部執行,要么全部不執行,是一個不可分割的工作單位。
數據庫事務的幾個典型特性:
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔離性(Isolation)
- 持久性(Durabilily)
簡稱就是 ACID:
- 原子性:事務作為一個整體被執行,包含在其中的對數據庫的操作要么全部被執行,要么都不執行。
- 一致性:指在事務開始之前和事務結束以后,數據不會被破壞,假如 A 賬戶給 B 賬戶轉 10 塊錢,不管成功與否,A 和 B 的總金額是不變的。
- 隔離性:多個事務并發訪問時,事務之間是相互隔離的,即一個事務不影響其它事務運行效果。簡言之,就是事務之間是進水不犯河水的。
- 持久性:表示事務完成以后,該事務對數據庫所作的操作更改,將持久地保存在數據庫之中。
事務的實現原理
本地事務
傳統的單服務器,單關系型數據庫下的事務,就是本地事務。本地事務由資源管理器管理,JDBC 事務就是一個非常典型的本地事務。
事務日志
InnoDB 事務日志包括 redo log 和 undo log。
redo log(重做日志):通常是物理日志,記錄的是數據頁的物理修改,而不是某一行或某幾行修改成怎樣,它用來恢復提交后的物理數據頁。
undo log(回滾日志):是邏輯日志,和 redo log 記錄物理日志的不一樣。
可以這樣認為,當 delete 一條記錄時,undo log 中會記錄一條對應的 insert 記錄,當 update 一條記錄時,它記錄一條對應相反的 update 記錄。
事務 ACID 特性的實現思想:
- 原子性:是使用 undo log 來實現的,如果事務執行過程中出錯或者用戶執行了 rollback,系統通過 undo log 日志返回事務開始的狀態。
- 持久性:使用 redo log 來實現,只要 redo log 日志持久化了,當系統崩潰,即可通過 redo log 把數據恢復。
- 隔離性:通過鎖以及 MVCC,使事務相互隔離開。
- 一致性:通過回滾、恢復,以及并發情況下的隔離性,從而實現一致性。
分布式事務
分布式事務就是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分別位于不同的分布式系統的不同節點之上。
簡單來說,分布式事務指的就是分布式系統中的事務,它的存在就是為了保證不同數據庫節點的數據一致性。
為什么需要分布式事務?接下來分兩方面闡述:
微服務架構下的分布式事務
隨著互聯網的快速發展,輕盈且功能劃分明確的微服務,登上了歷史舞臺。
比如,一個用戶下訂單,購買直播禮物的服務,被拆分成三個 service,分別是金幣服務(coinService),下訂單服務(orderService)、禮物服務(giftService)。
這些服務都部署在不同的機器上(節點),對應的數據庫(金幣數據庫、訂單數據庫、禮物數據庫)也在不同節點上。
用戶下單購買禮物,禮物數據庫、金幣數據庫、訂單數據庫在不同節點上,用本地事務是不可以的,那么如何保證不同數據庫(節點)上的數據一致性呢?這就需要分布式事務啦!
分庫分表下的分布式事務
隨著業務的發展,數據庫的數據日益龐大,超過千萬級別的數據,我們就需要對它分庫分表(以前公司是用 Mycat 分庫分表,后來用 Sharding-JDBC)。
一分庫,數據又分布在不同節點上啦,比如有的在深圳機房,有的在北京機房~你再想用本地事務去保證,已經無動于衷啦~還是需要分布式事務啦。
比如 A 轉 10 塊給 B,A 的賬戶數據是在北京機房,B 的賬戶數據是在深圳機房。
流程如下:
CAP 理論&BASE 理論
學習分布式事務,當然需要了解 CAP 理論和BASE 理論。
CAP 理論
CAP 理論作為分布式系統的基礎理論,指的是在一個分布式系統中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區容錯性),這三個要素最多只能同時實現兩點。
一致性(C,Consistency):一致性是指數據在多個副本之間能否保持一致的特性。
例如一個數據在某個分區節點更新之后,在其他分區節點讀出來的數據也是更新之后的數據。
可用性(A:Availability):可用性是指系統提供的服務必須一直處于可用的狀態,對于用戶的每一個操作請求總是能夠在有限的時間內返回結果。這里的重點是"有限時間內"和"返回結果"。
分區容錯性(P,Partition tolerance):分布式系統在遇到任何網絡分區故障的時候,仍然需要能夠保證對外提供滿足一致性和可用性的服務。
BASE 理論
BASE 理論, 是對 CAP 中 AP 的一個擴展,對于我們的業務系統,我們考慮犧牲一致性來換取系統的可用性和分區容錯性。
BASE 是 Basically Available(基本可用),Soft State(軟狀態)和 Eventually Consistent(最終一致性)三個短語的縮寫。
Basically Available:基本可用。通過支持局部故障而不是系統全局故障來實現的。
如將用戶分區在 5 個數據庫服務器上,一個用戶數據庫的故障只影響這臺特定主機那 20% 的用戶,其他用戶不受影響。
Soft State:軟狀態。狀態可以有一段時間不同步。
Eventually Consistent:最終一致。最終數據是一致的就可以了,而不是時時保持強一致。
分布式事務的幾種解決方案
分布式事務解決方案主要有以下這幾種:
- 2PC(二階段提交)方案
- TCC(Try、Confirm、Cancel)
- 本地消息表
- 最大努力通知
- Saga 事務
二階段提交方案
二階段提交方案是常用的分布式事務解決方案。事務的提交分為兩個階段:準備階段和提交執行方案。
二階段提交成功的情況:
- 準備階段,事務管理器向每個資源管理器發送準備消息,如果資源管理器的本地事務操作執行成功,則返回成功。
- 提交執行階段,如果事務管理器收到了所有資源管理器回復的成功消息,則向每個資源管理器發送提交消息,RM 根據 TM 的指令執行提交。
如圖:
二階段提交失敗的情況:
- 準備階段,事務管理器向每個資源管理器發送準備消息,如果資源管理器的本地事務操作執行成功,則返回成功,如果執行失敗,則返回失敗。
- 提交執行階段,如果事務管理器收到了任何一個資源管理器失敗的消息,則向每個資源管理器發送回滾消息。
資源管理器根據事務管理器的指令回滾本地事務操作,釋放所有事務處理過程中使用的鎖資源 。
2PC 方案實現起來簡單,成本較低,但是主要有以下缺點:
- 單點問題:如果事務管理器出現故障,資源管理器將一直處于鎖定狀態。
- 性能問題:所有資源管理器在事務提交階段處于同步阻塞狀態,占用系統資源,一直到提交完成,才釋放資源,容易導致性能瓶頸。
- 數據一致性問題:如果有的資源管理器收到提交的消息,有的沒收到,那么會導致數據不一致問題。
TCC(補償機制)
TCC 采用了補償機制,其核心思想是:針對每個操作,都要注冊一個與其對應的確認和補償(撤銷)操作。
TCC(Try-Confirm-Cancel)是通過對業務邏輯的分解來實現分布式事務。
針對一個具體的業務服務,TCC 分布式事務模型需要業務系統都實現一下三段邏輯:
- Try 階段:嘗試去執行,完成所有業務的一致性檢查,預留必須的業務資源。
- Confirm 階段:該階段對業務進行確認提交,不做任何檢查,因為 Try 階段已經檢查過了,默認 Confirm 階段是不會出錯的。
- Cancel 階段:若業務執行失敗,則進入該階段,它會釋放 Try 階段占用的所有業務資源,并回滾 Confirm 階段執行的所有操作。
TCC 分布式事務模型包括如下三部分:
- 主業務服務:主業務服務負責發起并完成整個業務活動。
- 從業務服務:從業務服務是整個業務活動的參與方,實現 Try、Confirm、Cancel 操作,供主業務服務調用。
- 業務活動管理器:業務活動管理器管理控制整個業務活動,包括記錄事務狀態,調用從業務服務的 Confirm 操作,調用從業務服務的 Cancel 操作等。
下面再拿用戶下單購買禮物作為例子來模擬 TCC 實現分布式事務的過程:假設用戶 A 余額為 100 金幣,擁有的禮物為 5 朵。A 花了 10 個金幣,下訂單,購買 10 朵玫瑰。余額、訂單、禮物都在不同數據庫。
TCC 的 Try 階段:
- 生成一條訂單記錄,訂單狀態為待確認。
- 將用戶 A 的賬戶金幣中余額更新為 90,凍結金幣為 10(預留業務資源)。
- 將用戶的禮物數量為 5,預增加數量為 10。
- Try 成功之后,便進入 Confirm 階段。
- Try 過程發生任何異常,均進入 Cancel 階段。
TCC 的 Confirm 階段:
- 訂單狀態更新為已支付。
- 更新用戶余額為 90,可凍結為 0。
- 用戶禮物數量更新為 15,預增加為 0。
- Confirm 過程發生任何異常,均進入 Cancel 階段。
- Confirm 過程執行成功,則該事務結束。
TCC 的 Cancel 階段:
- 修改訂單狀態為已取消。
- 更新用戶余額回 100。
- 更新用戶禮物數量為 5。
TCC 方案讓應用可以自定義數據庫操作的粒度,降低了鎖沖突,可以提升性能。
但是也有以下缺點:
- 應用侵入性強,Try、Confirm、Cancel 三個階段都需要業務邏輯實現。
- 需要根據網絡、系統故障等不同失敗原因實現不同的回滾策略,實現難度大,一般借助 TCC 開源框架,ByteTCC,TCC-transaction,Himly。
本地消息表
eBay 最初提出本地消息表這個方案,來解決分布式事務問題。業界目前使用這種方案是比較多的,它的核心思想就是將分布式事務拆分成本地事務進行處理。
可以看一下基本的實現流程圖:
基本實現思路如下。
發送消息方:
- 需要有一個消息表,記錄著消息狀態相關信息。
- 業務數據和消息表在同一個數據庫,即要保證它倆在同一個本地事務。
- 在本地事務中處理完業務數據和寫消息表操作后,通過寫消息到 MQ 消息隊列。
- 消息會發到消息消費方,如果發送失敗,即進行重試。
消息消費方:
- 處理消息隊列中的消息,完成自己的業務邏輯。
- 此時如果本地事務處理成功,則表明已經處理成功了。
- 如果本地事務處理失敗,那么就會重試執行。
- 如果是業務上面的失敗,給消息生產方發送一個業務補償消息,通知進行回滾等操作。
生產方和消費方定時掃描本地消息表,把還沒處理完成的消息或者失敗的消息再發送一遍。如果有靠譜的自動對賬補賬邏輯,這種方案還是非常實用的。
優缺點:該方案的優點是很好地解決了分布式事務問題,實現了最終一致性。缺點是消息表會耦合到業務系統中。
最大努力通知
什么是最大通知?最大努力通知也是一種分布式事務解決方案。
下面是企業網銀轉賬一個例子:
- 企業網銀系統調用前置接口,跳轉到轉賬頁。
- 企業網銀調用轉賬系統接口。
- 轉賬系統完成轉賬處理,向企業網銀系統發起轉賬結果通知,若通知失敗,則轉賬系統按策略進行重復通知。
- 企業網銀系統未接收到通知,會主動調用轉賬系統的接口查詢轉賬結果。
- 轉賬系統會遇到退匯等情況,會定時回來對賬。
最大努力通知方案的目標,就是發起通知方通過一定的機制,最大努力將業務處理結果通知到接收方。
最大努力通知實現機制如下:
最大努力通知解決方案:要實現最大努力通知,可以采用 MQ 的 ACK 機制。
方案如下:
- 發起方將通知發給 MQ。
- 接收通知方監聽 MQ 消息。
- 接收通知方收到消息后,處理完業務,回應 ACK。
- 接收通知方若沒有回應 ACK,則 MQ 會間隔 1min、5min、10min 等重復通知。
- 接受通知方可用消息校對接口,保證消息的一致性。
轉賬業務實現流程圖:
交互流程如下:
- 用戶請求轉賬系統進行轉賬。
- 轉賬系統完成轉賬,將轉賬結果發給 MQ。
- 企業網銀系統監聽 MQ,接收轉賬結果通知,如果接收不到消息,MQ 會重復發送通知。接收到轉賬結果,更新轉賬狀態。
- 企業網銀系統也可以主動查詢轉賬系統的轉賬結果查詢接口,更新轉賬狀態。
Saga 事務
Saga 事務由普林斯頓大學的 Hector Garcia-Molina 和 Kenneth Salem 提出。
其核心思想是將長事務拆分為多個本地短事務,由 Saga 事務協調器協調,如果正常結束那就正常完成,如果某個步驟失敗,則根據相反順序一次調用補償操作。
Saga 簡介:
- Saga = Long Live Transaction(LLT,長活事務)。
- LLT = T1 + T2 + T3 + ... + Ti(Ti 為本地短事務)。
- 每個本地事務 Ti 有對應的補償 Ci。
Saga 的執行順序:
- 正常情況:T1 T2 T3 ... Tn
- 異常情況:T1 T2 T3 C3 C2 C1
Saga 兩種恢復策略:
- 向后恢復,如果任意本地子事務失敗,補償已完成的事務。如異常情況的執行順序 T1 T2 Ti Ci C2 C1。
- 向前恢復,即重試失敗的事務,假設最后每個子事務都會成功。執行順序:T1,T2,...,Tj(失敗),Tj(重試),...,Tn。
舉個例子,假設用戶下訂單,花 10 塊錢購買了 10 多玫瑰,則有:
- T1=下訂單
- T2=扣用戶 10 塊錢
- T3=用戶加 10 朵玫瑰
- T4=庫存減 10 朵玫瑰
- C1=取消訂單
- C2=給用戶加 10 塊錢
- C3=用戶減 10 朵玫瑰
- C4=庫存加 10 朵玫瑰
假設事務執行到 T4 發生異?;貪L,在 C4 的要把玫瑰給庫存加回去的時候,發現用戶的玫瑰都用掉了,這是 Saga 的一個缺點,由于事務之間沒有隔離性導致的問題。
可以通過以下方案解決這個問題:
- 在應用層面加入邏輯鎖的邏輯。
- Session層面隔離來保證串行化操作。
- 業務層面采用預先凍結資金的方式隔離此部分資金。
- 業務操作過程中通過及時讀取當前狀態的方式獲取更新。
參考與感謝:
- 干貨 | 一篇文章帶你學習分布式事務
- 再有人問你分布式事務,把這篇扔給他
- 聊聊分布式事務,再說說解決方案
- MySQL事務實現原理
- 詳細分析 MySQL 事務日志(redo log 和 undo log)
- 《Saga 分布式事務解決?案與實踐》
- 分布式事務解決方案之最大努力通知