Seata 意爲:Simple Extensible Autonomous Transaction Architecture,是一套一站式分佈式事務解決方案,提供了 AT、TCC、Saga 和 XA 事務模式,本文詳解其中的 Saga 模式。 項目地址:github.com/seata/seatahtml
本文做者:屹遠(陳龍),螞蟻金服分佈式事務核心研發 。java
分佈式系統有一個比較明顯的問題就是,一個業務流程須要組合一組服務。這樣的事情在微服務下就更爲明顯了,由於這須要業務上的一致性的保證。也就是說,若是一個步驟失敗了,那麼要麼回滾到之前的服務調用,要麼不斷重試保證全部的步驟都成功。---《左耳聽風-彈力設計之「補償事務」》git
而在金融領域微服務架構下的業務流程每每會更復雜,流程很長,好比一個互聯網微貸業務流程調十幾個服務很正常,再加上異常處理的流程那就更復雜了,作過金融業務開發的同窗會頗有體感。github
因此在金融分佈式應用開發過程當中咱們面臨一些痛點:spring
咱們接觸到的大多數業務(好比在渠道層、產品層、集成層的系統),爲了保障業務最終一致性,每每會採用「補償」的方式來作,若是沒有一個協調器來支持,開發難度是比較大的,每一步都要在 catch 裏去處理前面全部的「回滾」操做,這將會造成「箭頭形」的代碼,可讀性及維護性差。或者重試異常的操做,若是重試不成功可能要轉異步重試,甚至最後轉人工處理。這些都給開發人員帶來極大的負擔,開發效率低,且容易出錯。數據庫
業務實體不少、實體的狀態也不少,每每作完一個業務活動後就將實體的狀態更新到了數據庫裏,沒有一個狀態機來管理整個狀態的變遷過程,不直觀,容易出錯,形成業務進入一個不正確的狀態。express
服務的冪等性是分佈式環境下的基本要求,爲了保證服務的冪等性每每須要服務開發者逐個去設計,有用數據庫惟一鍵實現的,有用分佈式緩存實現的,沒有一個統一的方案,開發人員負擔大,也容易遺漏,從而形成資損。apache
業務的執行狀況監控通常經過打印日誌,再基於日誌監控平臺查看,大多數狀況是沒有問題的,可是若是業務出錯,這些監控缺少當時的業務上下文,對排查問題不友好,每每須要再去數據庫裏查。同時日誌的打印也依賴於開發,容易遺漏。對於補償事務每每須要有「差錯守護觸發補償」、「工人觸發補償」操做,沒有統一的差錯守護和處理規範,這些都要開發者逐個開發,負擔沉重。json
一些場景下,咱們對數據有強一致性的需求時,會採用在業務層上須要使用「兩階段提交」這樣的分佈式事務方案。而在另一些場景下,咱們並不須要這麼強的一致性,那就只須要保證最終一致性就能夠了。數組
例如螞蟻金服目前在金融核心系統使用的就是 TCC 模式,金融核心系統的特色是一致性要求高(業務上的隔離性)、短流程、併發高。
而在不少金融核心以上的業務(好比在渠道層、產品層、集成層的系統),這些系統的特色是最終一致便可、流程多、流程長、還可能要調用其它公司的服務(如金融網絡)。這是若是每一個服務都開發 Try、Confirm、Cancel 三個方法成本高。若是事務中有其它公司的服務,也沒法要求其它公司的服務也遵循 TCC 這種開發模式。同時流程長,事務邊界太長會影響性能。
對於事務咱們都知道 ACID,也很熟悉 CAP 理論最多隻能知足其中兩個,因此,爲了提升性能,出現了 ACID 的一個變種 BASE。ACID 強調的是一致性(CAP 中的 C),而 BASE 強調的是可用性(CAP 中的 A)。咱們知道,在不少狀況下,咱們是沒法作到強一致性的 ACID 的。特別是咱們須要跨多個系統的時候,並且這些系統還不是由一個公司所提供的。BASE 的系統傾向於設計出更加有彈力的系統,在短期內,就算是有數據不一樣步的風險,咱們也應該容許新的交易能夠發生,然後面咱們在業務上將可能出現問題的事務經過補償的方式處理掉,以保證最終的一致性。
因此咱們在實際開發中會進行取捨,對於更多的金融核心以上的業務系統能夠採用補償事務,補償事務處理方面在30年前就提出了 Saga 理論,隨着微服務的發展,近些年才逐步受到你們的關注。目前業界比較也公認 Saga 是做爲長事務的解決方案。
Camel 是實現 EIP(Enterprise Integration Patterns)企業集成模式的一款開源產品,它基於事件驅動的架構,有着良好的性能和吞吐量,它在2.21版本新增長了 Saga EIP。
Saga EIP 提供了一種方式能夠經過 camel route 定義一系列有關聯關係的 Action,這些 Action 要麼都執行成功,要麼都回滾,Saga 能夠協調任何通信協議的分佈式服務或本地服務,並達到全局的最終一致性。Saga 不要求整個處理在短期內完成,由於它不佔用任何數據庫鎖,它能夠支持須要長時間處理的請求,從幾秒到幾天,Camel 的 Saga EIP 是基於 Microprofile 的 LRA(Long Running Action),一樣也是支持協調任何通信協議任何語言實現的分佈式服務。
Saga 的實現不會對數據進行加鎖,而是在給操做定義它的「補償操做」,當正常流程執行出錯的時候觸發那些已經執行過的操做的「補償操做」,將流程回滾掉。「補償操做」能夠在 Camel route 上用 Java 或 XML DSL(Definition Specific Language)來定義。
下面是一個 Java DSL 示例:
XML DSL 示例:
Eventuate Tram Saga 框架是使用 JDBC / JPA 的 Java 微服務的一個 Saga 框架。它也和 Camel Saga 同樣採用了 Java DSL 來定義補償操做:
ServiceComb Saga 也是一個微服務應用的數據最終一致性解決方案。相對於 TCC 而言,在 try 階段,Saga 會直接提交事務,後續 rollback 階段則經過反向的補償操做來完成。與前面兩種不一樣是它是採用 Java 註解+攔截器的方式來進行「補償」服務的定義。
Saga 是由 alpha 和 **omega ** 組成,其中:
下圖展現了 alpha,omega 以及微服務三者的關係:
螞蟻金服內部大規模在使用 TCC 模式分佈式事務,主要用於金融核心等對一致性要求高、性能要求高的場景。在更上層的業務系統由於流程多流程長,開發 TCC 成本比較高,大都會權衡採用 Saga 模式來到達業務最終一致性,因爲歷史的緣由不一樣的 BU 有本身的一套「補償」事務的方案,基本上是兩種:
社區和業界的解決方案通常是兩種,一種基本狀態機或流程引擎經過 DSL 方式編排流程程和補償定義,一種是基於 Java 註解+攔截器實現補償,那麼這兩種方案有什麼優缺點呢?
方式 | 優勢 | 缺點 |
---|---|---|
狀態機+DSL | 1.能夠用可視化工具來定義業務流程,標準化,可讀性高,可實現服務編排的功能 2.提升業務分析人員與程序開發人員的溝通效率 3. 業務狀態管理:流程本質就是一個狀態機,能夠很好的反映業務狀態的流轉 4.提升異常處理靈活性:能夠實現宕機恢復後的「向前重試」或「向後補償」 5.自然可使用 Actor 模型或 SEDA 架構等異步處理引擎來執行,提升總體吞吐量 | 1.業務流程實際是由 JAVA 程序與 DSL 配置組成,程序與配置分離,開發起來比較繁瑣 2.若是是改造現有業務,對業務侵入性高 3.引擎實現成本高 |
攔截器+java 註解 | 1.程序與註解是在一塊兒的,開發簡單,學習成本低 2.方便接入現有業務 3.基於動態代理攔截器,框架實現成本低 | 1.框架沒法提供 Actor 模型或 SEDA 架構等異步處理模式來提升系統吞吐量 2.框架沒法提供業務狀態管理 3.難以實現宕機恢復後的「向前重試」,由於沒法恢復線程上下文 |
Seata Saga 的簡介能夠看一下《Seata Saga 官網文檔》。
Seata Saga 採用了狀態機+DSL 方案來實現,緣由有如下幾個:
在不保證隔離性的狀況下:業務流程設計時要遵循「寧肯長款, 不可短款」的原則,長款意思是客戶少了線機構多了錢,以機構信譽能夠給客戶退款,反之則是短款,少的線可能追不回來了。因此在業務流程設計上必定是先扣款。
注意: 異常發生時是否進行補償也可由用戶自定義決定
假設有一個業務流程要調兩個服務,先調庫存扣減(InventoryService),再調餘額扣減(BalanceService),保證在一個分佈式內要麼同時成功,要麼同時回滾。兩個參與者服務都有一個 reduce 方法,表示庫存扣減或餘額扣減,還有一個 compensateReduce 方法,表示補償扣減操做。以 InventoryService 爲例看一下它的接口定義:
這個業務流程對應的狀態圖:
狀態語言在必定程度上參考了 AWS Step Functions。
更多詳細的狀態語言解釋請看《Seata Saga 官網文檔》。
狀態機引擎的設計主要分紅三層, 上層依賴下層,從下往上分別是:
Eventing 層:
ProcessController 層:
基於以上兩層理論上能夠自定義擴展任何"流程"引擎。這兩層的設計是參考了內部金融網絡平臺的設計。
下面是實踐中總結的在 Saga 模式下微服務設計的一些經驗,固然這是推薦作法,並非說必定要 100% 遵循,沒有遵循也有「繞過」方案。
好消息:Seata Saga 模式對微服務的接口參數沒有任務要求,這使得 Saga 模式可用於集成遺留系統或外部機構的服務。
因此服務設計時須要容許空補償,即沒有找到要補償的業務主鍵時返回補償成功並將原業務主鍵記錄下來。
因此要檢查當前業務主鍵是否已經在空補償記錄下來的業務主鍵中存在,若是存在則要拒絕服務的執行。
不少時候咱們不須要強調強一性,咱們基於 BASE 和 Saga 理論去設計更有彈性的系統,在分佈式架構下得到更好的性能和容錯能力。分佈式架構沒有銀彈,只有適合特定場景的方案,事實上 Seata Saga 是一個具有「服務編排」和「Saga 分佈式事務」能力的產品,總結下來它的適用場景是:
公衆號:金融級分佈式架構(Antfin_SOFA)