基於佇列的負載調節模式

使用一個佇列作為任務與其呼叫服務之間的緩衝區。 這種方法能平滑間歇性且可能導致服務失敗或任務逾時的重負載。這有助於減少需求高峰對任務及服務可用性與回應性的影響。

內容和問題

許多雲端解決方案執行的任務會呼叫服務。 在此環境中,間歇性重負載可能導致服務效能或可靠性問題。

某項服務可能與使用該服務的任務同屬同一解決方案,或是合作夥伴服務,提供頻繁使用的資源存取。 這類服務的例子包括快取或儲存服務。 當多個任務同時執行且使用同一個服務時,很難隨時預測請求量。

服務可能會遇到需求高峰,導致過載,導致無法快速回應請求。 如果服務無法處理這些請求所造成的爭用,以大量並行請求灌爆服務也可能導致服務發生故障。

Solution

在任務與服務之間放置佇列。 工作和服務會以異步方式執行。 任務會向佇列發布包含服務所需資料的訊息。 佇列作為緩衝區,儲存訊息直到服務取回。 服務會從佇列中擷取訊息並處理。 來自多個任務的請求,其產生速率差異很大,皆可透過同一個訊息佇列傳送到該服務。 下圖展示了佇列如何平衡服務負載。

圖示顯示訊息佇列如何作為任務與服務之間的緩衝區。

佇列將任務與服務解耦,使服務即使同時產生大量請求,也能以自己的節奏處理訊息。 此外,即使在將訊息傳送到佇列時服務無法使用,任務也不會延遲。

此模式提供下列優點:

  • 這有助於最大化可用性,因為服務延遲不會立即且直接影響應用程式。 即使服務無法使用或目前未處理訊息,應用程式仍可持續向佇列發布訊息。

  • 這有助於最大化擴展性,因為排隊數量和服務數量可以隨需求變化。

  • 這有助於控制成本,因為你只需要足夠的服務實例來滿足平均負載的需求,而非峰值負載。

Note

有些服務會在需求達到可能導致系統故障的臨界值時實施限速。 限速可能會減少可用功能。 在這些服務中實施負載平準,以確保需求不會超過這個門檻。

問題和考慮

在決定如何實施此模式時,請考慮以下幾點:

  • 實作應用程式邏輯來控制服務處理訊息的速度,以避免目標資源過載。 避免將需求尖峰傳遞至系統的下一個階段。 在負載下測試系統,以確保其提供所需的平衡。 為了達到所需的平級化,請調整佇列數量及處理訊息的服務實例數量。

  • 消息佇列是單向通訊機制。 如果任務期待服務回覆,你可能需要實作一個服務可以用來發送回應的機制。 欲了解更多資訊,請參閱Azure中的非同步訊息選項。

  • 不限制消費者整體下游速率的自動縮放,只會將過載轉移到下游依賴。 這種過載會加劇這些服務所共享資源的爭用,並降低佇列平衡負載的效果。

  • 如果你的平均生產者費率超過消費者費率,排隊時間會持續增加,延遲也會增加。 監控佇列深度,並在安全範圍內擴展消費者數量,或在生產端削減工作負載。

  • 此模式依賴佇列耐久性以防止訊息遺失。 如果訊息代理程式未將訊息持久化儲存至持久性儲存體,當發生當機或達到容量上限時,已排入佇列的資料可能會在消費者處理之前遺失。 選擇一個能將訊息持久化到磁碟或複製儲存的佇列服務,並了解其大小配額與保留限制。 對於需要訊息以在區域故障中存活的工作負載,請評估地理災難復原選項。

  • 大多數佇列服務的訊息至少帶有一次語意,這表示消費者可能會多次收到相同的訊息。 設計消費者邏輯為 冪元 邏輯,使同一訊息多次處理產生相同結果,並避免重複記錄或重複收費等問題。

  • 有些訊息無法處理,因為它們包含格式錯誤的資料、引用遺失的資源,或觸發持續錯誤。 與其讓這些訊息無限循環並阻塞佇列,不如將它們路由到 死單字佇列。 監控死信佇列深度,讓您的營運團隊能調查故障、修正根本問題,並在適當時重新提交訊息。

  • 在生產者與消費者之間建立佇列,無法在所有情況下保留原始提交順序,尤其當多個消費者同時處理訊息時。 如果你的工作量需要嚴格排序,可以在 Azure 服務匯流排 中使用像是 message sessions 這類功能。 如果不需要嚴格排序,消費者可以設計成任意順序處理訊息,這樣可以簡化縮放。

