優(yōu)先發(fā)送到服務(wù),以便具有較高優(yōu)先級(jí)的請(qǐng)求被接收和高于一個(gè)較低優(yōu)先級(jí)的更快速地處理請(qǐng)求。這種模式是在應(yīng)用程序是有用的,它提供不同的服務(wù)級(jí)別保證或者針對(duì)獨(dú)立客戶。
應(yīng)用程序可以委托給其他服務(wù)的具體任務(wù);例如,為了執(zhí)行后臺(tái)處理或與其他應(yīng)用程序或服務(wù)的整合。在云中,消息隊(duì)列通常用于將任務(wù)委派給后臺(tái)處理。在許多情況下,請(qǐng)求由服務(wù)接收的順序是不重要的。然而,在某些情況下,可能需要優(yōu)先考慮的具體要求。這些要求必須早于較低優(yōu)先級(jí)的其他可能先前已發(fā)送由應(yīng)用程序進(jìn)行處理。
隊(duì)列通常是先入先出(FIFO)結(jié)構(gòu),而消費(fèi)者通常會(huì)收到他們發(fā)布到隊(duì)列中的順序相同的消息。然而,一些消息隊(duì)列支持優(yōu)先級(jí)的消息傳遞;應(yīng)用程序發(fā)布一條消息可以分配優(yōu)先級(jí)的消息,并在隊(duì)列中的消息會(huì)自動(dòng)重新排序,使得具有較高優(yōu)先級(jí)的消息將這些優(yōu)先級(jí)較低的前被接收。圖1示出了一個(gè)隊(duì)列,它提供優(yōu)先權(quán)的消息。
圖1 - 使用支持消息優(yōu)先級(jí)排隊(duì)機(jī)制
注意: 大多數(shù)消息隊(duì)列的實(shí)現(xiàn)支持多個(gè)消費(fèi)者(以下的競(jìng)爭(zhēng)消費(fèi)者模式)和消費(fèi)過(guò)程的數(shù)量可以按比例增加或減小的需求支配。
在不支持基于優(yōu)先級(jí)的消息隊(duì)列系統(tǒng)中,一種替代的解決方案是為每一個(gè)優(yōu)先級(jí)的獨(dú)立隊(duì)列。該應(yīng)用程序負(fù)責(zé)將郵件投遞到適當(dāng)?shù)年?duì)列。每個(gè)隊(duì)列可以有一個(gè)單獨(dú)的消費(fèi)者池。高優(yōu)先級(jí)隊(duì)列可以有更快的硬件比低優(yōu)先級(jí)隊(duì)列中運(yùn)行的消費(fèi)者一個(gè)更大的泳池。圖2示出了這種方法。
圖2 - 使用不同的消息隊(duì)列為每個(gè)優(yōu)先級(jí)
這種策略的變化是有消費(fèi)者認(rèn)為檢查對(duì)高優(yōu)先級(jí)隊(duì)列中的消息,然后再才開(kāi)始從低優(yōu)先級(jí)隊(duì)列中讀取消息,如果沒(méi)有更高優(yōu)先級(jí)的消息都在等待的一個(gè)池。還有,使用消費(fèi)過(guò)程的一個(gè)池的溶液之間的一些語(yǔ)義差異(或者使用支持不同的優(yōu)先級(jí)或多個(gè)隊(duì)列,每個(gè)處理一個(gè)單一的優(yōu)先級(jí)消息的消息的單個(gè)隊(duì)列),以及使用多個(gè)隊(duì)列用溶液為每個(gè)隊(duì)列一個(gè)單獨(dú)的游泳池。
在單池的做法,高優(yōu)先級(jí)的消息總是會(huì)收到以前低優(yōu)先級(jí)的消息處理。在理論中,具有非常低的優(yōu)先級(jí)的消息可以被不斷地取代,并且可能永遠(yuǎn)不會(huì)被處理。在多池的方法,較低優(yōu)先級(jí)的報(bào)文將總是被處理,只是不一樣迅速的那些更高的優(yōu)先級(jí)的(取決于池和它們具有可用資源的相對(duì)大?。?。
使用優(yōu)先級(jí)排隊(duì)機(jī)制可提供以下優(yōu)點(diǎn):
在決定如何實(shí)現(xiàn)這個(gè)模式時(shí),請(qǐng)考慮以下幾點(diǎn):
這種模式非常適合場(chǎng)景:
微軟 Azure 不提供經(jīng)過(guò)整理的本地支持郵件自動(dòng)優(yōu)先級(jí)排隊(duì)機(jī)制。然而,它確實(shí)提供了 Azure 的服務(wù)總線主題和訂閱,支持排隊(duì)機(jī)制,提供郵件過(guò)濾,具有多種靈活的功能,使其非常適合用在幾乎所有的優(yōu)先級(jí)隊(duì)列的實(shí)現(xiàn)在一起。
一個(gè) Azure 的解決方案,可以實(shí)現(xiàn)服務(wù)總線話題,其中一個(gè)應(yīng)用程序可以發(fā)布消息,以同樣的方式作為一個(gè)隊(duì)列。消息可以包含在應(yīng)用程序定義的自定義屬性的形式的元數(shù)據(jù)。服務(wù)總線訂閱可以與主題相關(guān)聯(lián),并且這些訂閱可以篩選根據(jù)它們的屬性信息。當(dāng)一個(gè)應(yīng)用程序?qū)⑾l(fā)送到一個(gè)主題,該消息被定向到從那里它可以被消費(fèi)者閱讀相應(yīng)的訂閱。消費(fèi)者的過(guò)程可以檢索使用相同的語(yǔ)義消息隊(duì)列(訂閱是一個(gè)邏輯隊(duì)列)從一個(gè)訂閱消息。
圖 3 示出了使用的 Azure 服務(wù)總線主題和訂閱的解決方案
圖3 - 實(shí)現(xiàn)與 Azure 的服務(wù)總線主題和訂閱優(yōu)先級(jí)隊(duì)列
在圖3中的應(yīng)用程序創(chuàng)建多個(gè)消息和每個(gè)消息與價(jià)值分配被稱為優(yōu)先級(jí)的自定義屬性,無(wú)論是高還是低。該應(yīng)用程序的帖子,這些消息的一個(gè)話題。這個(gè)主題有兩個(gè)相關(guān)的訂閱,這兩個(gè)濾波器的消息通過(guò)檢查優(yōu)先級(jí)屬性。一位接受認(rèn)購(gòu),其中優(yōu)先級(jí)屬性設(shè)置為高的消息,而其他接受其中優(yōu)先級(jí)屬性設(shè)置為低的消息。消費(fèi)者池讀取每個(gè)訂閱的消息。高優(yōu)先認(rèn)購(gòu)有較大的游泳池,而這些消費(fèi)者可能會(huì)更強(qiáng)大(且昂貴)的計(jì)算機(jī)上運(yùn)行有提供比消費(fèi)者在低優(yōu)先級(jí)池的更多資源。
請(qǐng)注意,沒(méi)有什么特別的高,低優(yōu)先級(jí)消息在這個(gè)例子中指定。這些僅僅是指定為每個(gè)消息中的屬性的標(biāo)簽,并用于引導(dǎo)消息發(fā)送到一個(gè)特定的訂閱。如果附加的優(yōu)先級(jí)是必需的,它是比較容易地創(chuàng)建進(jìn)一步的訂閱和消費(fèi)者進(jìn)程池來(lái)處理這些優(yōu)先級(jí)。
在可用于此引導(dǎo)代碼時(shí) Queue 解決方案包含這種方法的一個(gè)實(shí)現(xiàn)。該解決方案包含一個(gè)名為 PriorityQueue.High 和 PriorityQueue.Low 兩個(gè)工作角色的項(xiàng)目。這兩個(gè)輔助角色繼承的類被稱為 PriorityWorkerRole 它包含用于連接到一個(gè)指定的預(yù)訂中 OnStart 方法的功能。
該 PriorityQueue.High 和 PriorityQueue.Low 輔助角色連接到不同的預(yù)訂,他們的配置設(shè)置來(lái)定義。管理員可以配置每個(gè)角色的不同數(shù)量要運(yùn)行;通常會(huì)有比 PriorityQueue.Low 工作者角色的 PriorityQueue.High 輔助角色更多的實(shí)例。
在 PriorityWorkerRole 類的 Run 方法安排虛擬 ProcessMessage 的方法(在 PriorityWorkerRole 類定義)的隊(duì)列中接收到的每個(gè)消息被執(zhí)行。下面的代碼顯示了運(yùn)行和 ProcessMessage 的方法。在類的 QueueManager,在 PriorityQueue.Shared 項(xiàng)目定義,提供了輔助方法使用的 Azure 服務(wù)總線隊(duì)列。
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 的方法的默認(rèn)功能。下面的代碼顯示了 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);
}
當(dāng)一個(gè)應(yīng)用程序?qū)⑾l(fā)布到與所使用的 PriorityQueue.High 和 PriorityQueue.Low 輔助角色的訂閱相關(guān)聯(lián)的主題,它指定了優(yōu)先使用優(yōu)先級(jí)的自定義屬性,如在下面的代碼示例。此代碼(這是在 PriorityQueue.Sender項(xiàng)目 WorkerRole 類實(shí)現(xiàn)),使用的 QueueManager 類的 SendBatchAsync 輔助方法發(fā)帖分批的話題。
// 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();
更多建議: