

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 系列事件編排模式
<a name="saga-choreography"></a>

## 意圖
<a name="saga-choreography-intent"></a>

系列事件編排模式有助於使用事件訂閱跨越多個服務的分散式交易中保持資料完整性。在分散式交易中，交易完成前可以呼叫多個服務。當服務將資料儲存在不同的資料存放區時，在這些資料存放區之間維持資料一致性可能會具有挑戰性。

## 動機
<a name="saga-choreography-motivation"></a>

*交易*是可能涉及多個步驟的單一工作單元，除非完整執行所有步驟，否則不執行任何步驟，藉此使得資料存放區保持其一致的狀態。*原子性、一致性、隔離性和耐久性 (ACID)* 等詞彙定義了交易的屬性。關聯式資料庫提供 ACID 交易來維持資料一致性。

為了維持交易的一致性，關聯式資料庫使用兩階段遞交 (2PC) 方法。這種方法是由*準備階段*和*遞交階段*組成。
+ 在準備階段，協調處理會要求交易的參與處理 (參與者) 承諾遞交或回復交易。
+ 在遞交階段，協調處理會要求參與者遞交該筆交易。如果參與者無法同意在準備階段遞交，則系統會回復交易。

在遵循 database-per-service 設計模式的分散式系統中，系統不允許兩階段遞交。這是因為每筆交易均分散在不同的資料庫中，而且沒有單一控制器可以協調與關聯式資料存放區中的兩階段遞交類似的處理。在這種情況下，其中一種解決方案是使用系列事件編排模式。

## 適用性
<a name="saga-choreography-applicability"></a>

在以下情況下使用系列事件編排模式：
+ 在橫跨多個資料存放區的分散式交易中，您的系統需要資料完整性和一致性。
+ 資料存放區 (例如 NoSQL 資料庫) 不提供 2PC 來提供 ACID 交易，您需要在單一交易中更新多個資料表，而在應用程式邊界內實作 2PC 將是一項複雜的工作。
+ 管理參與者交易的集中控制程序可能會成為單一失敗點。
+ 系列事件參與者是獨立的服務，需要鬆耦合。
+ 企業領域中有邊界的前後關聯之間存在通訊。

## 問題和考量
<a name="saga-choreography-issues"></a>
+ **複雜性：**隨著微服務數量的增加，由於微服務之間的交互數量，系列事件編排可能變得難以管理。此外，補償性交易和重試會增加應用程式程式碼的複雜性，這可能會導致維護上的額外負荷。當系列事件中只有少數參與者，且您需要一個沒有單點故障的簡單實作時，編排非常適合。當加入了更多參與者時，使用此模式來追蹤參與者之間的相依性會變得更加困難。
+ **彈性實作：**在系列事件編排中，與系列事件協同運作相比，在全域範圍內實施超時、重試和其他彈性模式會更加困難。編排必須在個別元件上執行，而不是在協調器層級執行。
+ **循環依賴關係：**參與者消耗彼此發布的訊息。這可能會導致循環依賴性，導致代碼複雜性和維護開銷，以及可能的死結。
+ **雙寫入問題：**微服務必須以原子方式更新資料庫並發布事件。任一作業失敗都可能導致不一致的狀態。解決這個問題的其中一種方法，是使用[交易寄件匣模式](transactional-outbox.md)。
+ **保存事件：**系列事件參與者根據發布的事件採取行動。請務必依照事件發生的順序儲存事件，以供稽核、偵錯和重新執行之用。如果需要重新執行系統狀態才能還原資料一致性，您可以使用[事件來源模式](event-sourcing.md)將事件保留在事件存放區中。事件存放區也可用於稽核和疑難排解，因為它們會反映系統中的每一項變更。
+ **最終一致性**：本地端交易的序列處理會導致最終一致性，此情況對於需要強式一致性的系統來說可能是個挑戰。您可以設定業務團隊對一致性模式的期望來解決此問題，或重新評估使用案例並切換到提供強式一致性的資料庫。
+ **等冪性：**系列事件參與者必須是等冪的，以便在由意外當機和協調器故障引起的暫時性故障時允許重複執行。
+ **交易隔離**：系列事件模式缺少交易隔離，這是 ACID 交易中的四個屬性之一。交易的[隔離程度](https://docs.aws.amazon.com/neptune/latest/userguide/transactions-isolation-levels.html)決定了其他並行交易能影響該筆交易在資料上操作的程度多寡。交易的並行協同運作可能會導致過時資料。我們建議使用語義鎖定來處理此類情況。
+ **可觀測性**：可觀測性是指詳細的日誌記錄和追蹤，藉此疑難排解實作和協同運作中的問題。當系列事件參與者的數量增加時，這會變得很重要，導致偵錯的複雜性。與系列事件協同運作相比，在系列事件編排中更難達成端到端監控和報告。
+ **延遲問題**：當系列事件是由數個步驟組成時，補償性交易可能會增加整體回應時間的延遲。如果交易進行同步呼叫，這可能會進一步增加延遲。

## 實作
<a name="saga-choreography-implementation"></a>

### 高層級架構
<a name="saga-choreography-high-level-arch"></a>

在下面的架構圖中，系列事件編排有三個參與者：訂單服務、庫存服務和支付服務。完成交易需要三個步驟：T1、T2 和 T3。三種補償性交易會將資料恢復到初始狀態：C1、C2 和 C3。

![\[系列事件編排高層級架構\]](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/saga-choreography-1.png)

+ 訂單服務會執行本機交易 T1，以原子方式更新資料庫，並將 `Order placed` 訊息發布至訊息代理程式。
+ 庫存服務會訂閱訂單服務訊息，並接收訂單已建立的訊息。
+ 庫存服務會執行本機交易 T2，以原子方式更新資料庫，並將 `Inventory updated` 訊息發布至訊息代理程式。
+ 付款服務會訂閱來自庫存服務的訊息，並收到清查已更新的訊息。
+ 付款服務會執行本機交易 T3，以原子方式使用付款詳細資訊來更新資料庫，並將 `Payment processed` 訊息發布至訊息代理程式。
+ 如果付款失敗，付款服務會執行補償性交易 C1，該交易會以原子方式回復資料庫中的付款，並將 `Payment failed` 訊息發布給訊息代理程式。
+ 執行補償交易 C2 和 C3 以還原資料一致性。

### 使用 AWS 服務來實作
<a name="saga-choreography-aws-services"></a>

您可以透過使用 Amazon EventBridge 來實現系列事件編排模式。EventBridge 使用事件來連接應用程式元件。它透過事件總線或管道處理事件。事件匯流排是接收[事件](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-events.html)並將事件傳遞至零個或多個目的地或*目標*的一種路由器。[與事件匯流排相關聯的規則](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-rules.html)會在事件到達時評估事件，並將事件傳送至[目標](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-targets.html)進行處理。

在以下體系結構中：
+ 微型服務 (訂單服務、庫存服務和付款服務) 是以 Lambda 函數的形式實作。
+ 有三種自訂 EventBridge 匯流排：`Orders` 事件匯流排、`Inventory` 事件匯流排和 `Payment` 事件匯流排。
+ `Orders` 規則、`Inventory` 規則和 `Payment` 規則會與傳送至對應事件匯流排的事件配對，並調用 Lambda 函數。

![\[使用 AWS 服務的系列事件編排架構\]](http://docs.aws.amazon.com/zh_tw/prescriptive-guidance/latest/cloud-design-patterns/images/saga-choreography-2.png)


在成功的情況下，當下訂單時：

1. 訂單服務會處理要求，並將事件傳送至 `Orders` 事件匯流排*。*

1. `Orders` 規則符合事件並啟動庫存服務*。*

1. 庫存服務會更新庫存，並將事件傳送至 `Inventory` 事件匯流排。

1. `Inventory` 規則符合事件並啟動付款服務。

1. 付款服務會處理付款，並將事件傳送至 `Payment` 事件匯流排。

1. 這些 `Payment` 規則會與事件相符，並將 `Payment processed` 事件通知傳送給接聽程式。

   或者，當訂單處理發生問題時，EventBridge 規則會啟動補償性交易，以還原資料更新以維持資料一致性和完整性。

1. 如果付款失敗，`Payment` 規則會處理事件並啟動庫存服務*。*存貨服務會執行補償性異動，以回復存貨。

1. 還原庫存後，庫存服務會將 `Inventory reverted` 事件傳送至 `Inventory` 事件匯流排*。*此事件由 `Inventory` 規則處理*。*它會啟動訂單服務*，*該服務會執行補償性交易以移除訂單。

## 相關內容
<a name="saga-choreography-resources"></a>
+ [系列事件協同運作模式](saga-orchestration.md)
+ [交易寄件匣模式](transactional-outbox.md)
+ [使用輪詢重試模試](retry-backoff.md)