知識庫 / Spring / Spring Boot RSS 訂閱

微服務架構中的 Saga 模式

Spring Boot
HongKong
6
11:11 AM · Dec 06 ,2025

1. 引言

在典型的微服務架構中,當單個業務用例跨越多個微服務時,每個服務都有其本地數據存儲和本地化事務。對於多個事務,以及微服務的數量龐大時,就產生了處理跨多個服務的事務的需求。


Saga 模式被引入用於處理這些多個事務。最初由 Hector Garcia Molina 和 Kenneth Salems 於 1987 年引入,它被定義為可以相互交錯的事務序列。

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

2. 分佈式事務的管理挑戰

分佈式事務如果實施不當,會帶來很多挑戰。在分佈式事務中,每個微服務都有獨立的本地數據庫。這種方法通常被稱為“服務專用數據庫”模型。

例如,由於 MySQL 的性能特性和功能,可能適合用於一個微服務,而 PostgreSQL 則可能根據其優勢和能力選擇用於另一個微服務。在這個模型中,每個服務都會執行其本地事務以完成整個應用程序事務。這個整個事務被稱為分佈式事務。

分佈式事務可以通過多種方式處理。傳統的兩種方法是 2PC(兩階段提交)和 ACID(原子性、一致性、隔離性和持久性)事務,每種方法都存在自身的挑戰,例如 多重持久性、最終一致性、延遲等

3. 理解 Saga 模式

Saga 模式是一種用於實現一系列本地事務的架構模式,有助於在不同的微服務之間保持數據一致性。

本地事務更新其數據庫並通過發佈消息或事件觸發下一個事務。如果本地事務失敗,Saga 將執行一系列補償事務以回滾先前事務所做的更改。這確保了即使事務失敗,系統也能保持一致性。

為了進一步説明這一點,請考慮一個訂單管理系統,它包含從下單到交付訂單的連續步驟:

在這個例子中,流程從應用程序中用户下單開始。流程隨後通過幾個步驟:庫存檢查、支付處理、運輸和通知服務。

如果支付失敗,應用程序必須執行補償事務以回滾先前步驟所做的更改,例如撤銷支付和取消訂單。這確保了 Saga 模式可以在任何階段處理失敗並補償先前事務

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

編排: 在這種模式中,單個微服務會消費事件、執行活動並將事件傳遞給下一個服務。沒有中心協調器,這使得服務之間的通信更加困難:

 

管絃: 在這種模式中,所有微服務都與中心協調器相連,該協調器以預定義的順序協調服務,從而完成應用程序流程。這有助於可見性、監控和錯誤處理:

4. 編排模式為何優於基於編排的模式?

由於編排模式的去中心化方法,管理和監控服務交互變得更加困難。缺乏集中協調和可見性導致複雜性增加,使得應用程序更難維護。

讓我們來看看編排模式的主要缺點以及選擇編排模式的優勢。

4.1. 編排的侷限性

基於編排的實現在構建分佈式應用程序時存在諸多侷限性:

  • 緊耦合 – 服務之間緊密耦合,因為它們直接連接。應用程序中對任何一個服務的修改都可能影響所有連接的服務,升級服務時需要依賴性管理。
  • 分佈式數據源之真 – 在各個微服務中維護應用程序狀態使得跟蹤流程變得複雜,可能需要額外的系統來彙總狀態信息。這增加了基礎設施併為整體系統帶來了複雜性。
  • 難以調試 – 當應用程序流程分佈在不同的服務中時,查找和修復問題會花費更長的時間。調試需要集中式日誌服務以及對代碼的深入理解。如果一個服務失敗,可能會導致更嚴重的問題,甚至可能造成廣泛的中斷。
  • 難以進行測試 – 由於微服務相互連接,測試變得困難。
  • 難以維護 – 隨着服務的演進,引入新版本需要重新引入條件邏輯,再次導致分佈式單體應用。這使得在不檢查整個代碼的情況下理解服務流程變得更加困難。

4.2. 編排的優勢

編排式實現在構建分佈式應用程序時具有許多優勢:

  1. 分佈式系統內的協調事務 – 不同的微服務處理分佈式系統中的不同事務方面。在編排式模式下,中央協調器以預定義的⽅式管理這些微服務的執行,並積極確保單個本地事務的精確執行,從而維護應用程序的一致性。
  2. 補償事務 – 在應用程序中,由於任何錯誤,執行的任何點都可能發生故障。 。這提高了生產力,減少了停機時間,並最終降低了檢測和從故障中恢復的平均時間。
  3. 更快的上市時間 – 協調器簡化了現有服務的重新配置和新流程的創建,從而促進了快速適應。這使應用程序團隊能夠更具敏捷性,從而加快了新想法和概念的上市時間。此外,協調器通常管理版本,減少了代碼中大量的 “if..then..else” 語句,用於創建不同版本的需求。

總結:編排式 Saga 模式提供了一種在微服務架構中實現協調、一致和可擴展的分佈式事務的方法,並且通過補償事務處理故障,使其成為構建健壯和可擴展的分佈式應用程序的強大模式。

5. 使用 Orkés Conductor 實施 Saga 編排模式

現在,讓我們來看一個使用 Saga 模式和 Orkés Conductor 的實際應用示例。

考慮一個訂單管理系統,包含以下服務:

  • OrderService – 處理初始訂單放置,包括將項目添加到購物車、指定數量和初始化結賬流程。
  • InventoryService – 檢查和確認項目可用性。
  • PaymentService – 安全地管理支付流程,處理各種支付方式。
  • ShipmentService – 準備項目進行運輸,包括包裝、生成運輸標籤和啓動運輸流程。
  • NotificationService – 向用户發送關於訂單更新的通知。

讓我們使用 Orkés Conductor 和 Spring Boot 3 複製這個流程。

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

要為我們的應用程序設置 Orkés Conductor,可以選擇以下方法:

在這個例子中,我們將使用 Playground。

這是使用 Saga 模式構建的食品外賣應用程序的代碼片段:

@AllArgsConstructor
@Component
@ComponentScan(basePackages = {"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;
    }
}

5.1. 食品外賣應用程序

以下是從 Conductor UI 呈現的食品外賣應用程序示例:


在 Playground 中查看

讓我們看看工作流程的進展情況:

  • 應用程序開始於用户在食品外賣應用程序上下單。初始流程被實現為一個一系列 工件任務,其中包括將食物添加到購物車(order_food)、檢查餐廳的食物可用性(check_inventory)、支付流程(make_payment)和送貨流程(ship_food)。
  • 應用程序流程隨後移動到 分支合併任務,該任務處理通知服務。它有兩個分支,一個通知送貨員,另一個告知用户。

現在,讓我們運行應用程序!

5.2. 運行應用程序

  1. 克隆項目
  2. 使用生成的訪問密鑰更新 application.properties 文件。為了將此工作者與應用程序服務器實例(先前解釋的工作流程)連接,需要在 Orkes Conductor 中創建應用程序並生成訪問密鑰。
    1. 如果使用 Playground,請參考此視頻生成訪問密鑰
    2. 如果本地設置 Conductor,請按照此處提供的説明 (安裝並本地運行)。
conductor.server.url=https://play.orkes.io/api
conductor.security.client.key-id=<key>
conductor.security.client.secret=<secret>

注意事項:

  • 由於我們使用的是 Playground,conductor.server.url 仍然保持不變。如果我們在本地配置了 Conductor,請用 Conductor 服務器 URL 替換它。
  • 用生成的密鑰替換 key-idsecret
  • 為了使 Worker 與 Conductor 服務器連接,我們需要提供權限(在剛剛創建的應用程序中),以便訪問工作流程和任務。
  • 默認情況下,conductor.worker.all.domain 設置為 ‘saga’。請確保更新為不同的名稱,以避免與 Orkes Playground 中其他人啓動的工作流程和 Worker 衝突。

使用以下命令從根項目運行應用程序:

gradle bootRun

應用程序正在運行;下一步是調用 triggerRideBookingFlow API 從應用程序中創建訂單。

$ curl --location 'http://localhost:8081/triggerFoodDeliveryFlow' \
 --header 'Content-Type: application/json' \
 --data '{
     "customerEmail": "[email protected]",
     "customerName": "Tester QA",
     "customerContact": "+1(605)123-5674",
     "address": "350 East 62nd Street, NY 10065",
     "restaurantId": 2,
     "foodItems": [
         {
             "item": "Chicken with Broccoli",
             "quantity": 1
         },
         {
             "item": "Veggie Fried Rice",
             "quantity": 1
         },
         {
             "item": "Egg Drop Soup",
             "quantity": 2
         }
     ],
     "additionalNotes": [
         "Do not put spice.",
         "Send cutlery."
     ],
     "paymentMethod" : {
         "type": "Credit Card",
         "details": {
             "number": "1234 4567 3325 1345",
             "cvv": "123",
             "expiry": "05/2022"
         }
     },
     "paymentAmount": 45.34,
     "deliveryInstructions": "Leave at the door!"
  }'

請求發送後,我們會收到一個工作流ID,表明我們的食品外賣應用已開始運行!🍕

使用工作流ID,我們可以通過Conductor UI可視化我們的應用程序。 讓我們複製工作流ID,然後在Conductor控制枱中,從左側菜單導航到“Executions > Workflow”。

一個示例執行情況如下:

 

讓我們看看如果某個服務失敗時應用程序流程會發生什麼。

5.3. 補償流程

以下是對食品外賣應用補償交易的簡化可視化:

在 Orkes Conductor 中定義工作流時,當主應用程序失敗時,我們可以觸發 failureWorkflow。在定義中包含要運行的工作流名稱,以防主應用程序失敗。

"failureWorkflow": "<name of the workflow to be run on failure>",

Orkes Conductor 在發生故障時,會回滾補償流程中的變更:

在 Playground 中查看

此流程在我們的主應用程序中的任何服務失敗時觸發。

假設由於資金不足導致支付失敗。 那麼,故障流程會觸發,啓動補償流程如下:

 

系統取消支付,隨後取消訂單,並將失敗通知發送給用户。

砰 🎊! 這樣,我們使用 Orkes Conductor 在我們的食品外賣應用程序中回滾已完成的交易,從而保持應用程序的一致性。

此外,還有一個 Slack 社區 可供查閲,其中包含與 Conductor 相關的任何問題。

6. 結論

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

Orkes Conductor 可在所有主流雲平台上使用:AWS、Azure 和 GCP。

如往常一樣,本文的源代碼可在 GitHub 上找到:GitHub

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.