題目與使用情境
請設計 300 個後端服務的公網統一入口。系統在三個雙活區域內承擔每秒 50 萬峰值請求,保存約 2 萬條路由定義。閘道負責 TLS 終止、呼叫方認證、粗粒度授權與配額、請求正規化、上游選擇、按權重灰度以及指標和鏈路追蹤。假設可用性目標為 99.99%,閘道新增 p99 延遲低於 10 毫秒。這些數字是面試輸入,並非任何產品的效能承諾。
普通路由與策略變更應在 30 秒內到達健康閘道;緊急憑證撤銷需要更快的通道。錯誤設定不能同時擊穿所有區域,控制面不可用時,閘道仍要依靠最後一個已知良好版本繼續服務。後端業務邏輯、回應聚合、長流程編排和面向業務物件的細粒度授權不屬於閘道職責。
這是一道高階系統設計題。難點位於元件邊界:定義請求熱路徑,隔離設定發布與線上流量,約束故障行為,並證明這個全域入口不會成為單點。
面試官在考察什麼
高品質回答首先會區分資料面與控制面。各區域閘道程序用本地不可變快照處理請求;控制面負責驗證、版本化、儲存和分發路由與策略。若每次請求都查詢資料庫或遠端設定服務,延遲目標和控制面故障隔離都無法成立。
第二個考點是職責邊界。TLS、身分驗證、路由匹配、粗粒度策略、限流、請求標頭、逾時和遙測屬於橫切能力;庫存判斷、支付決策、物件級權限屬於業務服務。允許任意業務外掛程式執行的「萬用閘道」很難測試,發布風險也會擴散到所有流量。
容量估算必須可重算。每秒 50 萬請求、平均入站請求 2 KiB,對應 500,000 × 2 KiB ≈ 0.95 GiB/s,尚未計算協定開銷。若完整策略鏈壓測後,單一執行個體在目標 p99 下可安全承載每秒 Q 個請求,至少需要 ceil(500,000 / Q) 個執行個體,再增加區域故障餘量。三個等流量區域失去一個後,倖存區域會從約每秒 16.7 萬升至 25 萬,增幅 50%;容量規劃必須涵蓋此狀態。
完整回答還要交代設定安全、區域路由、過載傳播、重試、可觀測性和明確的降級策略。只說「部署到多個區域」並沒有說明流量如何遷移、狀態如何更新、網路分割時保留哪些能力。
回答前應釐清的問題
- 用戶端是誰? 假設包括公網 Web、行動端與合作夥伴的 HTTP API。內部服務間流量可使用獨立入口或服務網格策略。
- 可用性單元是什麼? 每個區域的閘道跨至少三個故障域部署;三個區域雙活,全域路由會移除不健康區域。
- 路由如何區分? 按主機名稱、方法和正規化路徑匹配;順序必須確定,歧義定義在發布前被拒絕。
- 哪些策略同步執行? 簽章驗證、路由匹配、粗粒度授權、配額、請求限制和標頭轉換;閘道不查詢業務資料作決策。
- 設定要求多新? 普通變更 30 秒內收斂,閘道回報實際套用版本。安全撤銷依靠短期權杖或獨立分發的小型拒絕清單,不強迫重編全部快照。
- 跨區域配額多嚴格? 預設從全域預算向區域分配配額。嚴格全域計數會給每次請求增加跨區域依賴,需要另行證明必要性。
- 閘道可以重試嗎? 僅在確認首次嘗試未被接受時重試冪等請求,並受很小的重試預算約束;非冪等寫入需要業務冪等鍵或禁止自動重試。
- 哪些內容不在範圍內? 閘道前的 DDoS 清洗、服務實作、資料庫複寫和業務交易屬於其他系統。
30 秒回答框架
「我會在三個雙活區域分別部署無狀態閘道叢集,並置於具備健康感知的全域流量路由之後。每個請求留在一個區域內:閘道終止 TLS,用本地金鑰快取驗證身分,從不可變路由快照匹配規則,套用粗粒度策略和區域配額,再選擇同區域健康上游。獨立控制面驗證每次設定、分配版本、先對小批閘道灰度,再原子啟用;控制面故障時,閘道繼續使用最後一個已知良好快照。我會按三個等流量區域失去一個後倖存區域負載增加 50% 來配置容量,限制重試和佇列以免放大過載,並監控新增延遲、路由結果、上游健康、設定版本和區域切換。」
分步深入設計
系統分為四層。全域流量管理把用戶端送到鄰近且健康的區域;區域負載平衡器把流量分散到跨故障域的無狀態閘道;資料面代理到同區域服務端點;控制面儲存期望設定,將其編譯為帶版本快照,並在請求路徑之外分發。微軟官方架構文件把閘道定義為負責路由與橫切能力的統一入口,其代管和自我裝載閘道模式也體現了集中管理設定、分散承載執行階段流量的邊界。
正常請求流程如下:
- 全域 DNS 或 Anycast 選擇健康區域,區域負載平衡器選擇閘道執行個體。
- 閘道終止 TLS,執行連線數和請求本文大小限制,並附加請求 ID。
- 它用快取的簽發方中繼資料和公開金鑰驗證簽章權杖,不為每次請求呼叫身分服務。
- 編譯後的匹配器按主機、方法和正規化路徑,從目前快照中選擇路由。
- 策略鏈套用粗粒度 scope、區域配額、標頭、逾時和可選灰度分流。
- 閘道從本地快取的服務探索結果選擇健康端點,攜帶有限截止時間轉送。
- 它記錄結果、延遲、路由 ID、上游叢集、設定版本和追蹤上下文,並把遙測非同步送出熱路徑。
路由定義保持宣告式:
Route {
id: string
host: string
methods: string[]
path_template: string
upstream_cluster: string
auth_policy_id: string
quota_policy_id: string
timeout_ms: uint32
retry_policy: { max_attempts, retryable_statuses }
traffic_split: [{ revision, weight }]
}控制 API 用冪等鍵接收目標修訂並回傳修訂 ID。驗證包括 schema、匹配衝突、上游引用、憑證歸屬、策略上限和不安全的重試組合。編譯器產生包含預建匹配結構的不可變快照。發布依次經過驗證、影子比對、小批執行個體、單一故障域、單一區域,再擴到所有區域。閘道下載後驗證摘要與簽章,在請求執行緒之外建立物件,最後原子切換一個指標;進行中的請求繼續使用舊快照。健康指標惡化時,小批執行個體回退到上一版本。
最值得深入的瓶頸是大規模設定安全。逐條傳送可變更新,可能讓路由、策略與憑證在不相容版本間組合。版本快照明確了啟用原子單位。閘道把最新已驗證快照持久化到本地磁碟或節點持久儲存,至少保留一個舊版本,並公開 desiredversion、downloadedversion、active_version。控制面故障只凍結變更,不停止流量;損壞或不完整的快照會被拒絕。緊急撤銷不應等待 2 萬條路由重編:短期憑證限制暴露時間,小型簽章拒絕清單走獨立快速通道並設定到期時間。
容量需要壓測完整策略鏈,不能引用空代理吞吐。如果實測單一執行個體在目標 p99 下承載每秒 8,000 請求,峰值至少為 ceil(500,000 / 8,000) = 63 個執行個體,尚未加入餘量。三個等流量區域失去一個後,每個倖存區域承擔每秒 25 萬請求,按該基準需要 32 個執行個體;每區部署 40–45 個可留出維運空間。這個數字僅作演算,必須用真實 TLS、權杖驗證、負載大小、日誌和上游延遲重新測量。
閘道要主動捨棄過載,而不是累積。限制並行請求、連線、請求本文、每路由佇列和遙測緩衝;把截止時間傳遞給上游;斷路器避免故障服務占滿所有連線。只對少量冪等故障重試,加入抖動,並把每次嘗試計入重試預算。上游飽和時迅速回傳 503,通常比建立無界佇列、耗盡共享閘道更安全。
認證路徑優先本地驗證簽章權杖。公開金鑰非同步重新整理,在輪替期間重疊生效,並在有限時間內保留最後一個有效集合。若必須對不透明權杖做線上內省,就快取短期成功結果,並按路由風險定義失敗開放或失敗關閉;這個同步依賴會改變可用性計算。物件歸屬和業務授權仍在服務中執行,因為閘道沒有權威業務狀態。
配額在區域熱路徑執行。全域分配器把租戶預算拆成短期區域租約,區域狀態儲存作原子決策。這樣網路分割不會無限放大全域配額,但隔離區域只能花完現有租約。若各區域獨立放行並事後對帳,可用性更高,卻會產生超額放行;產品負責人需要選擇可接受上界。權杖桶細節交給現有分散式限流子系統,而不是在每個閘道內重複實作。
AWS 官方文件給出了多區域閘道的主備故障轉移和雙活加權路由。本題選擇雙活,以降低冷切換風險。健康檢查分層處理:執行個體健康移除一個程序,故障域訊號排空一組執行個體,端到端合成探測與區域錯誤率共同決定是否移除區域;條件允許時逐步遷移流量。區域後端與資料儲存也必須就緒,只移動閘道無法讓不可用服務恢復健康。
可觀測性至少包含閘道新增 p50/p95/p99 延遲、各路由請求與錯誤率、TLS 與認證失敗、配額結果、活動連線、佇列深度、重試、斷路狀態、上游延遲、端點健康和設定版本落後。成功日誌取樣,安全與錯誤事件在有限預算內保留;追蹤沿用入站上下文並建立閘道 span。告警要區分閘道失敗與上游失敗,避免因業務服務事故錯誤回復健康閘道。
主要替代方案是一個通用閘道,或按用戶端、業務域拆分多個閘道/BFF。單一叢集簡化公網入口與治理,卻擴大故障半徑,也容易堆積策略;多閘道隔離團隊和用戶端差異,卻增加維運重複與全域規則一致性成本。預設從一個輕量平台閘道和業務服務開始,只有用戶端確實需要聚合或不同契約時才增加 BFF。服務網格負責東西向流量,可與公網南北向閘道互補,不能直接取代它。
驗證包括:路由表確定性匹配的性質測試、快照相容測試、正常峰值和單一區域故障容量壓測、新舊修訂影子比對,以及對控制面失聯、金鑰陳舊、上游變慢、遙測反壓、故障域遺失和區域撤離的故障注入。每種失敗都有可觀察狀態與有限回應,設計才算閉環。
高品質範例回答
「我會在三個雙活區域跨故障域部署無狀態閘道叢集。全域路由把用戶端送到健康鄰近區域,區域負載平衡器再選擇執行個體。熱路徑依次執行 TLS、從本地金鑰快取驗證簽章身分、匹配編譯路由、套用粗粒度授權和區域配額、選擇同區域健康端點,並用有限逾時轉送。業務授權留給服務。
請求路徑不存取設定資料庫。獨立控制面驗證目標路由與策略,拒絕歧義匹配和危險重試,編譯不可變簽章快照,再按影子、小批執行個體、故障域和區域逐步發布。執行個體在請求執行緒外建立新快照並原子切換,持久化最後一個已知良好版本。因此控制面故障會停止變更,但不會停止流量;版本落後和自動回復讓部分發布可見且可逆。
每秒 50 萬請求、平均 2 KiB 入站流量約為 0.95 GiB/s。我要壓測完整策略鏈,得到單一執行個體安全吞吐 Q,部署 ceil(500,000 / Q) 再增加故障餘量。三個等流量區域失去一個後,倖存區域負載增加 50%,區域容量與壓測都涵蓋此狀態。
我會限制連線、並行、請求本文、佇列和重試次數。冪等請求使用很小的重試預算,非冪等寫入需要冪等鍵或禁止自動重試。全域配額用短期區域租約分配,明確網路分割下的取捨。最後監控閘道新增延遲、路由結果、上游健康、重試與斷路、活動設定版本和區域合成探測,並在上線前演練控制面失聯、錯誤設定、故障域遺失和區域切換。」
常見錯誤
- 每次請求都從資料庫讀取路由或策略 → 延遲和可用性綁定控制面 → 使用已驗證本地快照,並保留最後一個已知良好版本。
- 把業務邏輯放入閘道外掛程式 → 發布形成全域故障半徑,領域歸屬模糊 → 保持閘道宣告式,把業務決策放到服務或確有必要的 BFF。
- 逐條發布可變更新 → 路由、策略與憑證可能以不相容版本啟用 → 編譯一個帶版本快照並原子切換。
- 認為多執行個體就等於高可用 → 一個錯誤版本仍可同時擊穿所有執行個體 → 按小批、故障域、區域逐步灰度,設定自動健康門檻與回復。
- 只按正常峰值配置容量 → 區域撤離時倖存區域過載 → 計算並壓測三個等流量區域失去一個後的 50% 增幅。
- 重試所有失敗 → 重試放大過載並可能重複寫入 → 只重試有限的冪等情境,寫入由業務提供冪等性。
- 每次請求都呼叫身分服務 → 認證繼承同步遠端依賴 → 本地驗證簽章權杖,非同步重新整理公開金鑰並限制陳舊時間。
- 給每個區域完整全域配額 → 租戶額度會按區域數倍增 → 分配區域租約,或明確接受的超額上界。
- 只遷移閘道流量、不檢查後端 → 目標區域可能沒有健康服務或資料容量 → 把端到端探測和後端就緒納入切換條件。
- 記錄每個成功請求的完整負載 → 遙測消耗熱路徑資源並可能洩漏敏感資料 → 非同步記錄結構化中繼資料,取樣成功請求並按策略遮蔽。
追問與回答
追問一:如何回復錯誤路由設定而不中斷請求?
保留不可變快照和至少一個已驗證舊版本。閘道在請求執行緒外建立候選版本,檢查摘要和引用,再原子切換活動指標;進行中的請求持有舊快照直到結束。如果小批執行個體健康指標變差,控制面把修訂標記為失敗,執行個體切回舊指標。回復只改變設定狀態,不重新啟動整個叢集。
追問二:控制面不可用一小時會怎樣?
流量繼續使用持久化的最後一個已知良好快照,閘道公開快照年齡與版本,並拒絕未經驗證的變更。憑證和金鑰輪替必須設定足夠長的重疊有效期。緊急撤銷依靠短期權杖或獨立簽章的小型拒絕清單。故障期間失去變更能力,因此分發延遲應在現有材料到期前很久觸發告警。
追問三:閘道重試時如何避免重複執行 POST?
上游連線失敗不代表業務未提交,閘道不能自動重試非冪等請求。必須重試的操作由用戶端提供冪等鍵,業務服務保存並回傳第一次結果。閘道只在請求截止時間和小額重試預算內嘗試。如果傳輸層能證明對端尚未接收任何位元組,可單獨處理這種連線失敗。
追問四:區域路由選擇全域 DNS 還是 Anycast?
兩者都能滿足此架構。健康感知 DNS 維運更簡單,但用戶端快取會讓撤離逐漸發生;Anycast 可更快調度,卻需要更強網路維運,也仍需應用健康訊號。我會選擇平台已成熟營運的機制,實測切換時間,並讓用戶端容忍端點變化。區域閘道設計不依賴「DNS 立即生效」的假設。
追問五:什麼時候應該把一個閘道拆成多個?
當隔離或契約確實不同,例如受監管流量、獨立營運的業務域,或行動端與 Web 端需要顯著不同的聚合時再拆分。不要只是按每個微服務拆,否則用戶端重新感知內部拓撲,維運數量也會膨脹。即使執行階段叢集隔離,策略 schema、身分規則、遙測和發布安全仍可作為共享平台能力。