【博文目錄>>>】
計算資源整合模式
將多個任務或操作整合到一個計算單元中。這種模式可以提高計算資源利用率,並減少與在雲託管應用程序中執行計算處理相關的成本和管理開銷。
背景與問題
雲應用程序經常實現各種操作。在某些解決方案中,最初可能會遵循關注點分離的設計原則,並將這些操作劃分爲單獨託管和部署的離散計算單元(例如,作爲Microsoft Azure Cloud Service中的單獨角色,單獨的Azure網站,或單獨的虛擬機)。但是,儘管此策略可以幫助簡化解決方案的邏輯設計,但是將大量計算單元部署爲同一應用程序的一部分可能會增加運行時託管成本,並使系統的管理更加複雜
作爲示例,圖1顯示了使用多個計算單元實現的雲託管解決方案的簡化結構。每個計算單元都在其自己的虛擬環境中運行。每個功能已實現爲在其自己的計算單元中運行的單獨任務(標記爲任務A至任務E)
圖1-使用一組專用計算單元在雲環境中運行任務
每個計算單元即使在空閒或輕度使用時也會消耗可計費的資源。因此,這種方法可能並不總是最經濟高效的解決方案。
在Azure中,此問題適用於雲服務、網站和虛擬機中的角色。這些東西在它們自己的虛擬環境中執行。運行一組單獨的角色、網站或虛擬機,這些操作旨在執行一組定義良好的操作,但這些操作需要作爲單個解決方案的一部分進行通信和協作,這可能會導致資源利用效率低下。
解決方案
爲了幫助降低成本、提高利用率、提高通信速度和簡化管理工作,可以將多個任務或操作合併到一個計算單元中。
任務可以根據各種標準進行分組,分組標準是基於環境提供的功能以及與這些功能相關的成本。一種常見的方法是查找在可伸縮性、生存期和處理需求方面具有類似配置文件的任務。將這些項目組合在一起可以使它們作爲一個單位進行擴展。許多雲環境提供的彈性使計算單元的其他實例能夠根據工作負載啓動和停止。例如Azure提供了自動縮放功能,可以應用於雲服務、網站和虛擬機中的角色。有關更多信息,請參見自動縮放指導.
作爲說明如何使用可伸縮性來確定哪些操作不應該組合在一起的反例,請考慮以下兩個任務:
- 任務1輪詢發送到隊列的不頻繁、時間不敏感的消息.
- 任務2處理大量的網絡通信.
第二個任務需要彈性,這可能涉及啓動和停止大量的計算單元實例。將相同的縮放比例應用於第一個任務只會導致更多任務監聽同一隊列上的不頻繁消息,並且浪費資源。
在許多雲環境中,可以根據CPU核的數量、內存、磁盤空間等來指定計算單元可用的資源。一般來說,指定的資源越多,成本就越高。爲了提高財務效率,重要的是最大限度地提高昂貴的計算單元執行的工作量,並且不要讓其長時間處於閒置狀態。
如果有任務在短時間內需要大量CPU能力,請考慮將這些任務合併到一個提供必要能力的單個計算單元中。但是,重要的是要平衡這種需求,以使昂貴的資源繁忙,避免因壓力過大而發生爭用。例如,長時間運行的計算密集型任務可能不應共享相同的計算單元。
問題和思考
在實現此模式時,請考慮以下幾點:
- 可擴展性和彈性。許多雲解決方案通過啓動和停止單元實例在計算單元級別實現可伸縮性和彈性。避免在同一計算單元中對具有可伸縮性要求衝突的任務進行分組。
- 生命週期。雲基礎設施可以定期回收承載計算單元的虛擬環境。在計算單元內執行許多長期運行的任務時,可能需要配置該單元,以防止其在這些任務完成之前被回收。或者,使用檢查點方法設計任務,使它們能夠乾淨地停止,並在計算單元重新啓動時被中斷時繼續執行。
- 釋放節奏。如果任務的實現或配置經常更改,則可能需要停止託管更新代碼的計算單元,重新配置和重新部署該單元,然後重新啓動它。此過程還需要停止、重新部署和重新啓動同一計算單元中的所有其他任務。
- 安全。同一計算單元中的任務可以共享相同的安全上下文,並且能夠訪問相同的資源。任務之間必須高度信任,並確信一個任務不會損壞或對另一個任務產生不利影響。此外,增加在計算單元中運行的任務數量可能會增加計算單元的攻擊面;每個任務僅與漏洞最多的任務一樣安全。
- 容錯能力。如果計算單元中的一項任務失敗或行爲異常,則可能會影響同一單元中運行的其他任務。例如,如果一項任務無法正確啓動,則可能導致計算單元的整個啓動邏輯失敗,並阻止同一單元中的其他任務運行。
- 爭用。避免在爭用同一計算單元中的資源的任務之間引入競爭。理想情況下,共享相同計算單元的任務應表現出不同的資源利用特徵。例如,兩個計算密集型任務可能不應該駐留在同一計算單元中,並且兩個消耗大量內存的任務也不應駐留在同一計算單元中。但是,將計算密集型任務與需要大量內存的任務混合在一起可能是可行的組合。
注
您應該考慮僅爲已投入生產一段時間的系統整合計算資源,以便操作員和開發人員可以監視系統並創建熱圖,該熱圖可以標識每個任務如何利用不同的資源。該映射可用於確定哪些任務是共享計算資源的理想選擇。
- 複雜性。將多個任務組合到一個計算單元中會增加該單元中代碼的複雜性,可能使測試,調試和維護更加困難。
- 穩定的邏輯體系結構。設計並實現每個任務中的代碼,以便即使運行任務的物理環境發生了變化,也無需更改代碼。
- 其他策略。整合計算資源只是幫助減少與同時運行多個任務相關的成本的一種方法。它需要仔細的計劃和監視,以確保它仍然是一種有效的方法。其他策略可能更合適,具體取決於正在執行的工作的性質以及代表這些任務運行的用戶的位置。例如,工作負載的功能分解(如計算分區指南)也許是一個更好的選擇。
何時使用此模式
如果任務以自己的計算單位運行,則對成本不高的任務使用此模式。如果任務花費大量時間空閒,則在專用單元中運行此任務可能會很昂貴。
這種模式可能不適合執行關鍵容錯操作的任務,也不適合處理高度敏感或私有數據並需要自己的安全上下文的任務。這些任務應該在自己獨立的環境中運行,在一個單獨的計算單元中運行。
示例
在Azure上構建雲服務時,可以將多個任務執行的處理整合到一個角色中。通常,這是一個執行後臺或異步處理任務的工作人員角色。
注
在某些情況下,可以在web角色中包括後臺或異步處理任務。這種技術可以幫助降低成本和簡化部署,儘管它會影響Web角色提供的面向公共接口的可伸縮性和響應性。將多個Azure工作者角色組合爲Azure Web角色的文章包含有關在Web角色中實現後臺或異步處理任務的詳細說明。
該角色負責啓動和停止任務。當Azure構造控制器加載角色時,它將引發該角色的Start事件。您可以重寫WebRole或WorkerRole類的OnStart方法來處理此事件,也許可以初始化此方法中的任務所依賴的數據和其他資源。
當OnStart方法完成時,角色可以開始響應請求。您可以在模式和實踐指南將應用程序遷移到雲端的應用程序啓動過程部分中找到有關角色使用OnStart和Run方法的更多信息和指南。
注
保持OnStart方法中的代碼儘可能簡潔。Azure對該方法完成所花費的時間沒有施加任何限制,但是在此方法完成之前,該角色將無法開始響應發送給它的網絡請求。
OnStart方法完成後,角色將執行Run方法。此時,結構控制器可以開始向角色發送請求。
將實際創建任務的代碼放在Run方法中。請注意,Run方法有效地定義了角色實例的生存期。此方法完成後,結構控制器將安排角色關閉。
當角色關閉或被回收時,結構控制器將阻止從負載均衡器接收到更多傳入請求,並引發Stop事件。您可以通過重寫角色的OnStop方法來捕獲此事件,並在角色終止之前執行所有必要的整理工作。
注
必須在五分鐘內(如果您在本地計算機上使用Azure模擬器,則必須在30秒內)完成在OnStop方法中執行的所有操作;否則,Azure結構控制器將假定角色已停止並強制其停止。
圖2說明了角色的生命週期以及它所承載的任務和資源。任務由Run方法啓動,然後等待任務完成。任務本身實現了雲服務的業務邏輯,可以響應通過Azure負載均衡器發佈到角色的消息。
圖2-Azure雲服務中角色中的任務和資源的生命週期
ComputeResourceConsolidation.Worker項目中的WorkerRole.cs文件顯示瞭如何在Azure雲服務中實現此模式的示例。
注
Worker項目是ComputeResourceCombination解決方案的一部分,該解決方案可與本指南一起下載。
在工作角色中,初始化角色時運行的代碼將創建所需的取消令牌和要運行的任務列表。
public class WorkerRole: RoleEntryPoint{
// The cancellation token source used to cooperatively cancel running tasks.
private readonly CancellationTokenSource cts = new CancellationTokenSource ();
// List of tasks running on the role instance.
private readonly List<Task> tasks = new List<Task>();
// List of worker tasks to run on this role.
private readonly List<Func<CancellationToken, Task>> workerTasks
= new List<Func<CancellationToken, Task>>{ MyWorkerTask1, MyWorkerTask2};
...
}
提供MyWorkerTask1和MyWorkerTask2方法是爲了說明如何在同一輔助角色中執行不同的任務。以下代碼顯示MyWorkerTask1。這是一個簡單的任務,它休眠30秒鐘,然後輸出跟蹤消息。它無限期地重複此過程,直到任務被取消。 MyWorkerTask2中的代碼非常相似。
// A sample worker role task.private static async Task
MyWorkerTask1(CancellationToken ct){
// Fixed interval to wake up and check for work and/or do work.
var interval = TimeSpan.FromSeconds(30);
try {
while (!ct.IsCancellationRequested) {
// Wake up and do some background processing if not canceled.
// TASK PROCESSING CODE HERE
Trace.TraceInformation("Doing Worker Task 1 Work");
// Go back to sleep for a period of time unless asked to cancel.
// Task.Delay will throw an OperationCanceledException when canceled. await Task.Delay(interval, ct);
}
} catch (OperationCanceledException) {
// Expect this exception to be thrown in normal circumstances or check
// the cancellation token. If the role instances are shutting down, a
// cancellation request will be signaled.
Trace.TraceInformation("Stopping service, cancellation requested");
// Re-throw the exception.
throw;
}
}
注
示例代碼顯示的方法是後臺進程的常見實現。在現實世界中的應用程序中,您可以遵循相同的結構,只是您應將自己的處理邏輯放在等待取消請求的循環主體中。
在工作角色初始化其使用的資源後,Run方法將同時啓動兩個任務,如下所示。。
// RoleEntry Run() is called after OnStart().
// Returning from Run() will cause a role instance to recycle.
public override void Run(){
// Start worker tasks and add them to the task list.
foreach (var worker in workerTasks)
tasks.Add(worker(cts.Token));
Trace.TraceInformation("Worker host tasks started");
// The assumption is that all tasks should remain running and not return,
// similar to role entry Run() behavior.
try {
Task.WaitAny(tasks.ToArray());
} catch (AggregateException ex) {
Trace.TraceError(ex.Message);
// If any of the inner exceptions in the aggregate exception
// are not cancellation exceptions then re-throw the exception. ex.Handle(innerEx => (innerEx is OperationCanceledException));
}
// If there was not a cancellation request, stop all tasks and return from Run()
// An alternative to cancelling and returning when a task exits would be to
// restart the task.
if (!cts.IsCancellationRequested) {
Trace.TraceInformation("Task returned without cancellation request"); Stop(TimeSpan.FromMinutes(5));
}
}
...
在此示例中,Run方法等待任務完成。如果取消了任務,則Run方法將假定該角色已關閉,並等待剩餘的任務在完成之前被取消(它最多等待五分鐘才能終止)。 如果任務由於預期的異常而失敗,則Run方法將取消該任務。
注
請注意,您可以在Run方法中實施更全面的監視和異常處理策略,例如重新啓動失敗的任務,或包括使角色停止和啓動單個任務的代碼。
當結構控制器關閉角色實例時,將調用以下代碼中所示的Stop方法(從OnStop方法調用)。該代碼通過取消它來優雅地停止每個任務。如果完成任何任務需要五分鐘以上的時間,則Stop方法中的取消處理將停止等待並終止該角色。
// Stop running tasks and wait for tasks to complete before returning
// unless the timeout expires.
private void Stop(TimeSpan timeout){
Trace.TraceInformation("Stop called. Canceling tasks.");
// Cancel running tasks.
cts.Cancel();
Trace.TraceInformation("Waiting for canceled tasks to finish and return");
// Wait for all the tasks to complete before returning. Note that the
// emulator currently allows 30 seconds and Azure allows five
// minutes for processing to complete.
try {
Task.WaitAll(tasks.ToArray(), timeout);
} catch (AggregateException ex) {
Trace.TraceError(ex.Message);
// If any of the inner exceptions in the aggregate exception
// are not cancellation exceptions then re-throw the exception. ex.Handle(innerEx => (innerEx is OperationCanceledException));
}
}
相關模式和指導
在實施這一模式時,下列模式和指導也可能相關:
- 自動縮放指導。根據預期的處理需求,可以使用自動縮放來啓動和停止託管計算資源的服務實例。
- 計算分區指南。本指南介紹瞭如何在保持服務的可伸縮性,性能,可用性和安全性的同時,幫助您將雲服務中的服務和組件分配到最小的方式,以最大程度地降低運行成本。
更多信息
- 博客文章將多個Azure工作者角色組合爲Azure Web角色.
- 在MSDN上,模式和實踐指南中章節的應用程序啓動過程部分介紹了將應用程序遷移到雲中。
該模式具有與之關聯的示例應用程序。您可以從Microsoft下載中心下載:http://aka.ms/cloud-design-patterns-sample
原文鏈接
https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589778%28v%3dpandp.10%29