讓每個服務單位決定何時以及如何處理業務運作,而非依賴中央協調者。 此方法去中心化工作流程邏輯,並將責任分配至系統各元件。
內容和問題
通常你會將雲端應用程式拆分成幾個小型服務,這些服務協同運作以處理端到端的商業交易。 交易中的單一操作可能導致所有服務間多次點對點通話。 理想狀況下,這些服務是鬆散耦合的。 設計分散式、高效且可擴展的工作流程具有挑戰性,因為它涉及複雜的服務間溝通。
通訊的常見模式是使用集中式服務或 協調器。 傳入要求會流經協調器,因為它會將作業委派給個別的服務。 每個服務都完成了自己的責任,卻不了解整體工作流程。
你通常會以自訂軟體實作編排器模式,具備系統內服務職責的領域知識。 此方法的一個好處是,協調器能根據下游服務執行的個別操作結果整合交易狀態。
這種做法也帶來一些障礙。 新增或移除服務可能會中斷現有的邏輯,因為您需要重新連接通訊路徑的部分。 此相依性可讓協調器實作變得複雜且難以維護。 編排器可能會對工作負載的可靠性產生負面影響。 在負載情況下,它可能會導致效能瓶頸,並成為單一故障點(SPoF)。 當編排器失效或過載時,故障可能會傳播到所有相依的下游服務。
解決方案
將交易處理邏輯委派給各服務。 讓每個服務參與企業營運的通訊工作流程,並決定何時以及如何處理。
編舞模式減少了對集中化溝通流程的客製化軟體的依賴。 這些元件在彼此間編排工作流程時,實作共同邏輯,且彼此之間不直接溝通。
實作編舞的常見方式是使用訊息代理程式來緩衝要求,直到下游元件宣告並處理這些要求為止。 下圖顯示透過 發布者-訂閱者模式處理請求。
客戶端請求會在訊息代理中作為訊息佇列。
服務或用戶會輪詢經紀人,以判斷其是否能根據實作的業務邏輯處理該訊息。 經紀商也能向有興趣的訂閱者推送訊息。
每個訂閱服務依訊息指示執行其操作,並以操作成功或失敗訊息回應經紀人。
若操作成功,服務可將訊息發佈至同一佇列或不同佇列,讓其他服務在需要時繼續執行工作流程。 若操作失敗,服務會發布失敗訊息。 訂閱該訊息的服務可以對失敗操作或整個交易執行預設的補償動作。
問題和考慮
決定如何實作此模式時,請考慮下列幾點:
故障處理複雜度。 應用程式中的元件可能負責管理原子任務,並依賴系統的其他部分。 一個元件的故障可能影響其他元件,導致整體請求完成延遲。
要優雅地處理失敗,你必須實作故障處理邏輯,這會增加複雜度。 失敗處理邏輯,例如 補償交易,也容易發生故障。
順序性流程。 此模式適合平行處理獨立業務運作的工作流程。 當編舞需要以序列進行時,工作流程可能會變得複雜。 例如,D服務只有在B和C服務成功完成作業後才可開始運作。
大規模可觀察性。 若服務數量快速增加,這種模式會帶來挑戰。 許多獨立的環節使服務間的工作流程變得複雜。 若沒有中央協調器保存完整的交易狀態,沒有任何單一元件能完整掌握機上業務運作的全貌。 你必須持續使用 分散式追蹤 與相關識別碼來維持可觀察性。
韌性處理者溝通。 在編排器主導的設計中,核心元件可以將韌性責任(例如暫態、非暫態及超時失敗的重試處理)委派給專門的韌性處理者。
當你在以編舞為基礎的設計中移除編排器時,後續元件就不再承擔韌性責任。 它們仍集中在韌性處理程序中。 但下游元件必須直接與該處理器通訊,這會增加點對點的通訊。
事件結構演化。 事件結構演進可能隨時間導致消費者出現重大變化。 在此模式中,多個獨立服務會處理相同的事件。 如果生產者更改事件的資料結構,可能會破壞依賴舊結構的下游消費者。 使用架構註冊表來管理事件契約,並在服務獨立演進過程中,使用向後相容的演進。
冪性與事件排序。 至少一次的送達與重試可能會產生重複訊息,且同時使用者可能會錯序處理訊息。 透過追蹤穩定的訊息識別碼,將消費者設計為 冪等。 當需要有序處理時,可使用代理者功能如 服務匯流排 會話,或包含序列或版本資料,讓消費者能拒絕過時事件並偵測空隙。
原子狀態與事件發布。 某個服務若分別以獨立操作更新其資料存放區並發佈事件,可能會在其中一項操作成功提交時,另一項操作卻失敗。 使用 交易式收件匣模式 或等效的原子機制,將狀態變更與事件同時持久化,然後由獨立程序發布事件。
湧現行為與事件風暴。 去中心化事件拓撲能在大規模上產生湧現行為。 當多個服務對彼此事件做出反應時,系統可能無意中產生反饋迴路或事件風暴。 一個小事件可能會引發一連串的下游反應。 為防止循環事件鏈,應使用事件過濾、消費者並發限制、限速及明確規則等保護措施。
使用此模式的時機
當下列情況時,請使用此模式:
下游元件以 fire and forget 的方式獨立處理原子作業。 每個元件完成一項任務後,透過訊息代理向其他元件發出完成信號。 發起服務在派遣任務後不會主動管理或追蹤任務,但下游服務仍透過事件傳達結果。
你預期會經常更新和更換這些元件。 這種模式讓你能以較少的努力修改應用程式,且對現有服務的干擾最小。
你使用無伺服器架構來進行簡單的工作流程。 元件可以是短暫的和事件驅動的。 當事件發生時,服務會建立執行任務的元件,完成該任務後則移除元件。
有界上下文之間的通訊需要跨領域邊界的鬆散耦合。 若在單一有界上下文內進行通訊,則可考慮編排器模式,視複雜度與團隊偏好而定。
中央調度器引入了性能瓶頸。
在下列情況下,此模式可能不適用:
應用程式很複雜,需要中央元件來處理共享邏輯,讓下游元件保持輕量。
元件間的點對點通訊是不可避免的。
你需要使用商業邏輯來整合所有下游元件處理的操作。
工作負載設計
評估如何在工作負載設計中使用編舞模式,以達成 Azure Well-Architected Framework 支柱所涵蓋的目標與原則。 下表提供此模式如何支援每個要素目標的指引。
| 支柱 | 此模式如何支援支柱目標 |
|---|---|
| 卓越營運有助於透過標準化流程和團隊凝聚力來提供工作負載品質。 | 這種模式中的分散式元件是自主的,設計上可替換,因此你可以調整工作負載,且對系統整體的改變較少。 - OE:04 工具和程式 |
| 效能效率 可透過調整、數據和程式碼的優化, 有效率地協助您的工作負載符合需求 。 | 當集中式協調流程拓撲發生效能瓶頸時,此模式提供替代方式。 - PE:02 容量規劃 - PE:05 縮放和分區 |
與任何設計決策一樣,請考量此模式可能帶來的取捨,以及這些取捨對其他支柱目標的影響。
範例
此範例展示了編舞模式,透過建立事件驅動的雲端原生工作負載,將函式與微服務並行運行。 當客戶端要求寄送包裹時,工作負載會指派一台無人機。 包裹準備好由預定的無人機取走後,投遞程序便開始。 包裹在運送途中,工作負載會負責處理運送過程,直到收到已出貨的狀態。 完整參考架構請參見 Azure 容器應用程式 的微服務。
資料擷取服務會接收客戶端請求並將其轉換為包含傳遞細節的訊息。 商務交易會在服務接收這些新訊息後開始。
單一用戶端商務交易需要三個不同的商務作業:
建立或更新套件。
指派無人機送包裹。
負責配送,包括檢查並在包裹出貨時發送通知。
包裹、無人機排程器及配送微服務負責業務處理。 這些服務之間使用訊息傳遞,而非中央協調器來彼此溝通。 每個服務都必須事先實作一套協議,以去中心化的方式協調業務工作流程。
Design
服務會依序透過多跳處理業務交易。 每個跳點在所有商業服務間共用一條訊息匯流排。
當用戶端透過 HTTP 端點發送傳送請求時,擷取服務會接收該請求,將其轉換成訊息,然後將訊息發佈到共享訊息匯流排。 訂閱的商業服務會讀取新增到匯流排上的訊息。 當商業服務收到訊息時,這表示操作已成功完成、請求失敗或逾時。若請求成功,服務會以狀態碼Ok 回應訊息匯流排,產生新的操作訊息並將其送到訊息匯流排。 如果請求失敗或逾時,服務會將失敗原因代碼回報至訊息匯流排,並透過 Azure 服務匯流排 將該訊息移至死信佇列。 該服務也會將無法在特定時間內接收或處理的訊息移至死信佇列。
此設計利用多重訊息匯流排來處理整個商業交易。 Azure 服務匯流排 與 Azure 事件方格 提供此設計的訊息服務平台。 工作負載運行於 Azure 容器應用程式。 擷取服務作為 Azure 函式運行於容器應用程式,而套件、無人機排程器與配送服務則作為微服務在同一容器應用程式環境中執行。 容器應用程式處理執行業務邏輯的 事件驅動處理 。
這種設計也確保編舞是有順序的。 單一服務匯流排命名空間包含一個主題,該主題包含兩個訂閱及一個會話感知佇列。 資料引入服務會向主題名稱發布訊息。 套件服務與無人機排程服務會訂閱主題並發布訊息,通知隊列成功請求。 包含一個共用的會話識別碼,將 GUID 與傳遞識別碼關聯起來,讓交付服務能將每筆交易所需的兩個訊息做關聯。 一則訊息確認包裹已準備好,另一則則確認已安排無人機。 若無此會話相關性,傳遞服務無法跨獨立跳數關聯相關訊息,因為沒有中央協調者追蹤交易狀態。 配送服務會等待每筆交易的兩則相關訊息。 第一個訊息表示包裹已準備好出貨,第二個則表示無人機已排程。
在此設計中,服務匯流排處理高價值訊息,且在整個傳遞過程中不得遺失或重複。 當套件出貨時,狀態變更會發布到 Event Grid。 事件發送者對狀態變更的處理方式沒有預期。 此設計未包含的下游組織服務可監聽此事件類型並執行特定商業邏輯,例如向使用者發送訂單狀態電子郵件。
如果你在其他運算服務(例如 AKS)中部署此模式,便可以將 ambassador 以 sidecar 的形式部署在與業務應用程式相同的 pod 中。 共置可減少通訊延遲,但代理伺服器會增加處理量與資源開銷,並隨應用程式擴展。 當你需要平台未提供的、與程式語言無關的連線考量時,請使用此方法。
為避免連鎖重試操作導致多次嘗試,企業服務應立即標記不可接受訊息。 透過使用通用原因碼或定義的應用程式碼來豐富這些訊息,使服務能將它們移至 DLQ。 考慮實作 Saga 模式來管理下游服務的一致性問題。 例如,另一個服務僅透過執行補償、重試或樞紐交易來處理死信訊息以進行修復。
商業服務是冪等的,以確保重試操作不會產生重複資源。 例如,套件服務會使用新增或更新操作將資料加入資料存儲。
下一個步驟
- 檢視 Azure 中的非同步訊息選項 ,了解用於實施去中心化工作流程的不同基礎設施選擇。
相關資源
在你的編舞設計中考慮以下這些模式:
利用 大使模式 來模組化商務服務與訊息匯流排的溝通。
實作基於佇列的載荷調平模式來處理工作負載的尖峰。
透過 Publisher-Subscriber 模式使用非同步分散式訊息。
如果一個或多個相關操作失敗,則使用 補償交易 來撤銷一系列成功的操作。