分散式事務Saga模式

banq發表於2018-03-10

兩階段提交2PC是分散式事務中最強大的事務型別之一,兩段提交就是分兩個階段提交,第一階段詢問各個事務資料來源是否準備好,第二階段才真正將資料提交給事務資料來源,當需要同時更新多個資料來源實體時,例如確認訂單並立即更新庫存時,它非常有用。

但是,當您使用微服務時,情況會變得複雜。每個服務都擁有自己的資料庫系統,每個服務不能再越過別的服務直接訪問那個服務的資料庫了。

比如服務A有自己的資料庫O1,服務B有自己的資料庫O2,服務B如果想同時更新資料庫O1和O2,就不能越過服務B直接運算元據庫O1,而兩段提交正是適合這樣的場合,服務B可以在一個JTA事務中同時呼叫資料庫O1的XA資料來源JNDI,再呼叫資料庫O2的XA資料來源JNDI,那麼O1和O2的資料就會實現兩段提交,O1資料庫執行修改或插入操作後其實沒有儲存到資料庫,只有等O2資料庫執行修改或插入操作後,才在第二階段提交確認儲存,這個過程如果有任何出錯,資料庫O1和資料庫O2如同沒有執行修改或插入一樣,兩者資料狀態是一致的。

因此,在微服務架構中,因為一個服務不能越過其他服務直接訪問它們的資料庫,兩段提交可能不適用,當然EJB提供了基於容器的跨服務分散式事務,雖然聽起來很容易,但是因為是同步操作,對網路硬體要求比較高,一旦發生事務出錯,需要手工介入資料庫進行強制回滾,如果跨N個服務呼叫出錯,出錯定位是非常困難的,很難判斷問題出在哪個伺服器或哪段通訊上,不可能進行時間和空間的同時定位。

基於以上原因,本文介紹Saga模式是一種分散式非同步事務,一種最終一致性事務,是一種柔性事務,當然從傳統ACID同步事務過渡到非同步事務需要很多思維方式切換和步驟證明,可見本站其他文章,這裡

下面以電子商務案例說明Saga模式實現:

API閘道器 後面是四個微服務:OrderService(訂購) StockService(庫存) PaymentService(支付) 和DeliveryService(貨運)

在這個例子中,我們不能將“下訂單,向客戶收費,更新庫存”這幾個動作放入一個ACID事務中。但是又必須一致地執行這整個流程,這就需要建立一個分散式事務。

我們都知道,實施分散式任務是多麼困難,而且不幸的是,事務也不例外。處理瞬態狀態,服務之間的最終一致性,隔離和回滾是應該在設計階段考慮的情況。

幸運的是,我們已經為它提出了一些很好的模式,因為我們已經實施了二十多年的分散式事務。今天我想談論的那個叫做Saga模式。

Saga是最著名的分散式事務模式之一。關於它的第一篇文章早在1987年就已經發表了, 從那以後它一直是一個受歡迎的解決方案。

Saga是一系列本地交易,每筆事務都會更新單個服務中的資料。第一個事務由系統外部請求啟動,然後每個後續步驟由前一個事件完成而觸發。

對於我們這個電子商務示例,非常高層次級的Saga設計實現如下所示:


分散式事務Saga模式

現在有兩種不同的方式來實現saga事務,最流行的兩種方式是:

1. 事件/編排Choreography:沒有中央協調器(沒有單點風險)時,每個服務產生並聆聽其他服務的事件,並決定是否應採取行動。

2. 命令/協調orchestrator:中央協調器負責集中處理事件的決策和業務邏輯排序。

讓我們對這兩個實現進行更深入的瞭解,以瞭解它們的工作方式。

事件/編排Events/Choreography

在Events/Choreography方法中,第一個服務執行一個事務,然後釋出一個事件。該事件被一個或多個服務進行監聽,這些服務再執行本地事務併發布(或不釋出)新的事件。

當最後一個服務執行本地事務並且不釋出任何事件時,意味著分散式事務結束,或者它釋出的事件沒有被任何Saga參與者聽到都意味著事務結束。

讓我們看看它在我們的電子商務示例中的外觀:


分散式事務Saga模式

步驟如下:

1.訂單服務儲存新訂單,將狀態設定為pengding掛起狀態,併發布名為ORDER_CREATED_EVENT的事件。

2.支付服務監聽ORDER_CREATED_EVENT,並公佈事件BILLED_ORDER_EVENT。

3.庫存服務監聽BILLED_ORDER_EVENT,更新庫存,併發布ORDER_PREPARED_EVENT。

4.貨運服務監聽ORDER_PREPARED_EVENT,然後交付產品。最後,它釋出ORDER_DELIVERED_EVENT

5.最後,訂單服務偵聽ORDER_DELIVERED_EVENT並設定訂單的狀態為concluded完成。

在上面的情況下,如果需要跟蹤訂單的狀態,訂單服務可以簡單地監聽所有事件並更新其狀態。 在這個案例中,除了訂單服務以外的其他服務都是訂單服務的子服務,也就是說,為完成一個訂單服務,需要經過這些步驟,訂單服務與這些服務是包含與被包含關係,因此,訂單服務在業務上天然是一個協調器。

回滾分散式事務並不是免費的。通常情況下,您必須實施額外操作才能彌補以前所做的工作。

