使用Conductor實現微服務架構中Saga模式

banq發表於2024-03-29

在典型的基於微服務的架構中,單個業務用例跨越多個微服務,每個服務都有自己的本地資料儲存和本地化事務。當涉及多個事務且微服務數量龐大時,就需要處理跨各種服務的事務。
引入 Saga 模式來處理這些多個事務。它最初由 Hector Garcia Molina 和 Kenneth Salems 於 1987 年提出,被定義為一系列可以相互交錯的事務。

在本教程中,我們將深入探討管理分散式事務的挑戰、基於編排的 Saga 模式如何解決這個問題,以及使用 Spring Boot 3 和 Orkes Conductor(領先的企業級版本)實現 Saga 模式的示例。開源編排平臺Conductor OSS(以前稱為 Netflix Conductor)。

如果分散式事務實施不正確,就會帶來很多挑戰。在分散式事務中,每個微服務都有一個單獨的本地資料庫。這種方法通常稱為“每個服務資料庫”模型。

例如,MySQL 可能因其效能特徵和功能而適合一種微服務,而 PostgreSQL 可能因其優勢和功能而被選擇用於另一種微服務。在此模型中,每個服務執行其本地事務來完成整個應用程式事務。這整個事務稱為分散式事務。

分散式事務可以透過多種方式處理。兩種傳統方法是 2PC(兩階段提交)和 ACID(原子性、一致性、隔離性、永續性)事務,每種方法都有其挑戰,例如多語言永續性、最終一致性、延遲等。

什麼是Saga模式?
Saga模式是一種用於實現一系列本地事務的架構模式,有助於維護不同微服務之間的資料一致性。

本地事務更新其資料庫並透過釋出訊息或事件來觸發下一個事務。如果本地事務失敗,saga 會執行一系列補償事務來回滾先前事務所做的更改。這確保了即使事務失敗,系統也能保持一致。

為了進一步說明這一點,請考慮一個訂單管理系統,該系統由從下訂單到交付訂單的連續步驟組成:
在此示例中,該過程從使用者從應用程式下訂單開始;然後,該流程會經歷幾個步驟:庫存檢查、付款處理、運輸和通知服務。 
如果支付失敗,應用程式必須執行補償事務來回滾之前步驟中所做的更改,例如撤銷支付和取消訂單。這確保了 Saga 模式可以處理任何階段的失敗並補償先前的事務。

Saga 模式可以透過兩種不同的方式實現。

  • Choreography編舞:在此模式中,各個微服務使用事件、執行活動並將事件傳遞給下一個服務。沒有集中的協調器,使得服務之間的通訊更加困難
  • Orchestration編排:在此模式中,所有微服務都連結到集中協調器,該協調器按預定義的順序編排服務,從而完成應用程式流程。這有利於可見性、監控和錯誤處理:

為什麼選擇基於Orchestration編排的Saga模式?
編排模式中的分散方法使得管理和監控服務互動變得更具挑戰性。由於缺乏集中協調和可見性,複雜性增加,使得應用程式更難以維護。
讓我們看看 Choreography 的主要缺點以及選擇 Orchestration 的優點。

1、Choreography缺點
在構建分散式應用程式時,基於Choreography 的實現有很多限制:

  • 緊耦合——服務是緊密耦合的,因為它們是直接連線的。應用程式中服務的任何更改都可能影響所有連線的服務,因此在升級服務時需要依賴關係。
  • 分散式事實來源——跨各種微服務維護應用程式狀態會使流程流的跟蹤變得複雜,並且可能需要額外的系統來整合狀態資訊。這增加了基礎設施並給整個系統帶來了複雜性。
  • 難以排除故障 – 當應用程式流分佈在不同的服務中時,可能需要更長的時間來查詢和修復問題。故障排除需要集中的日誌服務和對程式碼的充分理解。如果一項服務出現故障,可能會導致更嚴重的問題,甚至可能造成大範圍的中斷。
  • 具有挑戰性的測試環境——由於微服務彼此互連,測試對於開發人員來說變得困難。
  • 難以維護——隨著服務的發展,合併新版本涉及重新引入條件邏輯,從而再次形成分散式整體。這使得在不檢查整個程式碼的情況下理解服務流變得更加困難。

