搜尋文件

輸入關鍵字,搜尋標題與正文。

    分散式系統文件 03/08

    過載、時間預算與背壓

    本文提要

    重試即使不會重複產生業務效果,仍然會占用系統資源;服務過載時,更多等待與重送可能形成惡性循環。 要控制這個循環,需要共同安排等待期限、重試責任、排隊容量與工作接受速率。

    18px · 寬鬆行距

    閱讀設定

    排版預覽 · 示範文字(可捲動)

    檔案與目錄

    Linux 以一棵從根目錄 / 開始的樹狀結構組織檔案。目錄用來整理檔案,也可以包含其他目錄。

    pwd
    ls -la /home
    18px

    16、18、20、22px;隨瀏覽器文字大小縮放。

    欄寬套用於背景文章;此處預覽字級與行距。手機正文自動配合螢幕。

    文件與本文目錄
    本主題文件

    重試即使不會重複產生業務效果,仍然會占用系統資源;服務過載時,更多等待與重送可能形成惡性循環。 要控制這個循環,需要共同安排等待期限、重試責任、排隊容量與工作接受速率。

    本文接續從重送請求到冪等副作用,不重述 API 的冪等契約;先備說明見逾時、重試與冪等性。

    查證日期:2026-11-04。依官方工程文件整理,未執行負載測試。下列匯出服務、容量與延遲數字均為自創簡化模型,不是產品預設值或效能實測。

    到達速率超過處理速率,佇列會持續增長

    假設 worker 群組能穩定完成每秒 40 份匯出,但每秒收到 60 份新工作;先忽略重試、取消、工作大小差異與擴容。只要這些條件持續,每秒淨增加 20 份待處理工作,30 秒就增加 600 份。

    佇列把立即處理改成稍後處理,沒有憑空增加每秒完成能力。若流入稍後低於處理速率,佇列可以吸收短暫突波;若長期流入更高,無限佇列只是把故障延後成記憶體耗盡、儲存不足或等待時間失控。

    AWS 的佇列工程文章區分可恢復的短期積壓與持續超過處理能力的情況,並討論工作時效與積壓隔離。參考 AWS:Avoiding insurmountable queue backlogs。

    即使只是等待,請求仍可能占用連線、記憶體與工作槽。將同步等待改成非同步工作資源,有助於釋放前端連線,卻仍要管理背景工作容量;見非同步 API 契約。

    每一層重試都會放大下游工作

    再假設 API 呼叫工作服務,工作服務呼叫資料庫,而兩層都在失敗時最多嘗試三次,包含首次。若每次上層嘗試都走完三次下層嘗試,一次對 API 的操作最多造成九次資料庫呼叫;這是本例的上限推算,不是任何三層系統都固定發生九次。

    同鍵去重也需要接收、驗證與查詢,所以不等於零成本。當下游因過載變慢,上游 timeout 後增加嘗試,下游就可能承受更多工作,進一步延長等待。

    常見的緩解方式是由清楚的一層負責重試、限制次數與總時間,並使用退避與隨機抖動分散嘗試。它們控制放大效應,不保證本次工作一定成功。AWS 對多層重試與這些策略的討論見 Timeouts, retries, and backoff with jitter:Retries and backoff、Jitter。

    整體時間預算要涵蓋等待與退避

    若本例的互動總預算是 2 秒,第一次嘗試用了 1.2 秒,退避又用了 0.3 秒,第二次嘗試只剩約 0.5 秒;不能因為換了一次網路呼叫,就重新獲得完整 2 秒。

    這裡把時間算成「經過多久」,還需確認計時方式不受系統日期調整影響。跨程序也不能直接傳遞某台機器的本地單調時鐘數值,當成另一台機器可直接比較的時間。下一篇會解釋時鐘與事件順序。

    gRPC 的 deadline propagation 會以扣除已耗時間的 timeout 傳遞,避免直接依賴兩台主機的實體時鐘一致;哪些語言自動傳遞仍依實作而定。參考 gRPC Deadlines:Deadline Propagation。

    取消可以讓服務得知呼叫端不再等待,但處理程式必須合作停止相關工作。已提交的建立工作,也不會因 RPC 取消而自動撤銷。背景匯出若需可取消,必須另有業務狀態與取消規則。參考 gRPC Cancellation 與 Core concepts:Cancelling an RPC。

    控制流入、同時執行與排隊,是三件事

    表格・3 欄 5 列
    控制方式直接控制的量對本例的作用與限制
    速率限制(rate limiting)一段期間允許的新請求量抑制流入,但請求變慢時,同樣速率仍可能累積大量並行工作
    併發限制(concurrency limiting)正在進行的工作數保護連線或 worker;無法直接保證每秒完成多少份
    有限佇列(bounded queue)等待中的工作數或占用量限制積壓;滿時需要拒絕、降級或讓上游放慢
    負載卸除(load shedding)過載時接受哪些工作在耗盡資源前拒絕部分工作,保留處理已接受工作的能力
    背壓(backpressure)下游容量如何回饋上游讓上游減速或停止送出;要靠上游配合或明確的流量協定

    這是依控制目標整理的概念比較,不是聲稱某一層只能實作一種。速率限制的使用者配額與防濫用面向另見限流、配額與資源防護。

    負載卸除需要盡量在付出大量成本前生效;若服務已做完整運算才回報忙碌,保護效果就很有限。AWS 也討論拒絕工作、在負載測試中量測成功的有效工作量,而不是只看服務是否還能回應。參考 AWS:Using load shedding to avoid overload。

    背壓不能只是把下游無限佇列搬到上游。若 API 等待 worker 空位時持續建立更多連線,系統仍可能在另一處耗盡資源。非同步訊息系統也需考慮積壓年齡、保存期限與租戶隔離,不能只說「放進佇列就沒事」。

    用一段歷程檢查容量策略

    對前述每秒完成 40 份、流入 60 份的簡化服務,假設現在明訂最多容納 200 份等待工作,並另外限制執行中的 worker 數量。這些是本例條件,並非容量建議。

    1. 一開始有空位,服務接受工作並回傳工作識別;本例將「已接受」定義為工作狀態已持久保存。
    2. 積壓持續增加,服務在接近上限時降低接受速率,或在無空位時拒絕新的建立意圖。
    3. 若呼叫端收到可重試的忙碌訊號,它必須遵守剩餘預算與退避;全體立即重送會把拒絕成本也推高。
    4. 呼叫端沒有收到回應時,仍可能遇到「其實已接受」;重試應沿用原操作識別,不能因過載換新鍵。
    5. 服務恢復後,已接受工作依排程繼續;若因期限需要放棄,應保留可查詢的終止狀態,而不是悄悄刪除。

    第四步把容量問題接回冪等問題:拒絕、接受與回應的邊界必須一起設計。並行接受工作時,容量檢查本身也需要可靠的協調或保守預留;每個 API 節點各自看到「尚有一格」並不代表全體真的只會多收一份。

    要觀察有效工作,而不只是請求數

    本例至少需要分開觀察新意圖數、網路嘗試數、接受與拒絕數、完成數、執行中工作數、積壓數與最舊工作的年齡。若每秒收到 100 次請求,其中 60 次只是同一批意圖重試,就不能直接當成 100 份新需求。

    也要區分快速拒絕與成功完成的延遲;把兩者混在平均值裡,可能讓過載時的數字看似變快。以上是從本例控制目標推導出的觀測需求,不是本文已建立或測試過的監控系統。

    時間預算讓我們知道「還能等多久」,但事件的時間戳能否告訴我們「哪個狀態應該先發生」?這是下一篇時鐘、事件順序與因果關係要釐清的問題。

    相關文件