
微服務倡導将複雜的單體應用拆分為若幹個功能簡單、松耦合的服務,這樣可以降低開發難度、增強擴充性、便于靈活開發。目前被越來越多的開發者推崇,系統微服務化後,一個看似簡單的功能,内部可能需要調用多個服務并操作多個資料庫實作,服務調用的分布式事務問題變的非常突出。分布式事務已經成為微服務落地最大的阻礙,也是最具挑戰性的一個技術難題。
- 什麼是微服務化帶來的分布式事務問題?
首先,設想一個傳統的單體應用(Monolithic App),通過 3 個 Module,在同一個資料源上更新資料來完成一項業務。
很自然的,整個業務過程的資料一緻性由本地事務來保證。
随着業務需求和架構的變化,單體應用被拆分為微服務:原來的 3 個 Module 被拆分為 3 個獨立的服務,分别使用獨立的資料源(Pattern: Database per service)。業務過程将由 3 個服務的調用來完成。
此時,每一個服務内部的資料一緻性仍有本地事務來保證。而整個業務層面的全局資料一緻性要如何保障呢?這就是微服務架構下面臨的,典型的分布式事務需求:我們需要一個分布式事務的解決方案保障業務全局的資料一緻性。
- Fescar 的發展曆程
阿裡是國内最早一批進行應用分布式(微服務化)改造的企業,是以很早就遇到微服務架構下的分布式事務問題。
2014 年,阿裡中間件團隊釋出 TXC(Taobao Transaction Constructor),為集團内應用提供分布式事務服務。
2016 年,TXC 經過産品化改造,以 GTS(Global Transaction Service)的身份登陸阿裡雲,成為當時業界唯一一款雲上分布式事務産品,在阿雲裡的公有雲、專有雲解決方案中,開始服務于衆多外部客戶。
2019 年起,基于 TXC 和 GTS 的技術積累,阿裡中間件團隊發起了開源項目 Fescar(Fast & EaSy Commit And Rollback, FESCAR),和社群一起建設這個分布式事務解決方案。
TXC/GTS/Fescar 一脈相承,為解決微服務架構下的分布式事務問題交出了一份與衆不同的答卷。
2.1 設計初衷
高速增長的網際網路時代,快速試錯的能力對業務來說是至關重要的:
• 一方面,不應該因為技術架構上的微服務化和分布式事務支援的引入,給業務層面帶來額外的研發負擔。
• 另一方面,引入分布式事務支援的業務應該基本保持在同一量級上的性能表現,不能因為事務機制顯著拖慢業務。
基于這兩點,我們設計之初的最重要的考量就在于:
• 對業務無侵入:這裡的“侵入”是指,因為分布式事務這個技術問題的制約,要求應用在業務層面進行設計和改造。這種設計和改造往往會給應用帶來很高的研發和維護成本。我們希望把分布式事務問題在 中間件 這個層次解決掉,不要求應用在業務層面做額外的工作。
• 高性能:引入分布式事務的保障,必然會有額外的開銷,引起性能的下降。我們希望把分布式事務引入的性能損耗降到非常低的水準,讓應用不因為分布式事務的引入導緻業務的可用性受影響。
2.2 既有的解決方案為什麼不滿足?
既有的分布式事務解決方案按照對業務侵入性分為兩類,即:對業務無侵入的和對業務有侵入的。
業務無侵入的方案
既有的主流分布式事務解決方案中,對業務無侵入的隻有基于 XA 的方案,但應用 XA 方案存在 3 個方面的問題:
• 要求資料庫提供對 XA 的支援。如果遇到不支援 XA(或支援得不好,比如 MySQL 5.7 以前的版本)的資料庫,則不能使用。
• 受協定本身的限制,事務資源的鎖定周期長。長周期的資源鎖定從業務層面來看,往往是不必要的,而因為事務資源的管理器是資料庫本身,應用層無法插手。這樣形成的局面就是,基于 XA 的應用往往性能會比較差,而且很難優化。
• 已經落地的基于 XA 的分布式解決方案,都依托于重量級的應用伺服器(Tuxedo/WebLogic/WebSphere 等),這是不适用于微服務架構的。
侵入業務的方案
實際上,最初分布式事務隻有 XA 這個唯一方案。XA 是完備的,但在實踐過程中,由于種種原因(包含但不限于上面提到的 3 點)往往不得不放棄,轉而從業務層面着手來解決分布式事務問題。比如:
• 基于可靠消息的最終一緻性方案
• TCC
• Saga
都屬于這一類。這些方案的具體機制在這裡不做展開,網上這方面的論述文章非常多。總之,這些方案都要求在應用的業務層面把分布式事務技術限制考慮到設計中,通常每一個服務都需要設計實作正向和反向的幂等接口。這樣的設計限制,往往會導緻很高的研發和維護成本。
2.3 理想的方案應該是什麼樣子?
不可否認,侵入業務的分布式事務方案都經過大量實踐驗證,能有效解決問題,在各種行業的業務應用系統中起着重要作用。但回到原點來思考,這些方案的采用實際上都是迫于無奈。設想,如果基于 XA 的方案能夠不那麼重,并且能保證業務的性能需求,相信不會有人願意把分布式事務問題拿到業務層面來解決。
一個理想的分布式事務解決方案應該:像使用本地事務一樣簡單,業務邏輯隻關注業務層面的需求,不需要考慮事務機制上的限制。
- 原理和設計
我們要設計一個對業務無侵入的方案,是以從業務無侵入的 XA 方案來思考:是否可以在 XA 的基礎上演進,解決掉 XA 方案面臨的問題呢?
3.1 如何定義一個分布式事務?
首先,很自然的,我們可以把一個分布式事務了解成一個包含了若幹分支事務的全局事務。全局事務的職責是協調其下管轄的 分支事務 達成一緻,要麼一起成功送出,要麼一起失敗復原。此外,通常分支事務本身就是一個滿足 ACID 的本地事務。這是我們對分布式事務結構的基本認識,與 XA 是一緻的。
其次,與 XA 的模型類似,我們定義 3 個元件來協定分布式事務的處理過程。
• Transaction Coordinator (TC):事務協調器,維護全局事務的運作狀态,負責協調并驅動全局事務的送出或復原。
• Transaction Manager (TM):控制全局事務的邊界,負責開啟一個全局事務,并最終發起全局送出或全局復原的決議。
• Resource Manager (RM):控制分支事務,負責分支注冊、狀态彙報,并接收事務協調器的指令,驅動分支(本地)事務的送出和復原。
一個典型的分布式事務過程:
- TM 向 TC 申請開啟一個全局事務,全局事務建立成功并生成一個全局唯一的 XID。
- XID 在微服務調用鍊路的上下文中傳播。
- RM 向 TC 注冊分支事務,将其納入 XID 對應全局事務的管轄。
- TM 向 TC 發起針對 XID 的全局送出或復原決議。
- TC 排程 XID 下管轄的全部分支事務完成送出或復原請求。
至此,Fescar 的協定機制總體上看與 XA 是一緻的。
3.2 與 XA 的差别在什麼地方?
架構層次
XA 方案的 RM 實際上是在資料庫層,RM 本質上就是資料庫自身(通過提供支援 XA 的驅動程式來供應用使用)。
而 Fescar 的 RM 是以二方包的形式作為中間件層部署在應用程式這一側的,不依賴與資料庫本身對協定的支援,當然也不需要資料庫支援 XA 協定。這點對于微服務化的架構來說是非常重要的:應用層不需要為本地事務和分布式事務兩類不同場景來适配兩套不同的資料庫驅動。
這個設計,剝離了分布式事務方案對資料庫在 協定支援 上的要求。
兩階段送出
先來看一下 XA 的 2PC 過程。
無論 Phase2 的決議是 commit 還是 rollback,事務性資源的鎖都要保持到 Phase2 完成才釋放。
設想一個正常運作的業務,大機率是 90% 以上的事務最終應該是成功送出的,我們是否可以在 Phase1 就将本地事務送出呢?這樣 90% 以上的情況下,可以省去 Phase2 持鎖的時間,整體提高效率。
這個設計,在絕大多數場景減少了事務持鎖時間,進而提高了事務的并發度。
當然,你肯定會問:Phase1 即送出的情況下,Phase2 如何復原呢?
3.3 分支事務如何送出和復原?
首先,應用需要使用 Fescar 的 JDBC 資料源代理,也就是 Fescar 的 RM。
Phase1:
Fescar 的 JDBC 資料源代理通過對業務 SQL 的解析,把業務資料在更新前後的資料鏡像組織成復原日志,利用本地事務 的 ACID 特性,将業務資料的更新和復原日志的寫入在同一個 本地事務中送出。
這樣,可以保證:任何送出的業務資料的更新一定有相應的復原日志存在。
基于這樣的機制,分支的本地事務便可以在全局事務的 Phase1 送出,馬上釋放本地事務鎖定的資源。
Phase2:
如果決議是全局送出,此時分支事務此時已經完成送出,不需要同步協調處理(隻需要異步清理復原日志),Phase2 可以非常快速地完成。
如果決議是全局復原,RM 收到協調器發來的復原請求,通過 XID 和 Branch ID 找到相應的復原日志記錄,通過復原記錄生成反向的更新 SQL 并執行,以完成分支的復原。
3.4 事務傳播機制
XID 是一個全局事務的唯一辨別,事務傳播機制要做的就是把 XID 在服務調用鍊路中傳遞下去,并綁定到服務的事務上下文中,這樣,服務鍊路中的資料庫更新操作,就都會向該 XID 代表的全局事務注冊分支,納入同一個全局事務的管轄。
基于這個機制,Fescar 是可以支援任何微服務 RPC 架構的。隻要在特定架構中找到可以透明傳播 XID 的機制即可,比如,Dubbo 的 Filter + RpcContext。
對應到 Java EE 規範和 Spring 定義的事務傳播屬性,Fescar 的支援如下:
• PROPAGATION_REQUIRED:預設支援
• PROPAGATION_SUPPORTS:預設支援
• PROPAGATION_MANDATORY:應用通過 API 來實作
• PROPAGATION_REQUIRES_NEW:應用通過 API 來實作
• PROPAGATION_NOT_SUPPORTED:應用通過 API 來實作
• PROPAGATION_NEVER:應用通過 API 來實作
• PROPAGATION_REQUIRED_NESTED:不支援
3.5 隔離性
全局事務的隔離性是建立在分支事務的本地隔離級别基礎之上的。
在資料庫本地隔離級别讀已送出或以上的前提下,Fescar 設計了由事務協調器維護的 全局寫排他鎖,來保證事務間的寫隔離,将全局事務預設定義在讀未送出的隔離級别上。
我們對隔離級别的共識是:絕大部分應用在 讀已送出 的隔離級别下工作是沒有問題的。而實際上,這當中又有絕大多數的應用場景,實際上工作在讀未送出的隔離級别下同樣沒有問題。
在極端場景下,應用如果需要達到全局的 讀已送出,Fescar 也提供了相應的機制來達到目的。預設,Fescar 是工作在 讀無送出 的隔離級别下,保證絕大多數場景的高效性。
事務的 ACID 屬性在 Fescar 中的展現是一個比較複雜的話題,我們會有專門的文章來深入分析,這裡不做進一步展開。
- 适用場景分析
前文所述的 Fescar 的核心原理中有一個重要前提:分支事務中涉及的資源,必須是支援ACID 事務的 關系型資料庫。分支的送出和復原機制,都依賴于本地事務的保障。是以,如果應用使用的資料庫是不支援事務的,或根本不是關系型資料庫,就不适用。
另外,目前 Fescar 的實作還存在一些局限,比如:事務隔離級别最高支援到讀已送出的水準,SQL 的解析還不能涵蓋全部的文法等。
為了覆寫 Fescar 原生機制暫時不能支援應用場景,我們定義了另外一種工作模式。
上面介紹的 Fescar 原生工作模式稱為 AT(Automatic Transaction)模式,這種模式是對業務無侵入的。與之相應的另外一種工作模式稱為 MT(Manual Transaction)模式,這種模式下,分支事務需要應用自己來定義業務本身及送出和復原的邏輯。
4.1 分支的基本行為模式
作為全局事務一部分的分支事務,除本身的業務邏輯外,都包含 4 個與協調器互動的行為:
• 分支注冊:在分支事務的資料操作進行之前,需要向協調器注冊,把即将進行的分支事務資料操作,納入一個已經開啟的全局事務的管理中去,在分支注冊成功後,才可以進行資料操作。
• 狀态上報:在分支事務的資料操作完成後,需要向事務協調器上報其執行結果。
• 分支送出:響應協調器發出的分支事務送出的請求,完成分支送出。
• 分支復原:響應協調器發出的分支事務復原的請求,完成分支復原。
4.2 AT 模式分支的行為模式
業務邏輯不需要關注事務機制,分支與全局事務的互動過程自動進行。
4.3 MT 模式分支的行為模式
業務邏輯需要被分解為 Prepare/Commit/Rollback 3 部分,形成一個 MT 分支,加入全局事務。
MT 模式一方面是 AT 模式的補充。另外,更重要的價值在于,通過 MT 模式可以把衆多非事務性資源納入全局事務的管理中。
4.4 混合模式
因為 AT 和 MT 模式的分支從根本上行為模式是一緻的,是以可以完全相容,即,一個全局事務中,可以同時存在 AT 和 MT 的分支。這樣就可以達到全面覆寫業務場景的目的:AT 模式可以支援的,使用 AT 模式;AT 模式暫時支援不了的,用 MT 模式來替代。另外,自然的,MT 模式管理的非事務性資源也可以和支援事務的關系型資料庫資源一起,納入同一個分布式事務的管理中。
4.5 應用場景的遠景
回到我們設計的初衷:一個理想的分布式事務解決方案是不應該侵入業務的。MT 模式是在 AT 模式暫時不能完全覆寫所有場景的情況下,一個比較自然的補充方案。我們希望通過 AT 模式的不斷演進增強,逐漸擴大所支援的場景,MT 模式逐漸收斂。未來,我們會納入對 XA 的原生支援,用 XA 這種無侵入的方式來覆寫 AT 模式無法觸達的場景。
- 擴充點
5.1 微服務架構的支援
事務上下文在微服務間的傳播需要根據微服務架構本身的機制,訂制最優的,對應用層透明的解決方案。有興趣在這方面共建的開發者可以參考内置的對 Dubbo 的支援方案,來實作對其他微服務架構的支援。
5.2 所支援的資料庫類型
因為 AT 涉及 SQL 的解析,是以在不同類型的資料庫上工作,會有一些特定的适配。有興趣在這方面共建的開發者可以參考内置的對 MySQL 的支援方案,來實作對其他資料庫的支援。
5.3 配置和服務注冊發現
支援接入不同的配置和服務注冊發現解決方案。比如:Nacos、Eureka、ZooKeeper 等。
5.4 MT 模式的場景拓展
MT 模式的一個重要作用就是,可以把非關系型資料庫的資源,通過 MT 模式分支的包裝,納入到全局事務的管轄中來。比如,Redis、HBase、RocketMQ 的事務消息等。有興趣在這方面共建的開發者可以在這裡貢獻一系列相關生态的适配方案。
5.5 事務協調器的分布式高可用方案
針對不同場景,支援不同的方式作為事務協調器 Server 端的高可用方案。比如,針對事務狀态的持久化,可以是基于檔案的實作方案,也可以是基于資料庫的實作方案;叢集間的狀态同步,可以是基于 RPC 通信的方案,也可以是基于高可用 KV 存儲的方案。
- Roadmap
藍圖
綠色部分是已經開源釋出出來的,黃色 部分是将在後續版本中由阿裡釋出出來的,藍色部分是我們和社群共建生态部分:
• 對不同資料庫的支援,開發者可以參考 MySQL 的實作。
• 對不同微服務架構的支援,開發者可以參考 Dubbo 的實作。
• 對 MQ、NoSQL 的支援,開發者可以參考 TCC 的實作。
• 配置和服務注冊發現:開發者通過少量的工作可以接入任何可以提供這類服務的架構。
• 當然,非 藍色 的部分也非常歡迎社群參與進來,貢獻更優的解決方案。
• 另外,XA 作為分布式事務的标準,是一個完備的分布式事務解決方案不可或缺的,遠景的規劃中,我們一定需要把 XA 的支援加入進來。
初步的版本規劃
v0.1.0:
• 微服務架構支援: Dubbo
• 資料庫支援: MySQL
• 基于 Spring AOP 的 Annotation
• 事務協調器: 單機版本
v0.5.x:
• 微服務架構支援: Spring Cloud
• MT 模式
• 支援 TCC 模式事務的适配
• 動态配置和服務發現
• 事務協調器: 高可用叢集版本
v0.8.x:
• Metrics
• 控制台: 監控/部署/更新/擴縮容
v1.0.0:
• General Availability: 生産環境适用
v1.5.x:
• 資料庫支援: Oracle/PostgreSQL/OceanBase
• 不依賴 Spring AOP 的 Annotation
• 熱點資料的優化處理機制
• RocketMQ 事務消息納入全局事務管理
• NoSQL 納入全局事務管理的适配機制
• 支援 HBase
• 支援 Redis
v2.0.0:
• 支援 XA
當然,項目疊代演進的過程,我們最重視的是社群的聲音,路線圖會和社群充分交流及時進行調整。
相關連結:
FESCAR on GitHub:
https://github.com/alibaba/fescarGTS on Aliyun:
https://help.aliyun.com/product/48444.html點選了解“阿裡雲新品釋出會頻道”:
https://promotion.aliyun.com/ntms/act/cloud/product.html