將一組分散式動作協調為單一作業。 如果有任何動作失敗,請嘗試以透明方式處理失敗,否則會復原執行的工作,因此整個作業會成功或失敗。 這可藉由讓分散式系統復原,並重試因暫時性例外狀況、長期錯誤和進程失敗而失敗的動作。
內容和問題
應用程式會執行包含一些步驟的工作,其中有些可能會叫用遠端服務或存取遠端資源。 個別步驟可能彼此獨立,但它們是由實作工作的應用程式邏輯所協調。
盡可能,應用程式應該確保工作會執行以完成,並解決存取遠端服務或資源時可能發生的任何失敗。 失敗可能會因為許多原因而發生。 例如,網路可能會關閉、通訊可能會中斷、遠端服務可能沒有回應或處於不穩定狀態,或遠端資源可能暫時無法存取,可能是因為資源限制。 在許多情況下,失敗將是暫時性的,而且可以使用重試模式來處理。
如果應用程式偵測到無法輕易復原的永久性錯誤,則必須能夠將系統還原為一致的狀態,並確保整個作業的完整性。
解決方案
排程器代理程式監督員模式會定義下列動作專案。 這些動作專案會協調要作為整體工作一部分執行的步驟。
排 程器 會安排組成要執行之工作的步驟,並協調其作業。 這些步驟可以合併成管線或工作流程。 排程器負責確保此工作流程中的步驟會以正確的順序執行。 執行每個步驟時,排程器會記錄工作流程的狀態,例如「尚未啟動的步驟」、「執行步驟」或「步驟已完成」。狀態資訊也應該包含允許步驟完成的時間上限,稱為「完成時間」。 如果步驟需要存取遠端服務或資源,排程器會叫用適當的 Agent,並傳遞要執行之工作的詳細數據。 排程器通常會使用 異步要求/回應傳訊來與代理程序通訊。 這可以使用佇列來實作,不過可以改用其他分散式傳訊技術。
排程器會在進程管理員模式中執行與進程管理員類似的函式。 實際工作流程通常是由排程器控制的工作流程引擎所定義和實作。 此方法會將工作流程中的商業規則與排程器分離。
Agent 包含邏輯,可封裝對遠端服務的呼叫,或存取工作中步驟所參考的遠端資源。 每個代理程式通常會包裝對單一服務或資源的呼叫,實作適當的錯誤處理和重試邏輯(受限於稍後所述的逾時條件約束)。 實作重試邏輯時,在所有重試嘗試中傳遞穩定標識符,讓遠端服務可以將其用於它可能擁有的任何重複數據刪除邏輯。 如果排程器所執行的工作流程步驟會跨不同步驟使用數個服務和資源,則每個步驟可能會參考不同的代理程式(這是模式的實作詳細數據)。
監督 員 會監視排程器所執行工作中步驟的狀態。 它會定期執行(頻率會是系統特定的),並檢查排程器所維護的步驟狀態。 如果它偵測到任何逾時或失敗,它會安排適當的代理程序復原步驟或執行適當的補救動作(這可能涉及修改步驟的狀態)。 請注意,排程器和代理程式會實作復原或補救動作。 監督員應該只要求執行這些動作。
排程器、代理程式和監督員是邏輯元件,其實體實作取決於所使用的技術。 例如,數個邏輯代理程式可能會實作為單一 Web 服務的一部分。
排程器會維護工作進度的相關信息,以及長期數據存放區中每個步驟的狀態,稱為狀態存放區。 監督員可以使用這項資訊來協助判斷步驟是否已失敗。 此圖說明排程器、代理程式、監督員和狀態存放區之間的關聯性。
注意
此圖顯示模式的簡化版本。 在實際實作中,可能會有許多同時執行的排程器實例,每一個工作子集。 同樣地,系統可以執行每個代理程式的多個實例,甚至執行多個監督員。 在此情況下,主管必須仔細協調其工作,以確保他們不會競爭以復原相同的失敗步驟和工作。 領導者 選舉模式 提供此問題的一個可能解決方案。
當應用程式準備好執行工作時,它會將要求提交至排程器。 排程器會在狀態存放區中記錄工作及其步驟的初始狀態資訊(例如尚未啟動的步驟),然後開始執行工作流程所定義的作業。 當排程器啟動每個步驟時,它會更新狀態存放區中該步驟狀態的相關信息(例如執行步驟)。
如果步驟參考遠端服務或資源,排程器會將訊息傳送至適當的 Agent。 訊息包含代理程式需要傳遞至服務或存取資源的資訊,以及作業的完整時間。 如果 Agent 順利完成其作業,則會傳回排程器的回應。 排程器接著可以在狀態存放區中更新狀態資訊(例如步驟已完成),然後執行下一個步驟。 此程式會繼續進行,直到整個工作完成為止。
代理程式可以實作執行其工作所需的任何重試邏輯。 不過,如果 Agent 未在完成期間到期之前完成其工作,排程器會假設作業失敗。 在此情況下,代理程式應該停止其工作,而不是嘗試將任何項目傳回給排程器(甚至沒有錯誤訊息),或嘗試任何形式的復原。 此限制的原因是,在步驟逾時或失敗之後,代理程式的另一個實例可能會排程執行失敗的步驟(稍後會說明此程式)。
如果代理程式失敗,排程器將不會收到回應。 模式不會區分已逾時的步驟和真正失敗的步驟。
如果步驟逾時或失敗,狀態存放區會包含指出步驟正在執行的記錄,但完整時間將會通過。 監督員會尋找如下所示的步驟,並嘗試復原這些步驟。 其中一個可能的策略是讓監督員更新完成值,以延長完成步驟的時間,然後將訊息傳送給排程器,以識別已逾時的步驟。然後排程器可以嘗試重複此步驟。 不過,此設計需要工作是 等冪的。 系統應該包含基礎結構,以維持一致性。 如需詳細資訊,請參閱 可重複的基礎結構、 建構 Azure 應用程式以進行復原和可用性,以及 資源一致性決策指南。
如果監督員持續失敗或逾時,可能需要防止重試相同的步驟。若要這樣做,監督員可以在狀態存放區中維護每個步驟的重試計數,以及狀態資訊。 如果此計數超過預先定義的臨界值,監督員可以採用在通知排程器應該重試步驟之前,先等候一段時間的策略,以預期會在這段期間內解決錯誤。 或者,監督員可以藉由實 作補償交易模式,將訊息傳送給排程器,以要求復原整個工作。 此方法將取決於排程器和代理程式,提供針對成功完成之每個步驟實作補償作業所需的資訊。
監督員不是監視排程器和代理程式的目的,如果排程器和代理程序失敗,請重新啟動它們。 系統這個層面應該由這些元件執行中的基礎結構來處理。 同樣地,主管不應該知道排程器正在執行的工作的實際商務作業(包括如何補償這些工作失敗)。 這是排程器所實作之工作流程邏輯的目的。 監督員的唯一責任是判斷某個步驟是否失敗,並安排步驟重複,或讓包含失敗步驟的整個工作復原。
如果排程器在失敗后重新啟動,或排程器所執行的工作流程意外終止,排程器應該能夠判斷排程器在失敗時正在處理之任何飛出工作的狀態,並準備好從該時間點繼續這項工作。 此程序的實作詳細數據可能是系統特定的。 如果無法復原工作,可能需要復原工作已經執行的工作。 這也可能需要實作 補償交易。
此模式的主要優點是系統在發生非預期的暫時性或無法復原失敗時具有復原性。 系統可以建構為自我修復。 例如,如果代理程式或排程器失敗,可以啟動新的代理程式,而且監督員可以安排要繼續的工作。 如果監督員失敗,可以啟動另一個實例,並從發生失敗的位置接管。 如果監督員排定定期執行,可以在預先定義的間隔之後自動啟動新的實例。 狀態存放區可以復寫,以達到更大的復原程度。
問題和考量
決定如何實作此模式時,您應該考慮下列幾點:
此模式可能難以實作,而且需要徹底測試系統的每個可能失敗模式。
排程器所實作的復原/重試邏輯很複雜,且相依於狀態存放區中保留的狀態資訊。 也可能需要記錄在永久性數據存放區中實作補償交易所需的資訊。 補償交易也可能失敗。
監督員執行的頻率會很重要。 它應該執行得足夠頻繁,以防止任何失敗的步驟長時間封鎖應用程式,但不應該經常執行,因而造成額外負荷。
代理程式所執行的步驟可以多次執行。 實作這些步驟的邏輯應該是等冪的。
使用此模式的時機
當在分散式環境中執行的進程,例如雲端,必須能夠復原通訊失敗和/或作業失敗時,請使用此模式。
此模式可能不適用於不會叫用遠端服務或存取遠端資源的工作。
工作負載設計
架構設計人員應該評估排程器代理程式監督員模式如何用於其工作負載的設計中,以解決 Azure 良好架構架構支柱中涵蓋的目標和原則。 例如:
要素 | 此模式如何支援支柱目標 |
---|---|
可靠性設計決策可協助工作負載復原到故障,並確保它會在發生失敗后復原到完全正常運作的狀態。 | 此模式會使用健康情況計量來偵測失敗,並將工作重新路由傳送至狀況良好的代理程式,以減輕故障的影響。 - RE:05 備援 - RE:07 自我修復 |
效能效率可透過調整規模、資料、程式碼達到最佳化,有效率地協助您的工作負載符合需求。 | 此模式會使用效能和容量計量來偵測目前的使用率,並將工作路由傳送至具有容量的代理程式。 您也可以使用它,將優先順序較高的工作執行排定優先順序高於優先順序較低的工作。 - PE:05 調整和分割 - PE:09 重大流程 |
如同任何設計決策,請考慮對其他可能以此模式導入之目標的任何取捨。
範例
實作電子商務系統的 Web 應用程式已部署在 Azure Microsoft。 用戶可以執行此應用程式來流覽可用的產品,並下單。 使用者介面會以 Web 角色的形式執行,而應用程式的順序處理元素會實作為一組背景工作角色。 訂單處理邏輯的一部分涉及存取遠端服務,而系統的這個層面可能會容易發生暫時性或更持久的錯誤。 因此,設計工具使用排程器代理程式監督員模式來實作系統的訂單處理元素。
當客戶下訂單時,應用程式會建構描述訂單的訊息,並將此訊息張貼至佇列。 在背景工作角色中執行的個別提交程式會擷取訊息、將訂單詳細數據插入訂單資料庫中,以及建立狀態存放區中訂單程序的記錄。 請注意,插入訂單資料庫和狀態存放區會執行為相同作業的一部分。 提交程式的設計目的是要確保這兩個插入都一起完成。
提交程式為訂單建立的狀態資訊包括:
OrderID。 訂單資料庫中訂單的標識碼。
LockedBy。 處理訂單之背景工作角色的實例標識碼。 執行排程器的背景工作角色可能有多個目前實例,但每個訂單只能由單一實例處理。
CompleteBy。 應該處理訂單的時間。
ProcessState。 處理訂單之工作的目前狀態。 可能的狀態為:
- 擱置中。 已建立訂單,但尚未啟動處理。
- 處理。 目前正在處理訂單。
- 已處理。 訂單已成功處理。
- Error。 訂單處理失敗。
FailureCount。 已嘗試處理訂單的次數。
在此狀態資訊中 OrderID
,欄位會從新訂單的訂單標識碼複製。 和 LockedBy
CompleteBy
欄位會設定為 null
、 ProcessState
欄位設定為 Pending
,且 FailureCount
欄位設定為 0。
注意
在此範例中,訂單處理邏輯相對簡單,而且只有叫用遠端服務的單一步驟。 在更複雜的多步驟案例中,提交程式可能會涉及數個步驟,因此會在狀態存放區中建立數筆記錄,每個記錄都會描述個別步驟的狀態。
排程器也會在背景工作角色中執行,並實作處理訂單的商業規則。 排程器輪詢新訂單的實例會檢查狀態存放區中欄位為 Null 且ProcessState
欄位暫止的記錄LockedBy
。 當排程器找到新訂單時,它會立即以自己的實例標識元填 LockedBy
入欄位、將欄位設定 CompleteBy
為適當的時間,並將欄位設定 ProcessState
為處理。 程式代碼的設計為獨佔和不可部分完成,以確保排程器的兩個並行實例無法同時處理相同的順序。
然後排程器會執行商務工作流程,以異步方式處理順序,並從狀態存放區傳遞 OrderID
欄位中的值。 處理訂單的工作流程會從訂單資料庫擷取訂單的詳細數據,並執行其工作。 當訂單處理工作流程中的步驟需要叫用遠端服務時,它會使用 Agent。 工作流程步驟會使用一組做為要求/回應通道的 Azure 服務匯流排 消息佇列來與代理程序通訊。 此圖顯示解決方案的高階檢視。
從工作流程步驟傳送至 Agent 的訊息會描述訂單,並包含完整時間。 如果代理程式在完成時間到期之前收到遠端服務的回應,它會在工作流程正在接聽的 服務匯流排 佇列上張貼回復訊息。 當工作流程步驟收到有效的回復訊息時,它會完成其處理,而排程器會將訂單狀態的欄位設定 ProcessState
為已處理。 此時,訂單處理已順利完成。
如果代理程式收到來自遠端服務的回應之前到期,Agent 只會停止其處理並終止處理訂單。 同樣地,如果處理訂單的工作流程超過完成時間,它也會終止。 在這兩種情況下,狀態存放區中訂單的狀態會保持設定為處理,但完整時間表示處理訂單的時間已經過去,而且進程被視為失敗。 請注意,如果正在存取遠端服務的代理程式,或處理訂單的工作流程意外終止,狀態存放區中的資訊會再次設定為處理,最後會有過期的完整值。
如果代理程式在嘗試連絡遠端服務時偵測到無法復原且無法轉移的錯誤,它可以將錯誤回應傳回工作流程。 排程器可以將訂單的狀態設定為錯誤,並引發警示操作員的事件。 然後,操作員可以嘗試手動解決失敗的原因,然後重新提交失敗的處理步驟。
監督員會定期檢查狀態存放區,尋找具有過期完整值訂單的訂單。 如果監督員找到記錄,則會遞增 FailureCount
字段。 如果失敗計數值低於指定的臨界值,監督員會將欄位重設為 LockedBy
null、以新的到期時間更新 CompleteBy
欄位,並將字段設定 ProcessState
為擱置中。 排程器的實例可以挑選此訂單,並像之前一樣執行其處理。 如果失敗計數值超過指定的臨界值,則會假設失敗的原因為非轉移。 監督員會將訂單的狀態設定為錯誤,並引發警示操作員的事件。
在此範例中,監督員會在個別的背景工作角色中實作。 您可以使用各種策略來安排要執行的監督員工作,包括使用 Azure 排程器服務(在此模式中不要與排程器元件混淆)。 如需 Azure 排程器服務的詳細資訊,請流覽 排程器 頁面。
雖然此範例未顯示,但排程器可能需要保留提交訂單的應用程式,告知訂單的進度和狀態。 應用程式和排程器會彼此隔離,以消除它們之間的任何相依性。 應用程式不知道哪個排程器實例正在處理訂單,而排程器不知道哪個特定應用程式實例張貼訂單。
若要允許報告訂單狀態,應用程式可以使用自己的私人回應佇列。 此回應佇列的詳細數據會包含在傳送至提交程式的要求中,這會在狀態存放區中包含這項資訊。 排程器接著會將訊息張貼至此佇列,指出訂單的狀態(已收到要求、訂單已完成、訂單失敗等等)。 它應該在這些訊息中包含訂單標識碼,以便與應用程式的原始要求相互關聯。
下一步
實作此模式時,下列指引也可能相關:
異步傳訊入門。 排程器代理程式監督員模式中的元件通常會彼此分離,並以異步方式通訊。 描述一些方法,這些方法可用來根據消息佇列實作異步通訊。
參考 6:傳奇的傳奇。 顯示 CQRS 模式如何使用進程管理員的範例(CQRS 旅程指引的一部分)。
相關資源
實作此模式時,下列模式也可能相關: