1. 題目與適用場景
SaaS 平台向多個租戶提供 API 請求、並發任務和儲存空間。每個租戶可能有專案級、組織級和資源級配額,部分限制按分鐘重設,部分限制按帳期累計。業務方希望在請求進入後快速判斷是否可用量,同時把真實用量用於告警、審計和計費。請設計配額檢查與用量計量服務,說明硬限制、軟閾值、超額策略和多區域故障下的行為。
2. 面試官考察點
- 是否能區分 allocation、rate、concurrent 三類限制,並明確作用域和重設語意。
- 是否將同步准入路徑與非同步用量事件、帳單聚合和對帳拆開,避免把計量延遲誤當成准入事實。
- 是否處理原子預留、冪等鍵、重複或亂序事件、熱點租戶和配額設定版本。
- 是否說明跨區域一致性、降級、審計追蹤、告警和人工調整的安全邊界。
3. 回答前需要釐清的問題
- 要限制的是請求速率、同時執行數量、儲存容量,還是帳期內累計用量?
- 配額作用域是組織、租戶、專案、使用者還是資源實例,是否需要層級繼承?
- 超過配額時必須拒絕、排隊、降級,還是允許超額並在帳單中計費?
- 多區域是否要求強一致,事件延遲和最終對帳允許多長時間?
4. 30 秒回答框架
我會把系統拆成配額目錄、同步准入引擎、預留帳本、非同步用量事件管道、聚合查詢和審計告警。請求攜帶租戶、專案、資源類型和冪等請求 ID,准入引擎按設定版本檢查速率、並發和累計配額,並在需要時原子預留;完成或取消時釋放預留並產生用量事件。事件帶唯一 ID、發生時間和維度,消費者冪等聚合,帳期結束後與帳本和下游帳單對帳。多區域按資源選擇強一致或有界超賣策略,故障時優先保護硬上限並返回可重試訊號。
5. 分步驟深入解答
第一步:建立配額模型和作用域
配額目錄保存資源類型、作用域、單位、視窗、上限、是否可調和設定版本。速率配額限制一段時間內的消耗,concurrent 配額限制同時執行操作,allocation 配額限制已分配資源。組織配額可以作為上限,租戶和專案配額只能在父級剩餘範圍內預留,避免每層獨立放行導致總量超賣。
第二步:設計同步檢查和原子預留
同步路徑只處理能影響准入的事實:目前視窗計數、活動預留和設定版本。對單一租戶熱點鍵使用分片計數器或按租戶分區的強一致儲存;預留操作必須檢查剩餘量並一次性增加預留,避免兩個並發請求同時讀取同一餘額。長任務返回 reservation ID,完成、取消和逾時都必須是冪等的。
checkAndReserve(tenant, dimensions, amount, requestId, configVersion)
verify configVersion is active
if requestId already committed: return previous decision
atomically check remaining quota and add reservation
persist reservation with expiry and requestId
return reservationId and retryAfter第三步:把用量事件與計量聚合解耦
請求成功、失敗、取消和過期都應產生事件,事件包含租戶、專案、資源、數量、單位、發生時間和唯一事件 ID。訊息系統至少一次投遞時,消費者以事件 ID 去重;亂序事件用事件時間視窗或可重播帳本處理。聚合結果用於查詢、閾值告警和帳單輸入,但不能直接覆蓋同步預留帳本。
第四步:處理超額、配額變更與公平性
硬配額達到上限時拒絕或排隊,軟閾值只觸發告警;是否允許超額必須是產品設定,並記錄授權主體和價格規則。降低配額前先檢查現有預留,不能讓已接受的工作突然失去額度。熱點租戶不能佔滿共享分片,可採用租戶級並發上限、令牌桶和公平佇列。配額增加請求應經過審批或自動規則,並保留舊版本以支援審計。
第五步:多區域、故障恢復與對帳
若硬上限必須全球準確,可把關鍵資源路由到單一權威區域或使用共識儲存;若更看重可用性,可按區域分配額度並明確最大超賣量。區域失聯時拒絕無法安全判斷的硬限制,軟限制可以短暫降級為告警。恢復後從不可變事件和預留帳本重播,比較准入記錄、聚合用量和帳單結果,修復差異時保留補償事件而不是直接改歷史。
6. 高品質示範回答
我會把配額目錄、同步准入引擎、預留帳本、非同步計量管道和審計查詢分開。目錄定義組織、租戶和專案作用域,以及 rate、concurrent、allocation 三類限制。准入請求用租戶、資源維度和冪等 ID 做原子檢查與預留;長任務返回 reservation ID,完成、取消和逾時均冪等。成功和失敗事件進入至少一次訊息管道,消費者按事件 ID 去重並用事件時間聚合,聚合結果供告警和帳單使用,但不覆蓋准入帳本。多區域按資源選擇權威寫入或有界超賣,故障時保護硬配額;恢復後從事件重播並對帳,所有配額變更和補償都可審計。
7. 常見錯誤
- 只做一個共享計數器 → 熱點租戶拖慢所有請求 → 按租戶分片並設定公平上限。
- 用非同步聚合結果決定同步准入 → 事件延遲造成超賣 → 用原子預留帳本維護准入事實。
- 只討論 rate limit → 長任務和儲存無限佔用 → 同時建模 rate、concurrent、allocation。
- 用請求 ID 去重卻不記錄事件 ID → 重試事件重複計量 → 請求預留和用量事件分別建立冪等鍵。
- 降低配額時直接覆蓋餘額 → 已接受任務被突然拒絕 → 使用版本化設定並檢查現有預留。
8. 追問及應對
追問一:為什麼不能只依賴 Redis 計數器?
計數器適合低延遲視窗統計,但跨資源原子預留、長任務逾時、設定版本和審計需要更完整的帳本。可以用計數器做快路徑,但必須有權威記錄和重建機制。
追問二:如何保證重複用量事件不重複計費?
為每個事件分配穩定唯一 ID,消費者先寫去重記錄再更新聚合,或在同一事務中完成。聚合結果可重算,帳單只消費已確認的聚合版本,並保留補償事件。
追問三:多區域網路分區時是否繼續放行?
對不可超賣的硬配額暫停或把資源路由到權威區域;對允許有界超賣的軟配額按預分配額度放行,並記錄最大風險上限。選擇必須由業務損失和一致性目標決定。
追問四:如何測試配額服務?
壓測同一租戶熱點、並發預留、重複和亂序事件、設定降級、區域分區、消費者重播和帳期切換。斷言硬上限不被突破,冪等操作結果穩定,恢復後帳本、聚合和帳單最終一致。