微服務架構下的分布式事務解決方案
隨著業務的快速發展、業務復雜度越來越高,傳統單體應用逐漸暴露出了一些問題,例如開發效率低、可維護性差、架構擴展性差、部署不靈活、健壯性差等等。
微服務架構是一個分布式的系統,按業務進行劃分為獨立的服務單元,解決單體系統的不足,同時也滿足越來越復雜的業務需求。每個微服務僅關注于完成一件任務并很好地完成該任務。
微服務架構的特點
微服務架構的優勢非常明顯,在近些年迅猛發展。
- 將復雜的業務拆分成多個小的業務,能夠達到更好的業務復用,有利于人員組織分工
- 服務獨立部署,獨立擴容,每個服務的修改和部署對其他服務沒有影響
- 每個服務可以根據業務場景選取合適的編程語言和數據庫
微服務有以上的優勢,但是微服務也帶來不少的新問題,例如:
- 服務數量眾多,其測試、部署、監控等都變的更加困難。
- 單體應用拆分為分布式系統后,進程間的通訊機制和故障處理措施變的更加復雜
- 系統微服務化后,原先是一個服務內部的本地數據庫事務,被拆到了多個服務,需要在分布式環境下保證事務的一致性
上述的各項問題中,1、2都可以通過近幾年涌現的各項微服務技術解決,例如Kubernetes提供了服務發現、服務治理等。因此分布式事務已經成為微服務落地最大的阻礙,也是最具挑戰性的一個技術難題。下面將深入和大家探討微服務架構下,分布式事務的解決方案。
從本地事務到分布式事務的演變
我們那轉賬作為例子,A需要轉100元給B,那么需要給A的余額-100元,給B的余額+100元,單體模式下,可以通過本地事務解決。
本地事務
把多條語句作為一個整體進行操作的功能,被稱為數據庫_事務_。數據庫事務可以確保該事務范圍內的所有操作都可以全部成功或者全部失敗。如果事務失敗,那么效果就和沒有執行這些SQL一樣,不會對數據庫數據有任何改動。
數據庫事務具有ACID這4個特性:
- A:Atomic,原子性,將所有SQL作為原子工作單元執行,要么全部執行,要么全部不執行;
- C:Consistent,一致性,事務完成后,所有數據的狀態都是一致的,即A賬戶只要減去了100,B賬戶則必定加上了100;
- I:Isolation,隔離性,如果有多個事務并發執行,每個事務作出的修改必須與其他事務隔離;
- D:Duration,持久性,即事務完成后,對數據庫數據的修改被持久化存儲。
分布式事務典型場景
銀行跨行轉賬業務是一個典型分布式事務場景,假設A需要跨行轉賬給B,那么就涉及兩個銀行的數據,無法通過一個數據庫的本地事務保證轉賬的正確性,只能夠通過分布式事務來解決。
將服務拆分為微服務時,遇見類似需要分布式事務的場景非常多,雖然微服務最佳實踐建議盡量規避分布式事務,但是在很多業務場景,分布式事務是一個繞不開的技術問題。
分布式事務方案
分布式事務模式常見的有XA、TCC、SAGA、可靠消息,下面進行簡短的介紹
兩階段提交/XA
XA是由X/Open組織提出的分布式事務的規范,XA規范主要定義了(全局)事務管理器(TM)和(局部)資源管理器(RM)之間的接口。本地的數據庫如MySQL在XA中扮演的是RM角色。
XA一共分為兩階段:
第一階段(prepare):即所有的參與者RM準備執行事務并鎖住需要的資源。參與者ready時,向TM報告已準備就緒。
第二階段(commit/rollback):當事務管理者(TM)確認所有參與者(RM)都ready后,向所有參與者發送commit命令。
目前主流的數據庫基本都支持XA事務,包括MySQL、Oracle、SQLServer、PostgreSQL。
一個成功完成的XA事務時序圖如下:
TCC事務方案
TCC方案其實是XA提交的一種改進。其將整個業務邏輯的每個分支顯式的分成了Try、Confirm、Cancel三個操作。Try部分完成業務的準備工作,confirm部分完成業務的提交,cancel部分完成事務的回滾。
事務開始時,業務應用會向事務協調器注冊啟動事務。之后業務應用會調用所有服務的try接口,完成一階段準備。之后事務協調器會根據try接口返回情況,決定調用confirm接口或者cancel接口。如果接口調用失敗,會進行重試。
一個成功完成的TCC事務時序圖如下:
SAGA事務方案
Saga和TCC一樣,也是最終一致性事務、柔性事務。Saga的本質就是把一個長事務分隔成一個個小的事務,每個事務都包含一個執行模塊和補償模塊。
Saga沒有try,直接提交事務,可能出現臟讀的情況,在某些對一致性要求較高的場景下,是不可接受的。
在啟動一個Saga事務時,事務管理器會告訴第一個Saga參與者,也就是子事務,去執行本地事務。事務完成之后Saga的會按照執行順序調用Saga的下一個參與的子事務。這個過程會一直持續到Saga事務執行完畢。
如果在執行子事務的過程中遇到子事務對應的本地事務失敗,則Saga會按照相反的順序執行補償事務。
一個成功完成的SAGA事務時序圖如下:
可靠消息
消息一致性方案是通過消息中間件保證上下游應用數據操作的一致性。基本思路是將本地操作和發送消息放在一個本地事務中,保證本地操作和消息發送要么兩者都成功或者都失敗。下游應用向消息系統訂閱該消息,收到消息后執行相應操作。
RocketMQ 提供了典型的可靠消息接口,可以參考。
分布式事務開源項目
當前的分布式事務領域,有java語言的開源項目,以seata為代表。在非Java領域,Go語言的 DTM 是代表項目。 DTM 支持XA、TCC、SAGA、可靠消息,架構圖如下:
圖中的各角色與XA模型中的角色模型一致,分別解釋如下:
- AP應用程序(定義和提交事務,當前支持Go語言,即將支持Nodejs、Python、PHP、Rust等)
- RM資源管理器(負責管理本地事務,不限語言,只要提供了http相關的接口即可)
- TM事務管理器(DTM,協調全局事務,進行提交以及回滾)
在上述的架構圖中,AP通過DTM提供的分布式事務接口,與RM和TM交互,對現有的微服務,侵入很小。
另外在實際的業務中,AP和RM角色可能會有重疊,例如TCC模式下,AP可能有自己的本地事務,也會注冊并調用其他事務分支。