系統設計面試:如何設計一個安全的 Feature Flag 服務?
題干與適用場景
請設計一個 Feature Flag 服務,讓團隊不必重新部署就能開關功能,支援按環境、使用者分群和百分比灰度,並在設定服務故障時保持安全預設值。面試可追問低延遲評估、設定稽核、審批、回滾與多區域可用性。
這題適合平台工程、後端與系統設計職缺。公開題庫將類似題目描述為每秒百萬次評估與極低延遲;公開面經則把它放在平台工程系統設計環節。回答重點應放在控制面、資料面與發布安全邊界,而非堆砌元件名稱。
面試官考察點
- 能否把少寫多讀的設定系統拆成控制面與資料面。
- 能否定義穩定的百分比灰度,避免使用者在請求間來回切換版本。
- 能否設計預設值、過期時間、kill switch 與回滾,限制設定錯誤的爆炸半徑。
- 能否說明一致性、延遲、稽核與多租戶隔離的取捨。
回答前需要釐清的問題
先確認評估是在 SDK、邊緣節點還是中心服務完成;目標是每秒百萬次評估還是較低吞吐;灰度維度是使用者、組織、區域還是工作階段;設定是否允許秒級生效;失敗時每個 flag 的安全預設值是什麼。也要確認是否需要實驗分流、強制關閉與審批流程。
30 秒回答框架
我會先給出控制面:建立 flag、規則、版本、審批與稽核;再給出資料面:SDK 或邊緣快取拉取已發布版本並在本地評估。規則按環境和目標群組匹配,百分比使用穩定使用者識別碼雜湊分桶。發布採逐步擴大、指標告警自動回滾;拉不到新設定時繼續使用有期限的舊版本或安全預設值。
分步驟深入解答
核心資料模型
Flag 至少包含 key、環境、預設值、規則列表、版本、發布時間、過期時間與稽核資料。規則可按組織、區域、使用者屬性匹配,也可提供百分比分桶。規則順序必須明確,第一個匹配規則勝出,並在發布前做語法、型別與語義驗證。
控制面與資料面
控制面負責寫入、審批、版本化、稽核與發布;資料面只讀取已發布快照並完成評估。客戶端 SDK 優先從記憶體快取讀取,背景透過輪詢、長連線或訊息通知更新。設定中心短暫不可用時,業務請求不必同步等待控制面。
穩定灰度與安全發布
把 flagKey + stableSubjectId + salt 做一致雜湊,再映射到 0 到 9999 的桶。百分比從 1% 擴大到 5%、25%、50%、100% 時,已進入的使用者保持在同一版本。發布前驗證規則與依賴,發布中觀察錯誤率、尾延遲與業務指標;觸發告警就回滾到上個已驗證版本。
~~~text evaluate(flag, context, snapshot): rules = snapshot[flag].rules[context.environment] for rule in rules: if matches(rule.targeting, context): if rule.percentage is absent: return rule.value bucket = hash(flag.key + context.stableSubject + rule.salt) % 10000 if bucket < rule.percentage * 100: return rule.value return snapshot[flag].safeDefault ~~~
關鍵取捨
| 方案 | 優點 | 代價 | 適用條件 |
|---|---|---|---|
| 中心同步評估 | 規則統一、更新快 | 每次請求依賴網路 | 低吞吐或必須強一致 |
| SDK 本地評估 | 延遲低、中心故障可隔離 | 規則下發與安全儲存更複雜 | 高 QPS、可接受短暫陳舊 |
| 邊緣評估 | 就近回應、跨區域穩定 | 分發與失效更複雜 | 全球流量與區域隔離 |
AWS AppConfig 的公開文件採用版本、環境、部署策略與驗證器,並支援按目標逐步部署;它也能用監控告警自動回滾。這支持「發布流程是系統的一部分」,不代表所有業務都必須複製 AWS 的元件形態。
高品質示範回答
我會把系統分成控制面和資料面。控制面保存 flag 定義、規則、版本與稽核記錄,所有變更經過驗證與審批後生成不可變快照。資料面由 SDK 或邊緣節點快取快照,在本地完成規則匹配與百分比評估,避免每次請求呼叫中心服務。
百分比灰度使用穩定主體識別碼做一致雜湊,因此同一使用者在 1% 擴到 25% 時不會反覆跳版本。每個 flag 都有安全預設值和過期策略;應用啟動時若拿不到快照,應按 flag 風險選擇關閉或繼續使用最後一個未過期版本。發布按小比例逐步擴大,配合錯誤率、P99 延遲和業務指標告警自動回滾。若需要強一致或立即關閉,我會提供短路徑 kill switch,但會說明它對快取、權限和稽核的額外成本。
常見錯誤
- 每次請求都存取中心設定服務,把 flag 系統變成業務關鍵鏈路上的單點延遲。
- 用隨機數做百分比灰度,導致同一使用者在請求之間不斷切換。
- 沒有版本號、過期時間與稽核記錄,無法解釋誰在何時發布了什麼。
- 只設計開關介面,不設計回滾、預設值與設定驗證。
- 把最終一致性、快取陳舊窗口與緊急關閉語義混在一起,沒有為不同風險設定不同策略。
追問及應對
如何保證跨實例的使用者體驗一致?
所有實例使用同一穩定主體識別碼、flag key 和 salt,且快照版本可觀測。不要把隨機請求 ID 作為分桶輸入;匿名流量可使用持久化工作階段識別碼,並說明其生命週期。
設定服務不可用怎麼辦?
資料面繼續使用最後一個未過期快照;超過 TTL 後按 flag 風險回到安全預設值。SDK 要記錄快照年齡、拉取失敗和評估來源,避免靜默使用無限陳舊設定。
如何撤回危險功能?
提供受權限保護的 kill switch,讓高風險 flag 的關閉路徑比普通發布更短。關閉操作仍需記錄操作者、原因、版本與影響範圍,避免緊急操作失去稽核。
如何防止規則設定錯誤?
發布前做 schema、型別、互斥條件與覆蓋率檢查;用離線樣本評估規則,確認每個目標至少命中一個預期分支。高風險變更先在影子環境或小比例環境執行。
多區域如何處理?
控制面可按區域複製已發布快照,資料面在本地讀取。每個快照帶版本與發布時間,監控區域間版本差距;若區域無法更新,繼續使用上一個安全版本並告警。
什麼時候不該使用 Feature Flag?
純靜態設定、一次性遷移或需要強事務一致性的權限判斷不一定適合 flag。若 flag 數量、規則和過期債務持續增長,應設定負責人、過期日期與清理指標,避免執行時規則取代正常發布流程。