淺談微服務架構交易機制實現

無可閃躲的分散式交易機制

Fred Chien(錢逢祥)
Brobridge - 寬橋微服務
9 min readJun 28, 2020

--

Photo by Fahrul Azmi on Unsplash

除非我們的應用非常簡單,又或者是業務需求對資料一致性、工作處理的延遲問題沒有太多需求,不然微服務架構下最讓人頭痛的問題,應該就是分散式交易機制(Distributed Transaction)的實現。

因為確實不太容易實現,所以有不少人為了迴避這個問題,直接採用共享資料(庫)的模式來解決。只是,這種共享模式以微服務架構的觀點來看,是種反模式(Anti-pattern)的設計,將軟體架構拉回到了單體式或三層式架構的老路。

我們要瞭解,微服務架構本質上就是分散式系統,而在分散式系統上的交易行為是跨服務、元件的工作,並非在單一節點身上就可以完成。這代表,不會有「一個資料庫系統」,能處理整個業務流程所需的交易工作,而是要面對的是一堆獨立的資料庫系統和一堆獨立的服務,然後在這群系統上設計出能跨系統協同運作的交易機制。

這不是容易的事,但卻是一個躲不掉的現實需求,只要我們想要引入微服務架構就必須面對的議題。所以對於這個問題,本文將淺顯整理一些實現的方向和概念,讓有興趣的人可以參考和模索。

回顧傳統交易機制的作法

傳統三層式架構、SOA 在實現交易機制時,多半是依賴「資料庫系統內建」的交易功能(Commit/Rollback)。主要是對資料的變更行為進行管控,確保在不同欄位的數字,能在不被打斷的前提下,同時進行資料修改。若其中有任何異常,則將資料恢復成變更行為被觸發之前的狀態。

由於傳統的交易機制,多半都集中在同一個資料庫系統上運行,我們只要對該資料庫下達交易命令即可。而資料庫系統的實現也相對單純,只要將資料庫內的目標資料欄位上鎖,避免其他命令來改動資料,就可以滿足交易過程所需的絕對原子性(Atomic)以及阻擋當下各種變更要求。

只不過,在微服務架構下,因為私有資料庫(Database per service)模式的引入,每個服務都有自己管理的資料以及自己負責的業務工作,所以傳統集中式交易機制的作法已經無法滿足需求。

初入微服務肯定會碰到的交易問題

需要多個跨服務 API 呼叫來完成的一個任務要求

提到交易機制,大家普遍會直接想到金融的轉帳交易等需求,這對很多人來說可能太過遙遠。但是,所有剛接觸微服務架構的人,肯定有在服務拆散後,必須得讓多個服務協同工作以完成一個業務要求的經驗。

例如:在 User 服務上,建立一個新使用者,但同時也要在 Permission 服務上建立該使用者的權限設定,甚至還要再更多服務上做相關資料的建立。

為了讓所有工作能準確完成,需要去發動執行並等待所有服務執行完成,而且,只要有一個環節失敗,就要把其他服務上所有的更動要求撤銷,已執行完成的服務,甚至要回滾成原本狀態。

如果有誰說他的微服務之路沒遭遇過這個關卡,不是沒真正碰過微服務架構,就是架構做錯了。

我們對分散式交易機制的期望和要求

對於交易機制,通常我們期望每個服務之間,要盡可能保持資料狀態的一致,而且要盡量縮短資料不一致的時間,至少不能因為資料的短暫不一致而影響業務的運作。

這議題有很多種面向可以討論和著手,依照應用需求和性質不同,也有許多種做法,甚至是無法通用的方案。但如果所有的交易機制,都要經過特殊設計,這對應用的開發來說,會是一個極大的麻煩。所以我們通常也追求一個「通用」的解決方案,至少大部分場景是可以滿足的方案。

而在面對分散式交易的需求,大體上有兩種主要思路:

  1. 補償式交易
  2. 多階段提交機制

這兩種各自都有其優缺點,各自能解決一些交易上的問題,許多交易機制解決方案,多半也都圍繞在這兩種方式進行。

補償式的交易實現

補償式交易(Compensation Transactioon),在分散式交易中是最容易實現的一種做法,也是在微服務架構下最被推薦的作法。簡單來說,這類方式就是畫一個大餅,這塊餅上每個部分都要完成,這大餅才會算是完成。於是在交易開始時,會將相關事件拋出,然後等所有工作完成的事件回來,直到達成交易中的所有目標。

至於錯誤處理的部分,當交易中有任何問題發生,也會有事件被生成,於是我們可以接收這些失敗事件,進行資料回復或工作撤銷還原的工作。可以說,這樣的錯誤處置手段有點像先斬後奏,先執行任務,真的有狀況,再來看如何補償。

雖然這樣的作法,能夠容易實現分散式交易的功能,但對於架構師和開發者來說,卻非常不容易維護,因為你永遠不知道一個事件之下,會有多少連鎖反應發生,甚至有可能發生無窮的事件迴盪。對於事件交易過程的追蹤,更是一大麻煩。

此外,補償式交易雖然彈性很高,擴展性也很好,但比較難要求所有的工作在一定時限內完成,不管是正常的變更工作,還是撤銷、退回的工作。也由於服務間可能會保有一定程度的資料不一致,有些應用可能並不適合這樣的設計。對於需要強資料一致性的交易(例如:轉帳交易)來說,這類做法就很難滿足,需要設計更複雜的事件機制才有機會達成。這對應用開發者來說,無疑是一件頭痛的事情。

