微服務分散式事務
當微服務架構將單體系統分解為一個個單一微服務時,它可能破壞了事務。這意味著單體系統中的本地事務將分佈到按順序呼叫的多個服務中。
以下是使用本地事務的單體系統的客戶訂單示例:

在上面的客戶訂單示例中,如果使用者將Put Order 操作傳送到單體系統,則單體系統將建立一個作用於多個數據庫表上的本地資料庫事務。如果其中任何一個步驟失敗,則整個事務回滾。這種ACID(原子性,一致性,隔離性,耐久性)是由資料庫系統保證。
當我們分解這個系統中,我們建立了兩個 CustomerMicroservice和 OrderMicroservice微服務,各自具有單獨的資料庫。這是一個帶有微服務的客戶訂單示例:

當 Put Order請求來自使用者時,將呼叫兩個微服務,並將修改操作應用到他們自己的資料庫中。由於事務現在跨多個數據庫,因此它現在被視為 分散式事務。
在單體系統中,我們有一個數據庫系統來確保ACIDity。那麼在分散式如何保證?
我們如何保證事務的原子性?(ACID的原子性)
在資料庫系統中,原子性意味著在事務中 所有步驟都要麼都完成或要麼全部沒有完成。 預設情況下,基於微服務的系統沒有全域性事務協調器。在上面的示例中,如果CreateOrder方法失敗,我們如何回滾我們應用的更改CustomerMicroservice?
我們是否針對併發請求隔離使用者操作了?( ACID的隔離性)
如果一個物件是由兩個事務同時操作,如何保證它們之間的隔離?在上面的示例中,一旦UpdateCustomerFund成功但仍在等待響應 CreateOrder,那麼當前客戶基金的請求是否會返回更新後的金額?
可能的解決方案
上述問題對於基於微服務的系統很重要,否則,無法判斷事務是否已成功完成。以下兩種模式可以解決問題:
2pc(兩階段提交)
2pc廣泛用於資料庫系統。在某些情況下,您可以使用2pc應用到微服務。小心點; 並非所有情況都適合2pc,事實上,2pc在微服務架構中被認為是不切實際的。
那麼什麼是兩階段提交?
正如其名稱提示,2pc有兩個階段:準備階段和提交階段。在準備階段,將要求所有微服務準備一些可以原子方式完成的資料更改。一旦準備好所有微服務,提交階段將要求所有微服務進行實際更改。
通常,需要有一個全域性協調器來維護事務的生命週期,協調器需要在準備和提交階段呼叫微服務。
以下是客戶訂單示例的2pc實現:

在上面的示例中,當用戶傳送下訂單請求時,Coordinator將首先建立包含所有上下文資訊的全域性事務。然後它會告訴CustomerMicroservice準備用建立的事務更新客戶資金。該CustomerMicroservice會再檢查,例如,如果客戶有足夠的資金來繼續進行交易。一旦 CustomerMicroservice可以執行更改,它將鎖定物件以免進一步更改並告知Coordinator它已準備好。在建立訂單時會發生同樣的事情OrderMicroservice。一旦Coordinator確認所有微服務都準備好應用他們的更改,它就會要求他們通過請求提交事務來應用他們的更改。此時,所有物件都將被解鎖。
如果在任何時候單個微服務無法準備,Coordinator則將中止事務並開始回滾過程。以下是客戶訂單示例的2pc回滾圖:

在上面的例子中,由於CustomerMicroservice某種原因未能做好準備,但OrderMicroservice已經回覆說它準備建立訂單。在Coordinator將請求中止對OrderMicroservice的事務,讓OrderMicroservice回滾所作的任何更改和解鎖的資料庫物件。
使用2pc的好處
2pc是一種非常強大的一致性協議。首先,準備和提交階段保證事務是原子的。事務將以所有微服務成功返回或所有微服務都沒有改變而結束。其次,2pc允許讀寫隔離。這意味著在協調器提交更改之前,資料庫欄位上的更改是相互不可見的。
使用2pc的缺點
雖然2pc已經解決了這個問題,但是對於許多基於微服務的系統並不是真的有用,因為2pc是同步的(阻塞)。協議將需要鎖定所有在事務完成之前更改的物件。在上面的示例中,如果客戶下訂單,則將為客戶鎖定“基金”欄位。這可以防止客戶申請新訂單。這是有道理的,因為如果“準備好的”物件在聲稱它已“準備好”之後發生了變化,那麼提交階段可能無效。
這不是很好。在資料庫系統中,事務通常在50毫秒內快速正常完成。但是,微服務在RPC呼叫方面存在長時間延遲,尤其是在與外部服務(如支付服務)整合時。鎖可能成為系統性能瓶頸。此外,當每個事務請求鎖定另一個需要的資源時,可能有兩個事務相互鎖定(死鎖)。
Saga模式
Saga模式是另一種廣泛使用的分散式事務模式。它與2pc不同,後者是同步的。Saga模式是非同步和反應性的。在Saga模式中,分散式事務由所有相關微服務上的非同步本地事務完成。微服務通過事件匯流排相互通訊。
以下是客戶訂單示例的Saga模式圖:

在上面的示例中,OrderMicroservice接收訂單的請求。它首先啟動本地事務以建立訂單,然後發出OrderCreated事件。CustomerMicroservice將監聽此事件,接受到此事件後並更新客戶資金。如果從資金中成功進行扣減,則會發出一個事件CustomerFundUpdated,表示交易結束。
如果任何微服務無法完成其本地事務,則其他微服務將執行補償事務以回滾更改。以下是補償交易的Saga模式圖:

在上面的示例中,由於UpdateCustomerFund某種原因失敗,然後它發出了一個CustomerFundUpdateFailed事件。在OrderMicroservice該事件監聽並啟動其補償交易恢復所建立的訂單。
Saga模式的優點
Saga模式的一大優勢是它支援長期事務。因為每個微服務僅關注其自己的本地原子事務,所以如果微服務執行很長時間,則不會阻止其他微服務。這也允許事務繼續等待使用者輸入。此外,由於所有本地事務都是並行發生的,因此任何物件都沒有鎖定。
Saga模式的缺點
Saga模式很難除錯,特別是涉及許多微服務時。此外,如果系統變得複雜,事件訊息可能變得難以維護。Saga模式的另一個缺點是它沒有讀取隔離。例如,客戶可以看到正在建立的訂單,但在下一秒,訂單將因補償交易而被刪除。
新增流程管理器
為了解決Saga模式的複雜性問題,將流程管理器新增為協調器是很正常的。流程管理器負責監聽事件和觸發端點。
結論
Saga模式是解決基於微服務的體系結構的分散式事務問題的優選方式。但是,它還引入了一組新問題,例如如何以原子方式更新資料庫併發出事件。採用Saga模式需要改變開發和測試的思維方式。對於不熟悉這種模式的團隊來說,這可能是一個挑戰。有許多變體可以簡化其實現。因此,選擇適當的方式為專案實施它是很重要的。
[該貼被banq於2018-10-04 18:42修改過]