微服務架構下的分佈式事務

目錄

微服務架構下的分佈式事務

場景分類

DTP模型

DTP模型的侷限性

微服務架構下的分佈式事務特性

微服務架構下分佈式事務處理模型

TCC模型

可靠消息模型

業務補償模型

模型總結對比


微服務架構下的分佈式事務

單體架構下的分佈式事務是一個服務內訪問多個數據源的分佈式事務,可以採用傳統分佈式事務處理模型——DTP(Distributed Transaction Processing)模型來解決。

在微服務的架構下,可能會出現跨服務跨資源的分佈式事務。在解決這類分佈式事務時,微服務追求系統的可用性最終一致性而非數據的強一致性。針對不同的微服務分佈式事務場景,介紹不同的分佈式事務處理模型,包括可靠消息模型業務補償模型TCC(Try-Confirm/Cancel)模型,並總結每種模型的處理流程和優缺點

單體應用架構在規模較小的情況下可以很好地滿足業務需求,但隨着互聯網技術的發展,系統規模的持續擴大,單體架構暴露的問題也越來越多。一方面代碼量大,邏輯複雜,不利於維護,更新某一個小模塊需要重啓整個項目;另一方面,不利於項目的橫向擴展和按需伸縮。微服務架構可以將不同模塊獨立開來,使得各個模塊之間更加的松耦合。各個模塊可以獨立部署、運行與更新,可以更加靈活的擴展與維護。此外,微服務與雲計算天然契合,使得微服務架構被廣泛討論與採用。

場景分類

隨着微服務概念的興起,如何在微服務架構下實施分佈式事務是一個值得探討的問題。早期事務的概念一般侷限於資源層面,不管是單機事務還是分佈式事務,都是交給資源層去做。然而在業務開發階段,事務的概念上升到應用層

應用層的事務場景有三種,如下圖所示(AP表示應用程序,RS表示資源)。單體架構下的事務包含圖1中的(a)和(b)兩種,即單服務內訪問單個數據資源的本地事務和單服務內訪問多個數據資源的分佈式事務;微服務架構下的分佈式事務除了這兩種類型外還會存在更復雜的情況,即圖1的(c)所描述的跨服務、跨資源的分佈式事務。

解決應用層的分佈式事務,較爲經典的方案是DTP模型。DTP模型延續了人們對以往分佈式事務的理解,將業務層的分佈式事務交由資源層處理,應用層不需要關注事務的執行流程。DTP模型只能解決圖中單服務、跨資源場景,若要解決跨服務、跨資源的分佈式事務,比較常見的方案有TCC模型、可靠消息模型和業務補償模型。

DTP模型

傳統單體架構下的分佈式事務處理一般採用DTP模型。DTP模型由X/Open公司提出,也稱 X/Open XA協議

應用程序(AP)通常是指單個的應用,在一個服務內訪問一到多個資源。資源管理器負責管理一到多個資源域,每個資源管理器實例(RM)管理一個資源域,負責具體的資源操作。事務管理器通過與資源管理器交流來協調全局事務。

首先,AP通過TX接口向TM註冊一個全局事務並告知TM需要操作哪些資源域。然後TM通過XA接口通知每個管理對應資源域的RM開啓一個子事務。接着AP通過RM對資源進行操作,並根據執行結果通知TM提交或回滾全局事務。如果所有子事務全部執行成功,則提交全局事務,否則回滾全局事務,即TM通知所有RM回滾子事務。

DTP模型的侷限性

不難看出,DTP模型使用2PC(Two Phase Commit,兩階段提交)協議來保證分佈式事務的原子性一致性。TM充當全局事務協調者,RM充當全局事務參與者。2PC能夠嚴格保證分佈式事務的原子性和一致性,並且由於直接作用於資源層,對業務代碼沒有過多的侵入性,這使得DTP模型具有一定的普適性,滿足大部分場景需求。

DTP模型的缺點在於性能低下,由於事務的隔離性,2PC一般採用基於鎖的併發控制來控制對數據的訪問,這意味着資源將被鎖定直至事務結束。如果一個分佈式事務對非熱點數據的訪問時間過長,將嚴重影響對於熱點數據的訪問,降低系統的併發性能

此外,就分佈式事務應用場景而言,DTP模型只適用於單服務、跨資源場景,不能有效解決跨服務、跨資源場景。而在微服務架構下,跨服務、跨資源分佈式事務往往更加常見。

微服務架構下的分佈式事務特性

ACID是傳統數據庫中事務的設計理念,目的是保證數據的正確性,避免出現髒讀、幻讀等錯誤。但是在分佈式系統中,尤其在應用層面,最重要的是滿足業務需求,而非追求絕對的系統特性。根據CAP原理強一致性可用性分區容錯性不能同時滿足。基於CAP原理的BASE理論(基本可用(Basically Available)-軟狀態(Soft State)-最終一致性(Eventual Consistency)採取了和ACID完全不同的設計思想,BASE理論通過犧牲強一致性來換取高可用性,但可以通過合適的方法達到最終一致性,這符合現實生活中分佈式領域的特點。在此基礎上實施分佈式事務,事務是在應用層執行的,不僅能夠保證數據的最終一致性,也能獲取很好的可用性。

在微服務架構下,跨服務、跨資源的分佈式事務滿足CAP原理,所以後面討論的微服務架構下的分佈式事務處理模型,都是在BASE理論下解決跨服務、跨資源分佈式事務的處理模型。

微服務架構下分佈式事務處理模型

在單體應用中,各個模塊的調用是通過方法或函數來實現的。而在微服務架構下,服務之間的交互必須通過服務間通信來解決。常用的兩種服務間通信機制基於消息異步通信基於請求/響應同步通信。不同的分佈式事務場景可能涉及不同的服務間通信機制,因此需要不同的分佈式事務處理模型來解決。

下面通過一個例子來描述現實生活中經常見到的幾類分佈式事務場景:

週末,Tom想去參加某明星在某地的演唱會,中午先去某家餐館喫飯,在一個微服務架構平臺通過訂餐接口完成一次訂餐操作;然後通過該平臺的訂票接口預訂好下午的車票和晚上的演唱會門票。大致活動如圖所示。

整個微服務架構平臺共有8個服務(不包括UI):

  1. 交易服務完成支付操作,記錄交易流水;
  2. 訂單服務爲本次交易生成訂單,檢查原材料是否充足;
  3. 賬戶服務記錄商家和客戶賬戶,完成轉賬操作;
  4. 可靠消息服務包含一個消息中間件,完成消息接收和投遞動作;
  5. 支付憑證服務給消費者發送消費詳細記錄;
  6. 訂票服務可以預定演唱會門票、機票、酒店等;
  7. 車票服務模擬火車訂票,提供訂票和退票兩個接口;
  8. 演唱會服務模擬演唱會訂票和退票。

整個過程包含三個場景,每個場景下的分佈式事務對應於不同的解決方案。本文將以場景1爲例介紹TCC模型,以場景2介紹可靠消息模型,以場景3介紹業務補償模型

TCC模型

TCC是Try-Confirm-Cancel的縮寫,分別對應着三種操作:Try操作Confirm操作Cancel操作,在服務中分別以三種接口的形式存在。下圖是TCC模型圖和正確執行時的工作流。

Try操作對業務進行檢查,比如檢查數據庫資源是否充足,然後在業務層隔離業務活動需要的資源;

Confirm操作的前提是Try操作成功。這一步纔是真正的執行業務操作,不需要檢查資源情況,使用的就是Try操作預留的資源;

Cancel操作的前提是Try操作失敗,釋放Try操作預留的資源。

TCC模型大致分爲三個部分:主服務從服務全局事務管理器。服務與服務之間通過請求/響應同步通信機制進行交互。主服務提供對外接口,接受客戶端請求,發起一個全局的業務活動並編排所有的事務參與者。從服務全局事務的參與者,提供Try、Confirm和Cancel三個接口,通過調用這些接口來使從服務完成分支事務。全局事務管理器是整個分佈式事務的協調者,記錄全局事務的執行日誌和事務狀態,並且在Try階段完成後,根據結果成功與否調用從服務的Confirm接口或Cancel接口。全局事務管理器是一個單獨的服務。

TCC模型的執行流程,如下圖所示。

  1. 交易服務接受請求開始執行本地事務。
  2. 交易服務向事務管理器申請一個分佈式事務,並註冊需要調用的從服務,即訂單服務和賬戶服務。
  3. 交易服務調用訂單服務和賬戶服務的Try接口,在業務層鎖定業務資源,比如訂單服務會預留一份菜品原材料,賬戶服務會在Tom的賬戶中預留本次的交易額。
  4. 當所有的Try接口操作成功(菜品原材料充足且Tom賬戶充足),交易服務提交本地事務;如果有Try操作失敗(比如菜品原料不夠或Tom賬戶餘額不足),交易服務回滾本地事務。
  5.  當所有的Try接口調用成功,主服務提交本地事務後,通過事務管理器調用從服務的Confirm接口,執行具體的業務邏輯,如扣除一份原材料,削減Tom賬戶餘額,增加商家賬戶餘額;若有Try接口調用失敗,導致主服務本地事務回滾,事務管理器調用從服務Cancel接口解鎖預留資源。
  6. 當所有從服務完成Confirm操作或Cancel操作,分佈式事務結束。

這裏需要注意兩個問題:

  • 一是具體設計時可以控制Try操作的超時時間,如果沒有按時執行Confirm操作可以主動執行Cancel操作,將資源留給其他事務,這樣可以提高服務的自治性
  • 二是在執行Confirm操作或者Cancel操作時一定要保證冪等性,確保由於任何原因導致多次調用這兩個接口時所產生的結果必須和調用一次產生的結果相同,這樣纔可以安全地實施重試策略

TCC模型也是通過兩階段提交協議來保證分佈式事務的原子性。在隔離性方面,DTP模型採用2PL[(兩階段封鎖協議)來控制併發。與DTP模型不同的是,TCC是在業務層上鎖。Try階段完成後,隔離本次所需資源,釋放掉數據庫層面的鎖,其他事務可繼續以同種方式操作數據庫的餘下可用資源,這樣就減少上鎖時間,提高併發性。一致性方面,TCC模型允許短時間內的不一致。比如Tom在付款後商家可能過一會才收到消費金額,但這在一定程度上可以容忍的。

TCC模型適合於當前的各種微服務框架,業務層的編碼可以靈活控制事務。但也正因爲如此,TCC模型需要爲正常的業務邏輯添加事務屬性來滿足分佈式事務的處理要求,代碼侵入性大可移植性低開發成本高

可靠消息模型

可靠消息模型的最大特點在於借用了消息中間件來完成分佈式事務,天然具備最終一致性的思想。下圖是可靠消息模型圖和正確執行時的工作流。

圖中,主服務不會直接與從服務交互,中間通過可靠消息服務解耦。從服務不影響主服務的事務處理,只是被動地接受主服務事務處理的結果。服務與服務之間通過消息的發佈與訂閱進行異步通信

圖中,①到⑥步是主服務向可靠消息服務發送消息階段(生產階段)

  • (1) 主服務向可靠消息服務發送消息,狀態爲“待生產”。
  • (2) 可靠消息服務持久化該消息。
  • (3) 向主服務返回消息持久化結果(成功與否)。
  • (4) 主服務處理本地事務(當步驟③返回成功)。
  • (5) 將本地事務處理結果發送至可靠消息服務。
  • (6) 根據主服務的處理結果修改消息狀態爲“待消費”(當步驟⑤成功)或刪除消息(當步驟⑤失敗)。

只有①到⑥步順利執行,即第⑥步成功將消息狀態修改爲“待消費”,纔會執行⑦到⑩步。⑦到⑩步是可靠消息服務向從服務投遞消息階段(消費階段)

  • (7) 可靠消息服務向從服務投遞消息。
  • (8) 從服務執行本地事務。
  • (9) 從服務向可靠消息服務發出確認信息(步驟⑧執行成功)。
  • (10) 可靠消息服務將這條消息刪除。

可靠消息模型中,從服務的處理不會影響主服務,分佈式事務的一致性體現在如果主服務成功執行,一定要向從服務成功地投遞消息,從服務接收到消息後一定準確地完成自身的業務邏輯。結合場景2,一旦交易確定,Tom已完成支付操作,那麼他一定要收到支付憑證服務給他發送的支付憑證賬單。如果Tom由於網絡原因沒有付款成功,則一定不能收到支付憑證,但支付憑證服務對Tom的付款操作沒有影響,是一個被動的操作。

可靠消息模型中分佈式事務的原子性可以細化爲兩階段:

  • 一是主服務完成業務邏輯後,必須將結果持久化到可靠消息服務裏;
  • 二是可靠消息服務根據完成結果進行操作,如果失敗,刪除消息,如果成功,必須將消息投遞到從服務中,並等待從服務的執行結果。

然而,常見的中間件一般只負責接收消息和投遞消息,不能正確地完成第一階段(生產階段)。因爲不論是主服務先完成業務而後向中間件發送消息,還是先向中間件發送消息而後執行業務,都可能存在異常導致兩邊信息不一致。所以需要對常規的中間件進行包裝,添加一個額外的服務完成圖7中的①到⑥步。其中①到③步必不可少,有了這三步才能夠保證在各種異常情況下主服務的業務執行結果和可靠消息的消息持久化過程保持一致。第二階段(消費階段)大部分的中間件可以實現,異常情況下中間件可能會向從服務多次投遞消息。因此,從服務的接口設計需要滿足冪等性。若多次投遞無效,說明從服務有問題,必要時需要人工介入

可靠消息模型是單獨做一個消息服務來管理消息,這樣可以做到獨立部署和維護重用性高降低業務邏輯和消息管理的耦合性。也可以將這個任務直接交給主服務來做,但是這樣做的弊端就是代碼入侵,將消息的可靠性保證與正常的業務邏輯混合在一起,可移植性低,每一個類似的場景都需要根據業務重新編碼。

業務補償模型

相對於TCC模型,業務補償模型的思想比較簡單。一旦分佈式事務某一步出錯,可以利用回滾的思想將已經執行過的業務按照相反的邏輯執行一遍。業務補償模型的架構和TCC模型架構類似,需要主從服務的共同參與。從服務的操作結果也影響主服務,也需要一個全局事務管理器。服務與服務之間通過請求/響應的同步通信機制進行交互。下圖是業務補償模型圖

下圖是正確執行時的工作流。

業務補償模型中從服務的接口只有兩個:Execute接口Compensate接口。不同於TCC模型,補償機制事務處理只有一個階段,即Execute階段,所有的業務活動都在這一階段完成。分佈式事務的正常流程是由主服務調度的,只有在異常情況下才會通過事務管理器進行補償操作。

結合例子,Tom通過訂票服務訂票時是希望兩張票能同時預定成功的,只買到門票或只買到車票該行程便無法成行。結合場景3可以描述業務補償的執行過程如下:

  • (1) 訂票服務接收到請求後,開始本地事務。
  • (2) 主服務通知事務管理器開始一個分佈式事務,並註冊需要調用的從服務。
  • (3) 主服務分別調用各從服務的Execute接口,執行業務操作,事務管理器記錄事務的活動狀態。
  • (4) 所有從服務成功完成子事務,主服務提交本地事務。如果出現異常,比如某一步訂票失敗,事務掛起,主服務回滾本地事務,並通過事務管理器開始執行補償操作。
  • (5) 所有從服務返回正確結果或者都補償完成,分佈式事務結束。

業務補償模式是通過事務管理器記錄分佈式事務的處理流程的,記錄的信息越詳細,越有利於控制業務補償的範圍。需要注意的是,業務補償模型中,從服務事務的執行並不是一定要按順序執行的。如果服務之間存在依賴關係就按照順序執行(但這違反了微服務的設計理念,服務之間耦合性太大)。如果服務之間不存在依賴(如場景3中預定門票和預定火車票是不存在依賴關係的),服務內的子事務可以按照順序執行,也可以併發執行。順序執行會影響效率,但是一旦出錯,只需要對已經執行過的業務進行補償就行。併發執行可以提高效率,但是一旦出錯,需要對所有服務進行業務補償,代價較高。

與TCC模型相比,業務補償模型容易理解,並且代碼入侵少,不需要改造正常的業務邏輯,只需要添加一個補償邏輯即可。但也正因爲如此,會有一定的代碼冗餘,所以業務補償模型適合於業務邏輯簡單的場景。如果業務邏輯繁雜,代碼量大,補償邏輯的實現將變得很複雜。另外一旦業務的正向邏輯發生修改,補償邏輯也需要做修改,將變得難以維護。就場景3而言,車票服務和演唱會服務只需要提供兩個接口:訂票和退票。正向流程調用訂票接口,補償流程調用退票接口。

業務補償模型存在較爲明顯的兩個缺點:

  • 一是重複補償補償失敗,重複補償可以通過設置Compensate接口的冪等性解決。補償失敗也就是在正向操作失敗時,執行補償操作時再度失敗。如果此時沒有一個額外的自動處理機制的話,需要人工進行干預。
  • 二是隔離性不好,業務補償模型的事務處理只有一個階段——Execute階段,這一階段可能出現多個事務對同一資源進行操作的混亂局面。可以借用TCC模型的思想,在Execute階段前加上一個Try階段,預定本次事務所需要的資源。

模型總結對比

早期的事務是在資源層處理的,涉及到分佈式事務時一般採用兩階段提交協議或者三階段提交協議來解決。然而在微服務的架構下,事務的概念已經從資源層上升到應用層,事務的處理變得複雜多變,如果採用2PC或3PC來解決,將極大影響系統的性能。在分佈式的環境中,不同的場景就要採取不同的分佈式事務處理模型。通過下表可以清楚地看到各個模型的特性。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章