# 云計算設計模式(二十)——調度程序代理管理者模式
協調一系列在分布式服務集和其他遠程資源的的行為,試圖透明地處理故障,如果這些操作失敗,或撤銷,如果系統不能從故障中恢復執行工作的影響。這種模式可以分布式系統中增加彈性和靈活性,使之恢復和重試失敗是由于短暫的異常,持久的故障和處理故障等操作。
[TOC=2,2]
## 背景和問題
應用程序執行其包括多個步驟,其中的一些可以調用遠程服務或訪問遠程資源的任務。各個步驟可以是相互獨立的,但它們是由實現該任務的應用程序邏輯編排。
只要有可能,應用程序應該確保任務運行完成和解決遠程訪問服務或資源時可能發生的任何故障。可能會因各種原因,這些故障。例如,該網絡可能是崩潰,通信可能被中斷,遠程服務可能停止響應或處于不穩定的狀態,或遠程資源可能暫時無法訪問,可能由于資源約束。在許多情況下,這些故障可能是暫時的,并且可以通過使用重試模式進行處理。
如果該應用程序檢測到一個更永久的故障,從它可以不容易恢復,它必須能夠將系統恢復到一致狀態,并確保整個端至端的操作的完整性。
## 解決方案
調度代理管理者模式定義了以下角色。這些演員編排的步驟(工作,單個項目)將作為任務(整個過程)的一部分進行:
- 調度安排構成的整體任務要執行,并配合它們的操作的各個步驟。可按照下列步驟組合成一個管道或工作流,并且所述調度器是負責確保在這個工作流程中的步驟,以適當的順序被執行。作為各步驟中進行(如“步驟還未開始”,“步運行時,”或“步驟完成”),并記錄有關該狀態的信息的調度器維護關于工作流的狀態信息。這個狀態信息也應包括的允許的步驟來完成(稱為完全按時間)的時間的上限。如果一個步驟需要訪問遠程服務或資源時,調度程序調用適當的代理程序,通過它的工作的細節將被執行。調度通常采用異步請求/響應消息與代理進行通訊。這可以通過使用隊列來實現,盡管也可以使用其它分布式消息傳遞技術來代替。
> 注意: 調度程序執行類似的功能,以在流程管理模式的過程管理器。實際工作流程通常被定義并通過由該調度器所控制的工作流引擎來實現。這種方法分離了業務邏輯從調度的工作流程。
- 代理包含邏輯,封裝調用一個遠程服務,或訪問由在一個任務的步驟中引用的遠程資源。每個代理通常通過它可以調用單個服務或資源,實施相應的錯誤處理和重試邏輯(如有超時限制,稍后說明)。如果由調度程序所運行的工作流中的步驟利用在不同步驟的若干服務和資源,每個步驟可能會引用不同代理(這是其中的模式的實現細節)。
- 監監視由調度正在執行中的任務步驟的狀態。它運行周期(頻率將系統專用),檢查的步驟,通過調度為保持狀態。如果檢測到任何已超時或失敗,它會安排相應的代理來恢復步驟或執行相應的補救措施(這可能涉及修改步驟的狀態)。注意,恢復或補救行動通常由調度器和代理執行。主管應該簡單地要求這些行動來執行。
調度程序,代理和管理者是邏輯組件和它們的物理實現取決于所使用的技術。例如,若干個邏輯代理可以被實現為一個單一的網絡服務的一部分。
調度器維護關于任務的進度和持久的數據存儲中的每個步驟中,被稱為狀態存儲的狀態信息。主管可以使用此信息來幫助確定一個步驟是否出現故障。圖1說明了調度程序的代理,監事和狀態存儲之間的關系。

圖1 - 在調度程序代理管理者模式的演員
注意:
此圖顯示的模式的簡化圖。在實際的實現中,有可能是調度程序的多個實例同時運行的任務的每個子集。類似地,系統可以運行每個代理程序的多個實例,或者甚至多個監控器。在這種情況下,主管必須協調其與對方認真的工作,以確保它們不會爭來恢復同樣失敗的步驟和任務。在領導人選舉模式提供一個可能的解決了這個問題。
何時一個應用程序希望執行一個任務,它提交一個請求給調度程序。調度記錄有關的任務及其步驟(例如,“步驟還未開始”)中的狀態存儲的初始狀態的信息,然后開始執行由流程定義的操作。作為調度程序開始每一步時,它將更新關于該步驟中的狀態存儲(例如,“步運行的”)的狀態的信息。
如果一個步驟引用遠程服務或資源時,調度程序將消息發送給適當代理。該消息可以包含代理需要傳遞給服務或訪問該資源,除了完整的通過時間的操作的信息。如果代理成功完成其操作時,它返回到調度程序的響應。然后調度程序可以更新在狀態存儲的狀態信息(例如,“步驟完成”),并進行下一步驟。這個過程繼續,直到整個任務完成。
代理可以實現任意重試邏輯需要執行它的工作。但是,如果該代理之前,完成未完成其工作期間屆滿的調度程序就會認為操作失敗。在這種情況下,代理應該停止其工作,并沒有試圖東西返回到調度程序(甚至沒有錯誤消息),或者進行任何形式的恢復。這樣做的原因的限制是,后一步驟中已超時或失敗,則代理的另一個實例可被調度來運行失敗的步驟(該過程將在后面描述)。
如果代理本身出現故障時,調度程序將不會收到回復。該模式可能不會讓這一步驟已超時,一個已經失敗的真正區別。
如果一個步驟超時或失敗時,狀態存儲將包含一個記錄,指出該步驟是否正在運行(“步驟運行”),但完全通過時間已經過去了。監事查找步驟,如本,并試圖恢復它們。一個可能的策略是為超級更新完成由值來擴展可用來完成步驟的時間,然后將消息發送到調度器識別已超時的步驟。然后,調度程序可以嘗試重復此步驟。然而,這樣的設計要求為冪等的任務。
這可能是必需的管理者防止如果連續失敗或者超時被重試相同步驟。為了實現這一點,對管理可維持一個重試計數為每一步,隨著狀態信息,在該狀態存儲。如果該計數超過預定閾值的管理者可以采用一種策略,例如,通知它應重試步驟中,在期望的故障將在這段時間內可以解決調度之前等待較長的時間。或者,該管理者可以將消息發送到調度請求將整個任務通過實現補償交易被撤消(該方法將依賴于調度程序和代理提供所必需的信息,以實現對已成功完成各步驟的補償操作)。
注意:
這不是管理者的目的來監控調度程序和代理商,如果他們不能重新啟動它們。系統的這方面應該由其中這些組件所運行的基礎設施進行處理。同樣,管理者不應該是由調度所執行的任務正在運行(包括如何補償應這些任務失敗)的實際業務運作的知識。這是由調度程序執行的工作流邏輯的目的。監事的責任是確定的步驟是否已失敗,并安排要么為它重復或者包含失敗的步驟,整個任務被取消。
如果該調度程序是失敗的,或者工作流程后,重新啟動正在由調度程序進行意外終止,該調度程序應能確定任何飛行任務,這是處理失敗時的狀態,并準備繼續這個任務從該點上失敗了。該方法的實現細節都可能是特定的系統。如果任務不能恢復,這可能是必要的,以撤消該任務已經完成的工作。這可能還需要執行一個補償事務。
這種模式的主要優點是,該系統是彈性的意想不到的臨時或不可恢復故障的情況下。該系統可以構造成可自愈。例如,如果一個代理程序或調度程序崩潰時,一個新的可啟動的,因而管理可以安排要恢復的任務。如果管理者發生故障,另一實例可以啟動,并且可以從發生故障的接管。如果管理者計劃定期運行,一個新的實例可以被自動預定義的時間間隔后啟動。該狀態存儲可以被復制以實現更大程度的彈性。
## 問題和注意事項
在決定如何實現這個模式時,您應考慮以下幾點:
- 該圖案可以是平凡的執行,并且需要的系統的每個可能的故障模式的全面測試。
- 通過調度實現的恢復/重試邏輯可以是復雜的并且依賴于狀態存儲保持狀態信息。它也可能是必要的,記錄在一個持久的數據存儲區執行一個補償事務處理所需的信息。
- 與監事運行是非常重要的頻率。它應該運行足夠頻繁,以防止任何失敗堵塞長時間的應用程序的步驟,但它不應該運行非常頻繁,它成為一個開銷。
- 由代理執行的步驟可以被執行一次以上。實現這些步驟的邏輯應該是冪等。
## 何時使用這個模式
使用這種模式時,在分布式環境中運行,例如云的方法必須是有彈性的,以通信故障和/或運行故障。
這種模式可能不適合任務不調用遠程服務或訪問遠程資源。
## 例子
實現一個電子商務系統中的 Web 應用程序已經部署在微軟的 Azure。用戶可以運行此應用程序來瀏覽提供一個組織的產品,下訂單,這些產品。用戶接口運行作為一個網絡的作用,并且該應用程序的命令處理元件被實現為一組工作角色。訂單處理邏輯的一部分包括訪問遠程服務,該系統的這一方面可能是易發生的瞬態或更持久的故障。為此,設計師使用了調度程序代理管理者模式實現了系統的訂單處理單元。
當客戶下訂單時,應用程序構建了一個消息,說明的順序和該職位的消息到隊列中。一個單獨的提交過程中,工人的角色運行,檢索此消息,將訂單到訂單數據庫的詳細信息,并為在國家商店的訂單流程的記錄。請注意,插入到常規數據庫和國家存儲作為同一操作的一部分執行。提交過程的設計,以確保兩個刀片共同完成。
該提交進程創建的訂單包括狀態信息:
- 訂單ID:在訂單數據庫中的訂單的 ID。
- LockedBy:的輔助角色的處理順序的實例 ID。有可能是運行調度程序的工人角色的多個電流情況下,但每個訂單只能通過一個實例來處理。
- CompleteBy:通過該命令應處理的時間。
- ProcessState:任務處理訂單的當前狀態。可能的狀態是:
- Pending:的順序已被創建,但處理尚未啟動。
- Processing:該命令正在處理中。
- Processed:訂單已成功處理。
- Error:訂單處理失敗。
- FailureCount:次數的處理已經嘗試了順序的號碼。
在這種狀態信息,OrderID 字段從新訂單的訂單 ID 復制。該 LockedBy 和 CompleteBy 字段設置為 null,則 ProcessState 字段設置為待定,并且 FailureCount 字段設置為 0。
注意:
在這個例子中,為了處理邏輯比較簡單,只包括一個調用的遠程服務的單個步驟。在一個更復雜的多步驟的情況下,提交過程很可能涉及多個步驟,所以多個記錄將在狀態存儲,每一個描述了一個單獨的步驟中的狀態被創建。
該調度程序同時作為一個輔助角色的一部分,實現了處理訂單的業務邏輯。調度輪詢新訂單的一個實例探討了狀態存儲的記錄,其中 LockedBy 字段為空,并在 ProcessState 場待定。何時調度程序發現一個新的訂單,立刻填充LockedBy 字段與它自己的實例 ID,設置 CompleteBy 字段到一個適當的時間,并設置 ProcessState 字段來處理。執行此代碼的設計是獨特和原子,以確保調度程序的兩個并發實例不能試圖同時處理的順序相同。
調度程序將運行業務流程處理訂單異步,從狀態存儲傳遞給它的值在 OrderID 字段。工作流處理的順序檢索來自數據庫的訂單訂單的詳細信息,并執行其工作。當訂單處理流程的步驟需要調用遠程服務,它使用一個代理。在工作流步驟的代理通過利用對作為請求/響應信道 Azure 的服務總線消息隊列進行通信。圖2示出了該解決方案的一個高層視圖。

圖2 - 使用調度程序代理管理者模式在 Azure 的解決方案來處理訂單
從一個工作流步驟發送到代理的消息描述的順序,并包括 CompleteBy 時間。如果代理接收來自遠程服務的響應的 CompleteBy 時間到期之前,構建其上的服務總線隊列在其上的工作流是聽張貼答復消息。當工作流步驟接收到有效的應答消息,它完成它的處理和調度臺的訂單狀態 ProcessState 場處理。在這一點上,為了處理已成功完成。
如果 CompleteBy 時間到期的代理接收來自遠程服務的響應之前,代理簡單地停止其處理,并終止處理順序。類似地,如果工作流處理的順序超過了 CompleteBy 時,它也將終止。在這兩種情況下,在該狀態存儲在順序的狀態保持給定處理中,但 CompleteBy 時間指示的時間用于處理訂單已經過去,該處理判定為不合格。請注意,如果正在訪問遠程服務,或者正在處理的順序工作流(或兩者)的代理意外終止,在狀態存儲的信息將再次保持設置為處理,最終將有過期 CompleteBy 值。
如果代理檢測到不可恢復的非瞬時性故障當它正在嘗試聯系遠程服務,它可以發送一個錯誤響應返回到工作流。該調度程序可以設置為錯誤,并提出了警示操作者的事件的狀態。然后,操作者可以嘗試手動解決失敗的原因,并重新提交失敗的處理步驟。
主管定期檢查狀態存儲在尋找訂單,過期 CompleteBy 值。如果管理者發現這樣的記錄,它增加了 FailureCount 領域。如果 FailureCount 值低于規定的閾值時,所述管理者復位 LockedBy 字段為空,更新 CompleteBy 場與新的到期時間,并設置 ProcessState 字段待定。調度程序的一個實例可以拿起這個命令并執行其處理如前。如果 FailureCount 值超過特定閾值時,對故障的原因被假定為非瞬態。監事設置為錯誤的狀態,并引發了警報操作,如前所述的事件。
注意:在這個例子中,管理者是在一個單獨的工作任務落實。您可以使用各種策略來安排監理任務運行,包括使用 Azure 的計劃程序服務(不要與計劃程序組件在此模式相混淆)。關于Azure的計劃程序服務的更多信息,請訪問調度程序頁面。
雖然未在本實施例中所示,該調度程序可能需要保留在通知關于單的進度及狀態首位提交的順序應用。應用程序和調度程序彼此分離,以消除它們之間的任何相關性。該應用程序并不知道哪個調度的實例處理的順序,調度不知道它的具體應用實例發布的順序。
為使訂單狀態予以報道,該應用程序可以使用自己的私人響應隊列。這個響應隊列的詳細信息將被納入送往提交過程的要求,其中包括在狀態存儲這些信息的一部分。該調度程序隨后將郵件投遞到該隊列表示訂單的狀態(“接收到的請求”,“為了完成”,“訂單失敗”,等等)。它應包括訂單ID在這些消息中,以便它們可以與由該應用程序的原始請求相關聯。
- 前言
- (一)—— 緩存預留模式
- (二)—— 斷路器模式
- (三)—— 補償交易模式
- (四)——消費者的競爭模式
- (五)——計算資源整合模式
- (六)——命令和查詢職責分離(CQRS)模式
- (七)——事件獲取模式
- (八)——外部配置存儲模式
- (九)—— 聯合身份模式
- (十)——守門員模式
- (十一)—— 健康端點監控模式
- (十二)—— 索引表模式
- (十三)——領導人選舉模式
- (十四)——實體化視圖模式
- (十五)—— 管道和過濾器模式
- (十六)——優先級隊列模式
- (十七)—— 基于隊列的負載均衡模式
- (十八)—— 重試模式
- (十九)——運行重構模式
- (二十)—— 調度程序代理管理者模式
- (二十一)——Sharding 分片模式
- (二十二)——靜態內容托管模式
- (二十三)——Throttling 節流模式
- (二十四)—— 仆人鍵模式