題干與適用場景
這題考察限流的協議邊界,不是只加 Redis 計數器。RFC 6585 定義 429 表示一段時間內請求過多,服務端可用 Retry-After 提示等待;RFC 9110 規定秒數與 HTTP 日期兩種表示。要把語意轉成客戶端行為。
面試官真正想聽什麼
- 限流鍵、窗口、配額和回應標頭能解釋誰被限、何時恢復。
- 429 body、Retry-After、請求 ID 和剩餘配額資訊一致且不洩漏租戶資料。
- 客戶端解析秒數或日期、加入抖動、遵守截止時間並限制嘗試次數。
- 非冪等寫入、非同步任務和網路逾時的重試邊界清楚。
推薦回答結構
先定義限流維度和錯誤分類,再給出 429 回應及 Retry-After 規則。客戶端依標頭、請求類型和預算等待、放棄或轉為非同步;所有重試使用指數退避與隨機抖動。
深入拆解:從回應到重試
讓限制原因可解釋
服務端按租戶、憑證、IP、端點或全域資源定義鍵,429 返回穩定錯誤類型、請求 ID 和安全原因。多個限流器同時觸發時取最長等待,不暴露其他租戶配額。
正確產生 Retry-After
秒數表示至少等待多久,HTTP 日期表示恢復時間點。內部用單調時間計算窗口,向上取整並設上限;日期可能受時鐘偏差影響,客戶端仍需最小等待與抖動。
客戶端解析與退避
優先遵守 Retry-After;缺少或非法時使用有上限的指數退避。每個邏輯請求維護嘗試預算和總截止時間,多個任務共享佇列,避免同時喚醒。
處理冪等邊界
GET、HEAD 和明確冪等的 PUT、DELETE 通常可重試;POST 只有帶冪等鍵或服務端保證才可重試。若回應遺失,先查詢狀態或重用相同鍵,不能建立新副作用。
觀測恢復而非只看錯誤率
記錄限流維度、429 數量、Retry-After 分布、等待、重試放大、最終成功與放棄。按 SDK 版本和租戶分組,區分立即重撞與流量增長。
可直接套用的回答示例
「我會按租戶、憑證和端點鍵限流,429 返回穩定錯誤類型、請求 ID、安全原因和 Retry-After。服務端用單調窗口算等待秒數,向上取整並限制最大值。SDK 優先解析 Retry-After,缺少時用帶抖動的指數退避,每個邏輯請求有截止時間和最大嘗試。GET 可重試,POST 需冪等鍵或先查狀態。監控 429、等待、重試放大、最終成功與放棄,並用多客戶端壓測驗證恢復是否平滑。」
常見失分點與修正
- 所有失敗都重試 → 按狀態碼、方法語意和錯誤類型分類。
- 忽略 Retry-After 格式 → 支援秒數和 HTTP 日期,處理非法值。
- 每執行緒立即重試 → 共用預算、佇列和隨機抖動。
- 把 POST 當天然冪等 → 使用冪等鍵、查詢狀態或明確不可重試。
評分標準與自檢清單
高分回答包含限流鍵、429 語意、Retry-After 產生與解析、退避抖動、總截止、冪等邊界、並發協調、配額安全、分工和驗證指標。
追問與延伸
Retry-After 應返回秒數還是日期?
兩種都符合 HTTP 語意。秒數適合短窗口並避免時鐘差,日期適合明確恢復時間;服務端穩定使用一種,SDK 相容另一種並處理過期值。
閘道和應用都限流,返回哪個等待?
對客戶端可見的等待應覆蓋所有已知限制,通常取最長等待並保留請求 ID。內部記錄每層命中,避免錯誤歸因。
沒有 Retry-After 時能否重試?
只有方法與錯誤語意允許、仍有截止時間和退避預算時才重試。不可重試寫入應返回可查詢狀態或明確失敗。
如何測試重試風暴?
讓大量客戶端同時觸發 429,注入非法標頭、時鐘偏差、連線逾時和恢復抖動,觀察到達曲線、放大系數、恢復時間與成功率。