假設庫存服務在事務過程中失敗了。讓我們看看回滾是什麼樣子的:

1.庫存服務產生PRODUCT_OUT_OF_STOCK_EVENT ;

2.訂購服務和支付服務會監聽到上面庫存服務的這一事件:

1. 支付服務會退款給客戶。

2. 訂單服務將訂單狀態設定為失敗。

請注意,為每個事務定義一個公共共享ID非常重要,因此每當您丟擲一個事件時,所有偵聽器都可以立即知道它引用的是哪個事務。

saga事件/編排設計的優點和缺點

事件/編排是實現Saga模式的自然方式; 它很簡單,容易理解,不需要太多的努力來構建,所有參與者都是鬆散耦合的,因為他們彼此之間沒有直接的耦合。如果您的事務涉及2至4個步驟,則可能是非常合適的。

但是,如果您在事務中不斷新增額外步驟,則此方法可能會很快變得混亂,因為很難跟蹤哪些服務監聽哪些事件。此外,它還可能在服務之間新增迴圈依賴,因為它們必須訂閱彼此的事件。

最後,使用這種設計來實現測試將會非常棘手。為了模擬交易行為,您應該執行所有服務。

Saga的命令/協調模式

這裡我們定義了一項新服務,全權負責告訴每個參與者該做什麼以及什麼時候該做什麼。saga協調器orchestrator以命令/回覆的方式與每項服務進行通訊,告訴他們應該執行哪些操作。


分散式事務Saga模式

1.訂單服務儲存pending狀態,並要求訂單Saga協調器(簡稱OSO)開始啟動訂單事務。

2.OSO向收款服務傳送執行收款命令,收款服務回覆Payment Executed訊息

3.OSO向庫存服務傳送準備訂單命令,庫存服務將回復OrderPrepared訊息

4.OSO向貨運服務傳送訂單發貨命令,貨運服務將回復Order Delivered訊息。

OSO訂單Saga協調器必須事先知道執行“建立訂單”事務所需的流程(通過讀取BPM業務流程XML配置獲得)。如果有任何失敗,它還負責通過向每個參與者傳送命令來撤銷之前的操作來協調分散式的回滾。當你有一箇中央協調器協調一切時,回滾要容易得多,因為協調器預設是執行正向流程,回滾時只要執行反向流程即可。

類似saga協調器的標準模式是狀態機,其中每個轉換對應於命令或訊息。狀態機是構建定義明確的行為的極好模式,因為它們易於實現,特別適用於測試。

命令/協調器設計的優點和缺點

基於協調器的Saga有很多好處:

1.避免服務之間的迴圈依賴關係,因為saga協調器會呼叫saga參與者,但參與者不會呼叫協調器

2.集中分散式事務的編排

3.只需要執行命令/回覆(其實回覆訊息也是一種事件訊息),降低參與者的複雜性。

4.更容易實施和測試

5. 在新增新步驟時,事務複雜性保持線性,回滾更容易管理

6.如果在第一筆交易還沒有執行完,想改變有第二筆事務的目標物件,則可以輕鬆地將其暫停在協調器上,直到第一筆交易結束。

然而,這種方法仍然有一些缺點,其中之一是有在協調器中集中太多邏輯的風險,並最終導致智慧協調器會告訴愚蠢的服務該做什麼的架構,這不符合Martinfowler定義微服務應該是聰明的服務+啞巴或愚蠢的管道。

Saga協調器的另一個缺點是它會稍微增加基礎設施的複雜性,因為您需要管理額外的服務。同時增加單點風險,協調器一旦出問題,全域性影響。

Saga模式提示

1.為每個事務建立一個唯一的ID

為每項事務設定一個唯一的識別符號是追蹤後續處理步驟的常用技術,但它也有助於參與者以標準方式向對方請求資料。例如,通過使用事務ID,送貨服務可以要求庫存服務在哪裡提取產品,如果訂單已付款,請與支付服務進行雙重檢查。

2.在命令Command中新增回復地址

可以考慮像在訊息中傳送回覆地址,而不是讓參與者回覆固定地址,這樣您可以讓參與者回覆多個協調人。

3.冪等操作

如果您使用佇列進行服務之間的通訊(如SQS,Kafka,RabbitMQ等),我個人建議您將您的操作設定為冪等。這些佇列中的大多數可能會傳遞相同的訊息兩次。(Kafak 0.10以後已經支援正好一次訊息傳遞,消除了重複訊息傳遞)

4.它也可能會增加服務的容錯能力。通常,客戶端中的錯誤可能會觸發/重放不需要的訊息,並與資料庫混淆。

5.避免同步通訊

隨著事務的進行,不要忘記在訊息中新增每個要執行的操作所需的所有資料。整個目標是避免服務之間再進行同步呼叫,以請求更多的資料。它將使您的服務能夠在其他服務離線時執行其本地事務。很多人錯誤地使用訊息系統,先使用訊息系統傳送一個提醒通知,然後再讓訊息接受者通過服務介面過來取資料,這等同於沒有使用訊息系統,因為同步操作會堵塞,而訊息系統是非堵塞的,大資料讀取時同步經常會堵塞,這是無法通過事前評估資料量大小來主觀以為這麼小資料量不會造成堵塞的。

Saga Pattern | How to Implement Business Transacti

相關文章