這種做法的典型,就是常聽到的 SAGA 模式。

多階段提交的交易實現

相對補償式交易來說,多階段提交(Multi-phase commit)則是一個較為硬性的作法,可以較容易用於實現強資料一致性的需求。因為設計上交易邏輯會比較集中,所以對於開發人員來說概念比較容易理解,長期維護上也比較輕鬆。

只是這樣的作法,多半需要一個交易協調器(Transaction Coordinator)的幫助,幫助控制交易的進行。而這個交易協調器的實現,除了有一定複雜度,又因為是有狀態(Stateful)的設計,所以擴展性不易達成。導致若要實現多階段提交,又是另一個巨大的議題。

若不引入交易協調器,對於開發人員來說,除了實現交易邏輯時相當繁雜和辛苦之外,也對開發人員能力水平會有更高的要求。更困難的是,因為要自行處理交易狀態管理,使得呼叫端服務、被呼叫服務,都可能不小心變成 Stateful Service 的存在,導致失去擴展性。

因此,多階段提交其實是一個理想的解決方案,但不易實現的作法。有些應用程式開發框架所提供簡單的交易機制,採用的就是包裝多階段提交的作法。只是,為了不擴大交易實作的複雜度,大多數應用程式開發框架所包裝的交易機制,功能相當有限,只能處理有限問題,而且還綁定語言或框架,基本上與微服務架構的目標已經背道而馳。

這類多階段提交,就是常聽見的 2PC、3PC 等。

SAGA 模式和多階段提交是絕對互斥的關係嗎?

SAGA 模式本質上是一種補償式(Compensation)的交易機制,其又分做 Choreography 和 Orchestration 兩種作法,一個是去中心化的作法,另一種是中心化的設計。無論是哪一種作法,都是基於事件驅動的模式下進行。

在最原始的設計中,SAGA 就是類似一種「射後不理」的機制,也就是丟出事件要求做了再說,其中若是有一個環節失敗,就再拋出事件告訴大家 Rollback(回滾)吧。這是很理想的作法,適合分散式架構下的實現,但在這樣原始的設計設計上,如果碰到業務邏輯複雜的系統,其實很有可能會造成「無法回滾」的情況。

但能否解決這個問題呢?其實可以,只要在設計上,加上兩階段提交(2PC)的機制,就能解決。只是這樣做以後,事件會越來越複雜,數量也會越來越多。 而且這樣做以後,會將整件事提升到另一種等級的困難度。

雖然很多人會拿多階段提交(如:2PC/3PC)與 SAGA 做直接比較,但實際上,他們是不衝突的東西,甚至是可以相容的實現。用事件形式實現多階段提交,完全是可行的作法。只是,多階段提交已經有需多歷史悠久的 Protocol 和實現,所以被拿出來當作是一種解決方案來跟 SAGA 作為比較。你硬要拿這些現成的東西來整進 SAGA,也不太可能。(簡單來說你想要整,就得自己想辦法實現 Application 層的多階段提交機制)

選擇適合的分散式交易機制

我們期望有極具彈性、擴展性的交易機制,又期望有高可維護性、強資料一致性的存在,這雖然很難或幾乎不可能有一種方式同時實現,但我們可以在其中做一些選擇,幫不同交易選擇適合的實作方式。

建議先思考哪一些任務或交易工作,適合「最終資料一致性」的場景,哪一些需要「強資料一致性」的介入。將所有的工作,以資料一致性的需求劃分,可以得到一些初步結果。再來是評估交易的複雜度,過於複雜而且牽涉服務過於多的任務,在實現補償式交易時,會是一件極為困難的事,所以這類任務應該避免採用補償式交易。

適合大部分交易場景的通用方案?

如果想要追求一個能滿足大部分交易場景的方案,包括能滿足強資料一致性、擴展性和易用性,建議實現 SAGA 和多階段提交的整合。

採用 Orchestration-based SAGA,將多階段提交的 Transaction Coordinator 實現在 SAGA Orchestrator 身上。不只如此,許多被呼叫的服務,因為要管理任務的生命週期、提交狀態和工作內容,也需要額外設計一個任務管理機制。

出自 Brobridge Twist 產品簡報:Transaction Coordinator 有許多議題需要關注和處理

實現時,種種議題也需要考量,因為 Transaction Coordinator 和任務管理器本身會變成是 Stateful Service 的存在,而面臨難以擴展的困境,除非針對這問題有特殊設計,不然實務上很容易與擴展性及維護性有所衝突,這些都是在實現這些機制所要考量的議題之一。

雖然有許多困難,但理論上只要能完成這些設計,分散式交易實現對於應用程式開發人員來說,就是一個再輕鬆不過的事。

為此,寬橋(Brobridge) 的「微服務交易解決方案 Brobridge Twist」,已經實現了 Transaction Coordinator 和任務狀態管理,在架構上解決了中心化的擴展性問題,也支援分散式部署,並提供簡單通用的 API ,讓開發者能輕易的將分散式交易機制套在應用之中。

本文資料,來源皆參考自 寬橋(Brobridge) 的微服務架構設計教育訓練課程,如果想要暸解更多關於微服務架構設計的議題,可以與我們聯絡。若對文中提及的「Brobridge Twist」微服務交易元件感興趣,也歡迎與我們洽詢。

簡單有效的微服務交易機制解決方案

--

--