使用此模式的時機

當下列情況時,請使用此模式:

  • 你的工作量會經歷間歇性高峰,可能會讓下游服務不堪負荷。

  • 你需要將請求的輸入與處理吞吐量解耦,以提升韌性與成本控制。

在下列情況下,此模式可能不適用:

  • 呼叫者需要低延遲、同步的回應。

  • 工作負載量通常低且穩定,因此增加排隊複雜度幾乎沒有好處。

工作負載設計

評估如何在工作負載的設計中使用以佇列為基礎的負載等化模式,以因應 Azure Well-Architected Framework 支柱所涵蓋的目標與原則。 下表提供此模式如何支援每個要素目標的指引。

支柱 此模式如何支援支柱目標
可靠性 設計決策有助於使工作負載具有韌性,並確保在故障發生後能復原到正常運作的狀態。 此模式所描述的方法,能透過將任務的到來與處理脫鉤,提供對突發需求激增的韌性。 它還可以隔離佇列處理中的故障,使其不會影響接收。

- RE:06 縮放
成本優化 專注於 維持並提升 您的工作負載的 投資報酬率 由於負載處理與請求或工作接收解耦,因此您可以使用此方法來減少因應尖峰負載而過度佈建資源的需求。

- CO:12 擴展成本
效能效率 可透過調整、數據和程式碼的優化, 有效率地協助您的工作負載符合需求 此方法使得有意識的設計能提升吞吐量效能,因為請求接收不需要與處理速率相關聯。

- PE:05 擴展和分區

如果此模式在一個支柱內部引入取捨,請將它們與其他支柱的目標進行考量。

Example

Web 應用程式會將數據寫入外部資料存放區。 若多個網頁應用程式同時執行,資料儲存庫可能無法足夠快速回應請求,導致請求逾時、限速或失敗。 下圖顯示一個資料儲存庫因來自應用程式實例的同時請求而不堪負荷。

圖示顯示多個同時請求,來自某個網頁應用程式的實例,導致服務不堪負荷。

為了解決這個問題,可以使用佇列來平衡應用程式實例與資料儲存之間的負載。 Azure Functions 應用程式會從 服務匯流排 佇列讀取訊息,並執行資料儲存的讀寫請求。 Azure Functions 可根據 服務匯流排 的訊息積壓情況,透過目標型調整來調整執行個體數目,且會在您設定的調整範圍內進行。 你也可以調整觸發並發設定來保護資料儲存。 有關實作指引,請參見 目標基礎擴展限制擴展。若不進行此調整,工作層可能會重新引入後端爭用。

圖示顯示如何使用佇列和函式應用程式來平衡負載。

作為一種技術變體,你可以用 Azure 容器應用程式 代替 Azure Functions 來實作相同的模式。 在此方法中,容器化工作者會從 服務匯流排 接收訊息並寫入資料儲存。 容器應用程式會根據與佇列相關的擴縮規則,在已設定的最小與最大複本數之間調整背景工作角色的規模。 你也可以用 Azure 佇列儲存體 作為事件來源來實作同樣的方法。 欲了解實作指引,請參閱「 在容器應用程式中設定擴展規則 」及「 使用容器應用程式部署事件驅動工作」。

下一步

實作此模式時,下列指引也可能相關:

  • Azure 中的非同步傳訊選項:訊息佇列本質就是非同步的。 如果任務直接與服務通訊,可能需要重新設計其應用邏輯。 同樣地,你可能需要重構服務,以接受來自訊息佇列的請求。

  • 在Azure訊息服務中選擇:獲取更多資訊,協助你在Azure應用程式中選擇訊息與排隊機制。

  • 開發背景工作建議:將此模式套用於背景工作,讓訊息佇列能在應用程式負載過高時儲存背景任務的請求。

  • Web-Queue-Worker 架構風格:Web與Worker皆為無狀態。 會話狀態可以儲存在分散式快取中。 工作者以非同步方式執行長時間工作,並可由隊列中的訊息觸發,或依排程執行批次處理。

  • 競爭的消費者模式:可能可執行多個服務實例,每個實例作為負載平準隊列中的訊息消費者。 您可以使用此方法來調整接收和傳遞至服務的訊息速率。

  • 限速模式:在服務中實作限速的一個簡單方法是使用基於佇列的負載平準,並將所有請求透過訊息佇列路由至服務。 服務可以以某種速率處理請求,確保不會耗盡其所需資源,並減少可能發生的爭用。