# 云計算設計模式(十六)——優先級隊列模式
優先發送到服務,以便具有較高優先級的請求被接收和高于一個較低優先級的更快速地處理請求。這種模式是在應用程序是有用的,它提供不同的服務級別保證或者針對獨立客戶。
## 背景和問題
應用程序可以委托給其他服務的具體任務;例如,為了執行后臺處理或與其他應用程序或服務的整合。在云中,消息隊列通常用于將任務委派給后臺處理。在許多情況下,請求由服務接收的順序是不重要的。然而,在某些情況下,可能需要優先考慮的具體要求。這些要求必須早于較低優先級的其他可能先前已發送由應用程序進行處理。
## 解決方案
隊列通常是先入先出(FIFO)結構,而消費者通常會收到他們發布到隊列中的順序相同的消息。然而,一些消息隊列支持優先級的消息傳遞;應用程序發布一條消息可以分配優先級的消息,并在隊列中的消息會自動重新排序,使得具有較高優先級的消息將這些優先級較低的前被接收。圖1示出了一個隊列,它提供優先權的消息。

圖1 - 使用支持消息優先級排隊機制
> 注意: 大多數消息隊列的實現支持多個消費者(以下的競爭消費者模式)和消費過程的數量可以按比例增加或減小的需求支配。
在不支持基于優先級的消息隊列系統中,一種替代的解決方案是為每一個優先級的獨立隊列。該應用程序負責將郵件投遞到適當的隊列。每個隊列可以有一個單獨的消費者池。高優先級隊列可以有更快的硬件比低優先級隊列中運行的消費者一個更大的泳池。圖2示出了這種方法。

圖2 - 使用不同的消息隊列為每個優先級
這種策略的變化是有消費者認為檢查對高優先級隊列中的消息,然后再才開始從低優先級隊列中讀取消息,如果沒有更高優先級的消息都在等待的一個池。還有,使用消費過程的一個池的溶液之間的一些語義差異(或者使用支持不同的優先級或多個隊列,每個處理一個單一的優先級消息的消息的單個隊列),以及使用多個隊列用溶液為每個隊列一個單獨的游泳池。
在單池的做法,高優先級的消息總是會收到以前低優先級的消息處理。在理論中,具有非常低的優先級的消息可以被不斷地取代,并且可能永遠不會被處理。在多池的方法,較低優先級的報文將總是被處理,只是不一樣迅速的那些更高的優先級的(取決于池和它們具有可用資源的相對大小)。
使用優先級排隊機制可提供以下優點:
- 它允許應用程序以滿足必要的可用性或性能優先的業務需求,如提供不同級別的服務,以客戶的特定群體。
- 它可以幫助最大限度地降低運營成本。在單隊列的方式,你可以縮減用戶的數量,如果有必要的。高優先級消息仍將被首先處理(雖然可能更慢),和低優先級的消息可能會延遲更長。如果您已實現與消費者的每一個單獨的隊列池多個消息隊列的方式,可以減少消費者的池低優先級隊列,或者甚至停止所有監聽的訊息的消費者暫停處理一些非常低優先級隊列這些隊列。
- 在多個消息隊列的方法可以幫助劃分的基礎上處理要求的消息,以最大限度地提高應用程序的性能和可擴展性。例如,重要的任務,可以優先被立即運行,而不太重要的后臺任務可以被安排在不太繁忙的時段運行的接收器來處理接收處理。
## 問題和注意事項
在決定如何實現這個模式時,請考慮以下幾點:
- 定義優先級的解決方案的情況下。例如,“高優先級”可能意味著,信息應該在十秒內進行處理。標識要求處理高優先級的項目,以及其他什么資源必須分配給符合這些標準。
- 確定是否所有高優先級的項目必須在任何優先級較低的項目之前進行處理。如果該消息是由消費者的一個池被處理,可能有必要提供一種可搶先和暫停正在處理的低優先級消息,如果更高優先級的消息,有一個任務的機制。
- 在多個隊列中的方法,使用該監聽所有的隊列,而不是一個專門的客戶池的每個隊列的消費過程的一個池時,消費者必須應用一種算法,以確保它總是從那些從低之前較高優先級的隊列提供服務的消息優先級隊列。
- 監視處理的高和低優先級隊列中的速度,以確保在這些隊列中的消息的預期的速率進行處理。
- 如果需要,以保證低優先級的消息將被處理時,可能有必要實現與消費者的多個池的多個消息隊列的方法。或者,在一個支持消息優先隊列,它可能會動態地增加一個排隊的消息的優先級,因為它的年齡。然而,該方法依賴于消息隊列提供此功能。
- 使用單獨的隊列中每個消息優先級最適合有少數明確定義的優先級系統。
- 消息優先級可以通過系統邏輯決定的。例如,而不是明確的高和低優先級的消息,他們可以被指定為“自費客戶”,或“非自費的客戶。”根據您的商業模式,你的系統可能會分配更多的資源,從收費處理消息付費用戶比非自費的。
- 有可能是檢查隊列的消息相關聯的金融和處理成本(一些商業郵件系統的消息被發布或檢索每次收取一小筆費用,每次一個隊列中查詢消息)。檢查多個隊列時,該成本將有所增加。
- 它可以是能夠動態調整的基礎上,該池所服務的隊列的長度消費者的一個池的大小。欲了解更多信息,請參閱自動縮放指導。
## 何時使用這個模式
這種模式非常適合場景:
- 系統必須處理可能有不同的側重點多個任務。
- 不同的用戶或租戶應配以不同的優先級。
## 例子
微軟 Azure 不提供經過整理的本地支持郵件自動優先級排隊機制。然而,它確實提供了 Azure 的服務總線主題和訂閱,支持排隊機制,提供郵件過濾,具有多種靈活的功能,使其非常適合用在幾乎所有的優先級隊列的實現在一起。
一個 Azure 的解決方案,可以實現服務總線話題,其中一個應用程序可以發布消息,以同樣的方式作為一個隊列。消息可以包含在應用程序定義的自定義屬性的形式的元數據。服務總線訂閱可以與主題相關聯,并且這些訂閱可以篩選根據它們的屬性信息。當一個應用程序將消息發送到一個主題,該消息被定向到從那里它可以被消費者閱讀相應的訂閱。消費者的過程可以檢索使用相同的語義消息隊列(訂閱是一個邏輯隊列)從一個訂閱消息。
圖 3 示出了使用的 Azure 服務總線主題和訂閱的解決方案

圖3 - 實現與 Azure 的服務總線主題和訂閱優先級隊列
在圖3中的應用程序創建多個消息和每個消息與價值分配被稱為優先級的自定義屬性,無論是高還是低。該應用程序的帖子,這些消息的一個話題。這個主題有兩個相關的訂閱,這兩個濾波器的消息通過檢查優先級屬性。一位接受認購,其中優先級屬性設置為高的消息,而其他接受其中優先級屬性設置為低的消息。消費者池讀取每個訂閱的消息。高優先認購有較大的游泳池,而這些消費者可能會更強大(且昂貴)的計算機上運行有提供比消費者在低優先級池的更多資源。
請注意,沒有什么特別的高,低優先級消息在這個例子中指定。這些僅僅是指定為每個消息中的屬性的標簽,并用于引導消息發送到一個特定的訂閱。如果附加的優先級是必需的,它是比較容易地創建進一步的訂閱和消費者進程池來處理這些優先級。
在可用于此引導代碼時 Queue 解決方案包含這種方法的一個實現。該解決方案包含一個名為 PriorityQueue.High 和 PriorityQueue.Low 兩個工作角色的項目。這兩個輔助角色繼承的類被稱為 PriorityWorkerRole 它包含用于連接到一個指定的預訂中 OnStart 方法的功能。
該 PriorityQueue.High 和 PriorityQueue.Low 輔助角色連接到不同的預訂,他們的配置設置來定義。管理員可以配置每個角色的不同數量要運行;通常會有比 PriorityQueue.Low 工作者角色的 PriorityQueue.High 輔助角色更多的實例。
在 PriorityWorkerRole 類的 Run 方法安排虛擬 ProcessMessage 的方法(在 PriorityWorkerRole 類定義)的隊列中接收到的每個消息被執行。下面的代碼顯示了運行和 ProcessMessage 的方法。在類的 QueueManager,在 PriorityQueue.Shared 項目定義,提供了輔助方法使用的 Azure 服務總線隊列。
~~~
public class PriorityWorkerRole : RoleEntryPoint
{
private QueueManager queueManager;
...
?
public override void Run()
{
// Start listening for messages on the subscription.
var subscriptionName = CloudConfigurationManager.GetSetting("SubscriptionName");
this.queueManager.ReceiveMessages(subscriptionName, this.ProcessMessage);
...;
}
...
?
protected virtual async Task ProcessMessage(BrokeredMessage message)
{
// Simulating processing.
await Task.Delay(TimeSpan.FromSeconds(2));
}
}
~~~
該 PriorityQueue.High 和 PriorityQueue.Low 輔助角色既覆蓋 ProcessMessage 的方法的默認功能。下面的代碼顯示了 ProcessMessage 的方法為 PriorityQueue.High 輔助角色。
~~~
Copy
?
?
protected override async Task ProcessMessage(BrokeredMessage message)
{
// Simulate message processing for High priority messages.
await base.ProcessMessage(message);
Trace.TraceInformation("High priority message processed by " +
RoleEnvironment.CurrentRoleInstance.Id + " MessageId: " + message.MessageId);
}
~~~
當一個應用程序將消息發布到與所使用的 PriorityQueue.High 和 PriorityQueue.Low 輔助角色的訂閱相關聯的主題,它指定了優先使用優先級的自定義屬性,如在下面的代碼示例。此代碼(這是在 PriorityQueue.Sender項目 WorkerRole 類實現),使用的 QueueManager 類的 SendBatchAsync 輔助方法發帖分批的話題。
~~~
// Send a low priority batch.
var lowMessages = new List<BrokeredMessage>();
?
for (int i = 0; i < 10; i++)
{
var message = new BrokeredMessage() { MessageId = Guid.NewGuid().ToString() };
message.Properties["Priority"] = Priority.Low;
lowMessages.Add(message);
}
?
this.queueManager.SendBatchAsync(lowMessages).Wait();
...
?
// Send a high priority batch.
var highMessages = new List<BrokeredMessage>();
?
for (int i = 0; i < 10; i++)
{
var message = new BrokeredMessage() { MessageId = Guid.NewGuid().ToString() };
message.Properties["Priority"] = Priority.High;
highMessages.Add(message);
}
?
this.queueManager.SendBatchAsync(highMessages).Wait();
~~~
- 前言
- (一)—— 緩存預留模式
- (二)—— 斷路器模式
- (三)—— 補償交易模式
- (四)——消費者的競爭模式
- (五)——計算資源整合模式
- (六)——命令和查詢職責分離(CQRS)模式
- (七)——事件獲取模式
- (八)——外部配置存儲模式
- (九)—— 聯合身份模式
- (十)——守門員模式
- (十一)—— 健康端點監控模式
- (十二)—— 索引表模式
- (十三)——領導人選舉模式
- (十四)——實體化視圖模式
- (十五)—— 管道和過濾器模式
- (十六)——優先級隊列模式
- (十七)—— 基于隊列的負載均衡模式
- (十八)—— 重試模式
- (十九)——運行重構模式
- (二十)—— 調度程序代理管理者模式
- (二十一)——Sharding 分片模式
- (二十二)——靜態內容托管模式
- (二十三)——Throttling 節流模式
- (二十四)—— 仆人鍵模式