題幹與適用場景
團隊希望先把新版本發布給少部分真實請求,再逐步擴大流量。服務需要設定流量權重、觀察 Canary 與穩定版本的差異,並在指標惡化時自動停止或回滾。請設計控制面與資料面,明確 SLO、指標視窗、狀態持久化、權限、冪等與控制器失聯時的行為。
這道題適合系統設計、平台工程與 SRE 職位。核心考察是如何把「安全發布」變成可恢復的狀態機,而不是只羅列 Kubernetes、服務網格與監控名詞。回答應能解釋流量路由、分析任務、決策閾值、人工介入與舊版本相容。
面試官考察點
強回答會先定義 Canary 的暴露範圍、持續時間與回滾目標,再把 Rollout、路由、指標查詢與決策器解耦。它會區分「成功」「失敗」「資料不足」三種結果,避免把指標缺失誤判為通過;會用持久化狀態與冪等操作恢復控制器重啟;會說明分析視窗必須匹配發布階段,以及如何防止小樣本雜訊、指標延遲與回滾風暴。
回答前需要釐清的問題
- 目標是單一服務、跨服務編排,還是只控制 Kubernetes 工作負載?
- 流量按隨機請求、使用者穩定雜湊、地區還是租戶分割?是否必須保持使用者黏性?
- 關鍵 SLO 是錯誤率、延遲、業務轉換還是資源成本,穩定基線如何選?
- 每個階段允許多久、失敗幾次觸發回滾,分析不確定時是否暫停等待人工?
- 資料庫 schema、訊息格式與外部 API 是否向後相容,回滾舊版本是否安全?
30 秒回答框架
「我會把服務拆成 Rollout 控制器、流量路由適配器、指標分析器與持久化狀態庫。每個發布都有穩定版本與候選版本、分階段權重、分析視窗與明確的成功/失敗/不確定條件;控制器只在分析成功時擴大流量,失敗時把權重降回穩定版本,不確定時暫停並告警。所有命令帶版本號與冪等鍵,狀態寫入後才能執行下一步。路由與指標系統短暫不可用時維持最後安全權重,恢復後從持久化狀態繼續。」
分步驟深入解答
第一步:定義目標與數量級
假設一個區域每天 200 次發布、每次最多持續 40 分鐘,控制器需要處理每秒幾十個狀態與指標事件;真正的業務請求仍由既有閘道與服務承載。這個估算表示控制面可採用單個高可用控制器加佇列,不需要為每個請求建立工作流。
安全目標是限制爆炸半徑:階段權重例如 1% → 5% → 25% → 50% → 100%,只是可設定示例,不是普適閾值。每一步要有最短觀察時間與最大等待時間,防止指標永遠不足而占用發布槽位。
第二步:拆分控制面與資料面
控制面儲存發布規格、版本摘要、目前階段、目標權重、分析結果與操作者。資料面由閘道或服務網格執行路由,把請求送到 stable 或 canary ReplicaSet。Argo Rollouts 架構文件將 Rollout、兩個版本的 ReplicaSet、Service/Ingress 與 AnalysisTemplate/AnalysisRun 分開,說明這些邊界可以獨立演進。
指標適配器只負責把查詢送到 Prometheus 等提供者並回傳帶時間範圍的觀測值;決策器依策略計算結果,不直接修改路由。如此更換指標後端不會改變發布狀態機。
第三步:設計可恢復的狀態機
可以使用 Draft → Running → Paused → Promoting → Succeeded,並從 Running 或 Paused 轉到 Aborting → RolledBack。每次狀態轉移帶 rollout_id、期望版本、階段序號與冪等鍵;資料庫唯一約束或 compare-and-set 防止兩個控制器同時推進。
Running + analysis=success -> Promoting(next_weight)
Running + analysis=failure -> Aborting(weight=0)
Running + analysis=inconclusive -> Paused(reason=insufficient_signal)
Paused + operator=resume -> Running
Aborting + route=stable -> RolledBack控制器重啟後從最後一次已提交的狀態重播未完成動作。路由更新與狀態寫入無法形成跨系統原子交易,因此動作必須可重複:設定同一權重多次不會產生額外副作用,且每次讀取實際路由後再決定下一步。
第四步:選擇指標與統計視窗
每個階段至少選一個可靠性指標與一個業務指標,例如 Canary 與 stable 的錯誤率差、P95 延遲差、關鍵請求成功率。比較時固定查詢視窗、分母與過濾條件,避免把 Canary 的重試流量與 stable 的原始請求混為一談。
分析視窗要涵蓋指標收集延遲,而且不應長於階段等待上限。Google SRE 的 Canary 指南指出,評估過程要把 Canary 與 control 對照,並提醒指標計算週期過長會讓短階段訊號變得模糊。小樣本時將結果標記為不確定,暫停比貿然放量更安全。
第五步:處理流量分割與使用者黏性
隨機按請求分割適合無狀態介面;需要一致體驗時按使用者或租戶穩定雜湊,並記錄路由版本。按百分比路由時要處理新版本沒有健康實例、權重未生效、跨區域不一致與快取鍵混用。
路由適配器應回傳實際生效的權重與版本摘要。控制器發現期望值與實際值不一致時暫停推進並告警,不能假設 API 成功就代表流量已切換。
第六步:設計回滾、暫停與人工介入
失敗動作先停止擴大 Canary,再把新流量降到零或安全權重;舊版本必須仍可運行,資料庫遷移要採用向後相容的 expand/contract 順序。回滾本身也要有逾時與重試上限,避免路由系統故障時無限重試。
分析結果為 Inconclusive 時暫停並保留現場:查詢、樣本數、版本、視窗與閾值都應可稽核。Argo Rollouts 文件把 Inconclusive 作為暫停狀態,交給人工判斷繼續或中止,這比把缺失資料當作成功更可控。
第七步:可靠性、權限與稽核
控制器需要 leader election 或租約,佇列事件至少一次投遞,消費者用冪等鍵去重。發布規格、策略變更與人工批准寫入不可變稽核日誌。只有發布 owner 能改變權重,指標讀取憑證放在密鑰管理系統,回滾權限與普通發布權限分離。
監控控制面 SLO:狀態推進延遲、卡住發布數量、回滾耗時、路由實際權重偏差、分析查詢失敗率。控制面自身異常時,路由保持最後安全狀態,並由值班人員接管,而不是自動把 Canary 放大到 100%。
第八步:驗證與容量測試
用故障注入驗證錯誤率升高、指標無資料、指標延遲、路由 API 逾時、控制器重啟、重複訊息與資料庫 schema 不相容。檢查每種故障的最終狀態與告警,而不只看 happy path。
回放歷史發布記錄,測量分析查詢成本與佇列積壓;對控制器做 N+1 實例故障測試。可把一百個並行發布作為壓測上限,觀察狀態庫鎖衝突、指標提供者 QPS 與路由更新速率,再調整階段並發上限。
設計取捨與邊界
自動決策減少人工延遲,但閾值錯誤會把雜訊放大成回滾,或把真實回歸當成通過。簡單的絕對錯誤率閾值易解釋,適合低流量服務;穩定版本對照或分層基線更能抵禦全天流量變化,卻需要更複雜的統計與樣本對齊。高風險服務可以要求自動分析通過後再人工批准。
藍綠發布提供快速切換與簡單回滾,但通常需要雙份容量;Canary 節省暴露面,卻要維護流量分割與分析視窗。Feature flag 能獨立控制功能開關,但不能取代二進位、依賴或 schema 的相容性檢查。選擇應由回滾成本、流量形態與 SLO 風險決定。
落地計畫與證據
先為單個無狀態服務實作唯讀分析與手動暫停,確認 stable/canary 標籤、指標分組與稽核欄位正確;再開放自動回滾,最後增加多區域、業務指標與並行發布限制。每個階段保留人工 kill switch 與明確 owner。
Google SRE 將 Canary 定義為限時、部分流量的部署與評估,並要求把評估接入發布流程;Argo Rollouts 則提供 AnalysisTemplate/AnalysisRun、指標閾值以及成功、失敗、不確定狀態。公開系統設計面試資料也把流量分割、guardrail 評估與自動回滾作為 Canary 設計要點。本題據此聚焦控制面狀態機與可恢復邊界,而非泛泛比較部署名詞。
常見誤區與追問
只說「按 10% 流量觀察」
沒有說明使用者分組、觀察多久、指標分母與失敗動作,無法證明系統安全。補充穩定基線、視窗、閾值、暫停與回滾路徑。
把指標無資料當作通過
收集器故障會偽造健康訊號。將無資料、NaN、延遲與樣本不足標記為不確定,暫停並告警。
只回滾 Deployment,不處理路由
舊 Pod 恢復不代表請求已離開 Canary。回滾必須核對實際權重、服務選擇器與快取/工作階段黏性。
資料庫遷移不可逆
舊版本可能無法讀取新 schema,路由切回也救不了請求。採用向後相容的 expand/contract,並把遷移狀態納入發布門檻。
如果指標提供者停機怎麼辦?
維持最後安全權重,停止自動放量,記錄未完成分析並通知 owner。恢復後從持久化階段重跑,不能用預設「通過」填補空白。