2、Orchestration優點
在構建分散式應用程式時,基於Orchestration 的實現具有許多優點:

  • 分散式系統內的協調事務——不同的微服務處理分散式系統中事務的不同方面。透過基於編排的模式,中央協調器以預定義的方式管理這些微服務的執行。它主動確保各個本地事務的精確執行,從而保持應用程式的一致性。
  • 補償事務——在應用程式中,由於任何錯誤,任何執行點都可能發生故障。Saga 模式允許在發生故障時執行補償事務。它可以回滾之前完成的事務,確保應用程式保持一致的狀態。
  • 非同步處理——每個微服務都可以獨立處理其活動,集中協調器可以管理這些非同步操作的通訊和排序。這在特定步驟可能需要較長時間才能完成或需要並行處理的情況下非常有用。
  • 可擴充套件性——編排模式具有高度可擴充套件性,這意味著我們可以透過簡單地新增或修改所需的服務來對應用程式進行更改,而不會顯著影響整個應用程式。這在應用程式需要適應不斷變化的需求、允許輕鬆擴充套件或修改架構的情況下特別有用。
  • 增強的可見性和監控功能——利用編排模式提供跨分散式應用程式的集中可見性,從而實現快速識別和解決問題。這提高了生產力,最大限度地減少了停機時間,並最終減少了檢測故障和從故障中恢復的平均時間。
  • 更快的上市時間——編排器簡化了現有服務的重新佈線和新流程的建立,促進快速適應。這使得應用程式團隊變得更加敏捷,從而加快新想法和概念的上市時間。此外,編排器通常會管理版本控制,從而減少程式碼中使用大量“if..then..else”語句來建立不同版本的需要。

總之,基於編排的 Saga 模式提供了一種在微服務架構中實現協調、一致和可擴充套件的分散式事務的方法,並具有透過補償事務處理故障的額外好處。這使其成為構建健壯且可擴充套件的分散式應用程式的強大模式。


使用 Orkes Conductor 實現 Saga 編排模式
現在,讓我們看一下使用 Saga 模式和Orkes Conductor 的應用程式的實際示例。

考慮一個具有以下服務的訂單管理系統:

  • OrderService – 處理初始訂單放置,包括將商品新增到購物車、指定數量以及初始化結賬流程。
  • InventoryService – 檢查並確認物品的可用性。
  • PaymentService – 安全地管理支付流程,處理各種支付方式。
  • ShipmentService – 準備運輸物品,包括包裝、生成運輸標籤和啟動運輸流程。
  • NotificationService – 向使用者傳送有關訂單更新的通知。

讓我們探索使用 Orkes Conductor 和 Spring Boot 3 複製此流程。

在開始應用程式開發之前,請確保系統滿足以下先決條件。

  • 安裝Java 17

要為我們的應用程式設定 Orkes Conductor,我們可以選擇以下任意方法:
  • 本地設定 Conductor


以下是使用 Saga 模式構建的送餐應用程式的程式碼片段:

@AllArgsConstructor
@Component
@ComponentScan(basePackages = {<font>"io.orkes"})
public class ConductorWorkers {
    
    @WorkerTask(value =
"order_food", threadCount = 3, pollingInterval = 300)
    public TaskResult orderFoodTask(OrderRequest orderRequest) {
        String orderId = OrderService.createOrder(orderRequest);
        TaskResult result = new TaskResult();
        Map<String, Object> output = new HashMap<>();
        if(orderId != null) {
            output.put(
"orderId", orderId);
            result.setOutputData(output);
            result.setStatus(TaskResult.Status.COMPLETED);
        } else {
            output.put(
"orderId", null);
            result.setStatus(TaskResult.Status.FAILED);
        }
        return result;
    }
}


讓我們看看工作流程是如何進行的:

  • 當使用者在食品配送應用程式上下訂單時,該應用程式就會啟動。初始流程作為一系列工作任務實現,包括將食物新增到購物車 ( order_food )、檢查餐廳的食物供應情況 ( check_inventory )、付款流程 ( make_ payment ) 和配送流程 ( Ship_food )。
  • 然後應用程式流程繼續進行fork-join 任務,該任務處理通知服務。它有兩個叉子,一個用於通知送貨員,另一個用於通知使用者。

以下是食品配送應用程式補償事務:

在 Orkes Conductor 中定義工作流時,我們可以 在主應用程式失敗時觸發failureWorkflow。在定義中,包含在應用程式失敗時要執行的工作流名稱。
"failureWorkflow": "<name of the workflow to be run on failure>",
Orkes Conductor 中的補償工作流程會在發生故障時回滾更改

結論
在本文中,我們使用 Orkes Conductor 和 Java Spring Boot 3 成功開發了一個訂單管理應用程式,實現了 Saga 模式。

github專案

 

相關文章