優先順序佇列模式

Azure 服務匯流排

設定傳送至服務的要求優先順序,以便接收和處理優先順序高於優先順序較低的要求。 此模式適用於為個別用戶端提供不同服務等級保證的應用程式。

內容和問題

應用程式可以將特定工作委派給其他服務,例如執行背景處理或與其他應用程式或服務整合。 在雲端中,訊息佇列通常用來將工作委派給背景處理。 在許多情況下,服務接收要求的順序並不重要。 不過,在某些情況下,必須排定特定要求的優先順序。 這些要求應該早於應用程式先前傳送的優先順序要求之前處理。

解決方案

佇列通常是先入先出(FIFO)結構,取用者通常會以與張貼至佇列相同的順序接收訊息。 不過,某些消息佇列支援優先順序傳訊。 張貼訊息的應用程式可以指派優先順序。 佇列中的訊息會自動重新排序,以便在優先順序較低的訊息之前收到具有較高優先順序的訊息。 下圖說明此程式:

此圖說明支援訊息優先順序的佇列機制。

注意

大部分的訊息佇列實作都支援多個取用者。 (請參閱 競爭取用者模式。根據需求,可以相應增加和減少取用者程序的數目。

在不支援以優先順序為基礎的消息佇列的系統中,替代解決方案是維護每個優先順序的個別佇列。 應用程式負責將訊息張貼至適當的佇列。 每個佇列可以有個別的取用者集區。 優先順序較高的佇列可以有比優先順序較低的佇列更快的硬體上執行的取用者集區。 下圖說明針對每個優先順序使用不同的消息佇列:

此圖說明針對每個優先順序使用不同的消息佇列。

此策略的一個變化是實作單一取用者集區,先檢查高優先順序佇列上的訊息,然後才開始從較低優先順序佇列擷取訊息。 解決方案之間有一些語意差異,其使用單一取用者進程集區(無論是支援具有不同優先順序的訊息的單一佇列,或是支持處理單一優先順序的多個佇列的多個佇列),以及針對每個佇列使用不同的佇列使用不同的佇列使用多個佇列使用不同的佇列使用多個佇列的解決方案。

在單一集區方法中,優先順序較高的訊息一律會在優先順序較低的訊息之前接收和處理。 理論上,低優先順序訊息可能會持續被取代,而且永遠不會處理。 在多個集區方法中,優先順序較低的訊息一律會處理,但不會像較高優先順序的訊息一樣快(視集區的相對大小及其可用的資源而定)。

使用優先順序佇列機制可以提供下列優點:

  • 它可讓應用程式符合需要可用性或效能優先順序的商務需求,例如為不同客戶群組提供不同層級的服務。

  • 這有助於將營運成本降到最低。 如果您使用單一佇列方法,您可以視需要相應減少取用者的數目。 高優先順序訊息仍會先處理(雖然可能較慢),而優先順序較低的訊息可能會延遲較長的時間。 如果您使用每個佇列的個別取用者集區來實作多個消息佇列方法,則可以減少較低優先順序佇列的取用者集區。 您甚至可以停止接聽這些佇列上訊息的所有取用者,以暫停處理某些非常低優先順序的佇列。

  • 多個消息佇列方法可藉由根據處理需求分割訊息,來協助將應用程式效能和延展性最大化。 例如,您可以設定重要工作的優先順序,讓立即執行的接收者處理這些工作,而較不重要的背景工作則由排定在較忙碌時間執行的接收者處理。

考量

當您決定如何實作此模式時,請考慮下列幾點:

  • 在解決方案的內容中定義優先順序。 例如, 高優先順序 訊息可以定義為應在10秒內處理的訊息。 識別處理高優先順序專案的需求,以及需要配置以符合準則的資源。

  • 決定在所有優先順序較低的專案之前,是否都必須處理所有高優先順序專案。 如果訊息是由單一取用者集區處理,您必須提供機制,以在較高優先順序的訊息進入佇列時先占並暫停處理低優先順序訊息的工作。

  • 在多個佇列方法中,當您使用單一取用者進程集區來接聽所有佇列,而不是每個佇列的專用取用者集區時,取用者必須套用演算法,以確保其一律會在優先順序較低的佇列訊息之前為來自較高優先順序佇列的訊息提供服務。

  • 監視高低優先順序佇列的處理速度,以確保這些佇列中的訊息會以預期的速率處理。

  • 如果您需要保證處理低優先順序的訊息,請使用多個取用者集區來實作多個消息佇列方法。 或者,在支援訊息優先順序的佇列中,您可以隨著佇列訊息年齡的增長,動態增加佇列訊息的優先順序。 不過,此方法取決於提供這項功能的訊息佇列。

  • 針對有一些定義完善的優先順序的系統,建議根據訊息優先順序使用不同的佇列策略。

  • 系統可以邏輯判斷訊息優先順序。 例如,您可以指定訊息為「付費客戶」或「非付費客戶」,而不是有明確的高優先順序和低優先順序訊息。您的系統接著可以配置更多資源,以處理來自付費客戶的訊息。

  • 可能有與檢查訊息佇列相關聯的財務和處理成本。 例如,一些商業傳訊系統會在每次張貼或擷取訊息時收取少量費用,而且每次查詢佇列時都會收取少量費用。 當您檢查多個佇列時,此成本會增加。

  • 您可以根據集區所服務的佇列長度,動態調整取用者集區的大小。 如需詳細資訊,請參閱自動調整指引

使用此模式的時機

此模式在下列案例中很有用:

  • 系統必須處理具有不同優先順序的多個工作。

  • 不同的使用者或租用戶應以不同的優先順序提供服務。

工作負載設計

架構設計人員應該評估優先順序佇列模式在工作負載的設計中如何使用,以解決 Azure 架構良好架構支柱涵蓋的目標和原則。 例如:

要素 此模式如何支援支柱目標
可靠性設計決策可協助工作負載復原到故障,並確保它會在發生失敗后復原到完全正常運作的狀態。 根據商務優先順序來分隔專案,可讓您將可靠性工作放在最重要的工作上。

- RE:02 重要流程
- RE:07 背景工作
效能效率 可透過調整、數據、程式代碼的優化,有效率地協助您的工作負載 符合需求 根據商務優先順序來分隔專案,可讓您將效能工作集中在最耗時的工作上。

- PE:09 重大流程

如同任何設計決策,請考慮對其他可能以此模式導入之目標的任何取捨。

範例

Azure 不提供原生支援透過排序自動排序訊息優先順序的佇列機制。 不過,它確實會提供 Azure 服務匯流排 主題、服務匯流排 支援佇列機制的訂用帳戶,以提供訊息篩選,以及一系列彈性功能,讓 Azure 最適合大多數優先順序佇列實作。

Azure 解決方案可以實作應用程式可以張貼訊息的 服務匯流排 主題,就像將訊息張貼到佇列一樣。 訊息可以包含應用程式定義自訂屬性形式的元數據。 您可以將 服務匯流排 訂用帳戶與主題產生關聯,而訂用帳戶可以根據其屬性篩選訊息。 當應用程式將訊息傳送至主題時,訊息會導向至適當的訂用帳戶,讓取用者可以讀取該訊息。 取用者進程可以使用與消息佇列一起使用的相同語意,從訂用帳戶擷取訊息。 (訂用帳戶是邏輯佇列。下圖顯示如何使用 服務匯流排 主題和訂用帳戶來實作優先順序佇列:

此圖顯示如何使用 服務匯流排 主題和訂用帳戶來實作優先順序佇列。

在上圖中,應用程式會建立數個訊息,並在每個訊息中指派名為 Priority 的自定義屬性。 Priority具有或Low的值High。 應用程式會將這些訊息張貼至主題。 本主題有兩個相關聯的訂用帳戶,可根據 屬性篩選訊息 Priority 。 一個訂用帳戶接受屬性設定為HighPriority訊息。 另一個會接受 屬性設定為 LowPriority訊息。 取用者集區會從每個訂用帳戶讀取訊息。 高優先順序訂用帳戶具有較大的集區,而且這些取用者可能會在比低優先順序集區計算機更有可用資源的計算機上執行。

在此範例中,指定高優先順序和低優先順序訊息並無特殊之處。 這些標籤只是在每個訊息中指定為屬性的標籤。 它們用來將訊息導向至特定訂用帳戶。 如果需要額外的優先順序,建立更多訂用帳戶和取用者流程集區來處理這些優先順序相當容易。

GitHub 上的 PriorityQueue 解決方案是以此方法為基礎。 此解決方案包含名為和PriorityQueueConsumerLowPriorityQueueConsumerHigh Azure 函式專案。 這些 Azure 函式專案會透過觸發程式和系結與 服務匯流排 整合。 它們會連線到 中 ServiceBusTrigger 定義的不同訂用帳戶,並回應傳入訊息。

public static class PriorityQueueConsumerHighFn
{
    [FunctionName("HighPriorityQueueConsumerFunction")]
    public static void Run(
      [ServiceBusTrigger("messages", "highPriority", Connection = "ServiceBusConnection")]string highPriorityMessage,
      ILogger log)
    {
        log.LogInformation($"C# ServiceBus topic trigger function processed message: {highPriorityMessage}");
    }
}

身為系統管理員,您可以設定 Azure App 服務 上函式可相應放大的實例數目。 您可以從 Azure 入口網站 設定 [強制向外延展限制] 選項,為每個函式設定最大向外延展限制來執行此動作。 您通常需要擁有比 PriorityQueueConsumerLow 函式更多的函式實例PriorityQueueConsumerHigh。 此設定可確保從佇列讀取高優先順序訊息的速度會比低優先順序訊息更快。

另一個專案 PriorityQueueSender包含已設定為每隔 30 秒執行一次的時間觸發 Azure 函式。 此函式會透過輸出系結與 服務匯流排 整合,並將低優先順序和高優先順序的訊息批次傳送至IAsyncCollector物件。 當函式將訊息張貼至 與 和 PriorityQueueConsumerLow 函式所使用的PriorityQueueConsumerHigh訂用帳戶相關聯的主題時,它會使用Priority自定義屬性來指定優先順序,如下所示:

public static class PriorityQueueSenderFn
{
    [FunctionName("PriorityQueueSenderFunction")]
    public static async Task Run(
        [TimerTrigger("0,30 * * * * *")] TimerInfo myTimer,
        [ServiceBus("messages", Connection = "ServiceBusConnection")] IAsyncCollector<ServiceBusMessage> collector)
    {
        for (int i = 0; i < 10; i++)
        {
            var messageId = Guid.NewGuid().ToString();
            var lpMessage = new ServiceBusMessage() { MessageId = messageId };
            lpMessage.ApplicationProperties["Priority"] = Priority.Low;
            lpMessage.Body = BinaryData.FromString($"Low priority message with Id: {messageId}");
            await collector.AddAsync(lpMessage);

            messageId = Guid.NewGuid().ToString();
            var hpMessage = new ServiceBusMessage() { MessageId = messageId };
            hpMessage.ApplicationProperties["Priority"] = Priority.High;
            hpMessage.Body = BinaryData.FromString($"High priority message with Id: {messageId}");
            await collector.AddAsync(hpMessage);
        }
    }
}

下一步

當您實作此模式時,下列資源可能會對您有説明:

  • 在 GitHub 上示範此模式的範例。

  • 異步傳訊入門。 處理要求的取用者服務可能需要將回復傳送至張貼要求的應用程式實例。 本文提供可用來實作要求/回應傳訊之策略的相關信息。

  • 自動調整指引。 您有時可以根據佇列長度調整處理佇列的取用者進程集區大小。 此策略可協助您改善效能,特別是針對處理高優先順序訊息的集區。

當您實作此模式時,下列模式可能會對您有説明:

  • 競爭取用者模式。 若要增加佇列的輸送量,您可以實作多個取用者,以平行方式接聽相同佇列和處理工作。 這些取用者競爭訊息,但只有一個應該能夠處理每個訊息。 本文提供有關實作此方法之優點和缺點的詳細資訊。

  • 節流模式。 您可以使用佇列來實作節流。 您可以使用優先順序傳訊來確保來自重要應用程式或由高價值客戶執行的應用程式的要求優先於較不重要應用程式的要求。