限制應用程式實例、個別租戶或整個服務所能消耗的資源。 這讓系統能在突發或持續負載下正常運作並達成服務水準目標(SLO)。
內容和問題
雲端應用程式的負載會隨時間變化,取決於活躍用戶及其活動。 更多用戶在營業時間內登入,系統每月執行計算量龐大的分析。 突發爆發也會發生。 若處理需求超過可用容量,系統會減速或失效。 當系統達成約定的服務水準時,該故障即違反 SLO。
有多種策略會根據應用程式的業務目標來處理不同的負載。 其中一種策略是 自動擴展,將配置的資源與當前需求匹配並控制成本。 但配置新資源需要時間且增加成本。 需求超過產能成長或預算,將造成資源赤字。
解決方案
自動擴充的替代方案,是為資源使用量設上限,並在使用量超過該上限時對請求進行節流。 工作負載會監控自身的資源使用,當使用量超過閾值時,會限制一位或多位使用者的請求。 系統持續運作並符合其SLO要求。
節流是一種控制回路,而不是單一的准入決策。 系統需要來自三個層面的低延遲訊號:基礎設施使用率、應用程式狀態,以及各主體的計數器。 它持續測量飽和度,在明確界線執行限制,並隨著交通模式變化調整這些限制。 過載是一種正常運作模式,成熟系統會偵測並恢復。 限速為你的工作負載提供了 自我保護 的能力。
系統可實施多種節流或相關策略:
每個主體的速率限制: 若使用者在指定的時間範圍內已超過設定的速率,則拒絕其請求。 此策略要求系統將每個請求歸因於一個主體,並以該主體為單位來衡量資源使用。 關於多租戶工作負載,請參見 「衡量每個租戶的消耗量」。
優雅降級: 關閉或降低非必要功能的可用性,讓核心功能有足夠的資源。 此策略以回應完整性換取可用性。 例如,一個影音串流應用程式可以降到較低解析度。
負載調節:透過使用佇列讓活動量更平穩。 在多租戶環境中,分級會降低每個租戶的效能。 當租戶有不同的服務水準協議(SLA)時,應立即處理高價值租戶的工作,並保留優先順序較低的工作,直到積壓緩解。 可透過使用 優先佇列模式,或為每個優先順序層級提供獨立的端點,來實作此方法。
依優先順序延後處理: 為較低優先權的應用程式或租戶延後作業。 暫停或限制操作,並回傳一個例外,告訴租戶稍後再試。
出站速率限制: 當外部相依項失敗或傳回錯誤時,限制自身對外呼叫的速率。 降低飛行中請求次數,以防止日誌淹沒,並避免因依賴不良而產生重試成本。 相依性恢復後,恢復正常的請求流程。 例如, NServiceBus 就實作了這項功能。
以下圖表顯示了一個應用程式在使用三個功能(A、B、C 時)中,隨時間的資源使用情況(記憶體、CPU、頻寬及其他因素的組合)。功能是特定功能領域,例如執行特定任務的元件、執行複雜計算的程式碼,或提供如記憶體快取等服務的元素。
該圖表為堆疊區域圖。 特徵 A 線下方的區域顯示特徵 A 消耗的資源,特徵 A 與特徵 B 線之間的區域顯示特徵 B 消耗的資源,特徵 B 與特徵 C 線之間的區域顯示特徵 C 消耗的資源。 功能 C 的行位於堆疊頂端,因此同時顯示系統隨時間的總資源使用情況。
圖表顯示特徵退化程度相當優美。 在 T1 時間前,總資源使用接近臨界點,並有可能耗盡可用容量。 功能B比功能A或功能C重要性較低,因此系統會關閉功能B並釋放其資源。 在 T1 與 T2 之間,特徵 A 與特徵 C 正常運作。 到了 T2 時,總資源消耗下降到足以重新啟動功能 B 的程度。
你可以結合自動擴展、平順降級和節流,維持應用程式的回應能力並符合 SLA 要求。 當你預期需求會持續高企時,限速會維持穩定,同時系統會逐步擴展。縮放完成後,系統會恢復完整功能。
下一張圖表顯示了隨時間的總資源使用情況,以及節流如何與自動縮放及其他補償控制結合。
折線圖繪製所有應用在縱軸與時間上的資源利用。 兩條水平參考線標示資源利用的軟上限及自動擴展前的最大容量。 較高的水平線從時間 T2 開始,標示自動縮放後的最大容量。 使用率曲線會隨時間推移而上升並波動。 它在時間 T1 時跨越軟上限,這時自動縮放開始。 在 T1 到 T2 之間,系統會被限速並進行自動縮放,且利用率會低於自動縮放前的最大容量。 在 T2 時刻,自動擴展完成,節流限制放寬,使用率曲線躍升,並持續在新的、較高的最大容量之下波動。
在 T1 時,系統達到軟上限並開始擴展。如果新資源無法及時抵達,需求可能會耗盡現有資源,系統也可能崩潰。 限流會在擴展期間拒絕超額請求,以將資源使用量維持在硬性上限以下,然後在新增容量上線後解除這些限制。
Tip
邊緣控制機制和節流模式因應的是不同的問題。 邊緣控制措施,例如 Azure DDoS Protection 和網頁應用程式防火牆(WAF)的速率限制規則,會在網路邊界運作,並在大量或惡意流量到達您的應用程式之前將其丟棄。 限流模式運行在你的應用程式內,並根據應用程式定義的限制來衡量 合法 流量。 同時使用這兩層。 DDoS 防護無法阻止合法使用者過載你的服務,應用程式限速也不會吸收體積攻擊。
問題和考慮
在決定如何實施此模式時,請考慮以下幾點:
及早做出節流決定。 限速是一種影響整個系統的架構決策。 之後再加裝會很貴。
使節流限制與最先達到飽和的元件一致。
請求速率是最常見的限制維度,但真正的瓶頸通常是同時進行中的請求、隊列深度、CPU 或記憶體使用率,或下游相依性本身的限制。 每秒請求數限制無法保護以扇出點並發為瓶頸的系統。
在每個節流執行邊界,例如閘道、服務、分割區或下游相依性,找出最先飽和的維度,並在該維度上設定限制。 如需在扇出點提供具並行數限制的保護,請參閱可與節流互補的 艙壁模式。
有意識地選擇一個限制性演算法。 使其與所保護元件的公差相匹配。
演算法 行為與最佳配合 代幣桶 支援最高可達設定大小的突發流量,並以固定速率補充。 適用於需要吸收短暫尖峰的閘道器。 漏水桶 以恆定速率發射。 用於需要穩定傳入流量速率的後端。 固定式視窗 易於實作,但允許在視窗邊界出現背靠背的突發流量。 滑動視窗 這樣可以平滑固定視窗的邊界問題,但代價是需要更多狀態。 決定限制會影響哪些人。 在粗略邊界(如區域閘道)降速,可能影響許多無關用戶,因為只有少數人負責負載。
當一個限制跨越多個節點時,決定計數器的位置。 本地計數器速度快,但當同一呼叫端觸及多個副本時,會少計。 像 Redis 這樣的共享商店中的集中計數器會看到所有請求,但每個決策都會增加延遲。 若要近似全域速率,請將限制分配到各個副本,並定期進行協調。
快速做出限速決定。 系統必須偵測負載上升、反應,並在負載解除後恢復正常。 此過程需要持續的效能監測機制。
主動卸載負載,而不是等到瀕臨崩潰時才這麼做。 只有在元件飽和後才開始拒絕請求的節流機制,會在呼叫端感受到任何背壓之前先造成延遲暴增。
隨著使用率接近硬性上限,開始拒絕越來越多的請求。 早期拒絕訊號會提醒來電者退讓,並防止突然限制時常引發的延遲崩潰。 將 p99 延遲相對於你的 SLO 作為主要觸發條件。 平均利用率看似正常,但 p99 其實已經超過門檻。
如果你能區分請求的價值,請優先捨棄價值較低或更適合重試的工作。 如需詳細資訊,請參閱 優先順序佇列模式。
回傳一個狀態碼,讓用戶端知道暫時性拒絕是節流所造成的:
- HTTP 429(請求過多): 呼叫者在設定的請求時段內超過設定的請求速率。
- HTTP 503(服務無法使用): 服務目前無法處理這個請求,通常是因為意外的負載激增。
請加入
Retry-AfterHTTP 標頭,讓客戶端可以選擇重試策略。 回傳足夠的上下文,讓來電者有意識地重試,而不是猜測。 例如,請說明來電者超過的上限、釐清受影響的範圍,或建議一個可成功的費率。 無法解釋的拒絕無法幫助來電者適應。從你的依賴性傳播過載訊號,而不是吸收它們。 對其呼叫端進行節流的服務,也必須遵循它從自身下游相依服務收到的節流回應。 如果你的服務透過靜默重試或回傳一般的 HTTP 500(內部伺服器錯誤)回應來隱藏下游的 429 或 503 回應,呼叫者無法減速,重試會被放大,過載會連鎖回上游。 Retry Storm 反模式描述了這種失敗模式。 將背壓回傳給上游呼叫端,使整個呼叫鏈一起卸載。
讓拒絕的成本低於它所避免的工作成本。 如果拒絕請求需要大量驗證、深度解析或複雜政策評估,大量被拒絕的請求仍可能讓系統飽和。 盡可能在請求管線中儘早拒絕,並對拒絕路徑本身進行負載測試。
針對節流無法為自動擴展爭取足夠時間的情況預作規劃。 如果需求增長速度快於新容量啟用,即使是限速系統也可能失效。 當這種結果無法接受時,就保留更大的容量儲備,並配置更積極的自動擴展。
不要用快取來取代限速。 快取會降低原點的平均負載,但不會限制峰值負載。 每次快取未命中都會傳到起點,當熱門金鑰因流量過期時,許多來電者會爭相補滿。 使用快取來降低一般情況下的負載壓力,並用節流來限制最壞情況的上限。 欲了解更多資訊,請參閱 Cache-Aside 圖案。
將不同作業的資源成本標準化,因為它們通常執行成本不相等。 例如,讀取操作的限速可能較高,寫入操作則較低。 忽略每次操作成本可能會耗盡產能並產生攻擊途徑。
讓限速設定在執行時可更改。 當異常負載出現時,你需要在沒有部署的情況下調整限制。 在事件發生時,部署速度緩慢且風險高。 外部配置儲存模式會將設定外部化,讓你能在執行時更改。
考慮適應性極限而非靜態極限。 有些限速 SDK 會對延遲或佇列深度訊號做出反應,讓限制追蹤實際元件狀況。 一定要將自適應限制器與設定的最大值配對。
隨著工作量的增加,重新檢視你的極限。 自適應限制器無法追蹤所有類型的漂移,例如SLO變動、依賴容量變化或每次操作成本的變動。 安排定期由操作員根據這些輸入進行審查。
使用此模式的時機
使用此模式:
讓系統能維持在其 SLO 範圍內。
以防止單一租戶壟斷應用程式資源。
處理活動中突然的高峰。
用來限制系統所需的最大資源等級。
在電網碳強度偏高期間減少低價值的運算。
工作負載設計
評估如何在工作負載設計中使用節流模式,以達成Azure Well-Architected框架支柱所涵蓋的目標與原則。 下表提供此模式如何支援每個要素目標的指引。
| 支柱 | 此模式如何支援支柱目標 |
|---|---|
| 可靠性 設計決策有助於使工作負載具有韌性,並確保在故障發生後能復原到正常運作的狀態。 | 您可以設計限制來協助防止可能導致故障的資源耗盡。 您也可以在正常降級計劃中使用此模式作為控制機制。 - RE:07 自我保護 |
| 安全性 設計決策有助於確保 工作負載數據和系統的機密性、 完整性和 可用性 。 | 您可以設計限制,以協助防止資源耗盡,這可能會導致系統自動濫用。 - SE:06 網路控制 - SE:08 強化資源 |
| 成本優化 專注於 維持並提升 您的工作負載的 投資報酬率。 | 這些強制限制可以為成本建模提供資訊,並直接與你應用程式的商業模式相關聯。 它們也會對使用率加上明確的上限,這可納入資源大小調整。 - CO:02 成本模型 - CO:12 擴展成本 |
| 效能效率 可透過調整、數據和程式碼的優化, 有效率地協助您的工作負載符合需求 。 | 當系統需求過高時,此模式有助於降低可能導致效能瓶頸的壅塞。 您也可以使用它來主動避免吵雜的鄰近案例。 - PE:02 容量規劃 - PE:05 擴展和分區 |
如果此模式在一個支柱內部引入取捨,請將它們與其他支柱的目標進行考量。
Example
下圖顯示多租戶系統中的節流。
左側三個加上標籤的使用者代表多租戶 Surveys 應用程式的租戶:Adatum、Fabrikam 和 Contoso。 每個使用者透過租戶專屬的自訂網域發送請求,應用程式會用該網域來識別租戶。 Adatum 透過 surveys.adatum.com 每秒發送 5 次請求,Fabrikam 透過 surveys.fabrikam.com 每秒發送 10 次請求,Contoso 透過 surveys.contoso.com 每秒發送 150 次請求。 右側的調查應用程式網頁角色會衡量每個租戶的每秒請求速率。 Adatum 與 Fabrikam 請求流程會直接傳遞至應用程式。 Contoso 的要求流程因速率超過每個租用戶限制,而被「錯誤:節流回應」封鎖。
來自多個租戶組織的使用者可透過雲端應用程式填寫並提交問卷。 應用程式包含監控每個租戶使用者提交請求速率的儀器。
為防止使用者因某個租戶而降低對其他租戶用戶的回應速度與可用性,應用程式限制任何單一租戶可提交的每秒請求速率。 應用程式會封鎖超過此限制的要求。
下一個步驟
相關資源
- 測量每個租戶的消耗量
- Azure 中的自動調整規模
- Queue-Based 負載平衡模式
- 優先順序佇列模式
- 外部組態存放區模式