凌晨 2 点 Feature Flag 被全量打开:我用灰度策略 + 自动回滚把故障恢复时间从 23 分钟压到 40 秒
凌晨 2 点 Feature Flag 被全量打开我用灰度策略 自动回滚把故障恢复时间从 23 分钟压到 40 秒说实话我从来没想过一个配置开关能把整个 on-call 团队从床上薅起来。凌晨 2 点 17 分PagerDuty 响了。新上线的「会员积分翻倍」功能被全量打开但后端账务系统根本没准备好。订单页面开始报错客服群里炸锅老板在群里连发了三个问号。从发现到止血我们用了 23 分钟。而那 23 分钟里真正有意义的修复动作只有 40 秒把 Feature Flag 切回灰度。那次之后我把整个发布治理链路重新改了一遍。今天把这套东西写出来希望对你们有用。不是代码的锅是人的锅也是流程的锅先还原一下现场。我们用的是自研的 Feature Flag 平台规则存在 Redis 里管理后台给运营用。那天白天产品运营在后台配置了一条规则「新会员在 7 月 20 日 0 点看到翻倍活动」。本意是只给新会员灰度但配置的时候手滑把user_segment写成了all。更坑的是这条规则在发布到生产环境后没有触发任何审批。也没有自动回滚。等到流量高峰问题才暴露。23 分钟的排查时间线大概是这样的02:17监控告警下单接口错误率飙升到 18%02:21确认不是数据库问题也不是依赖服务超时02:26有人在群里问是不是今晚上的活动有问题02:31查到 Feature Flag 平台发现all被打开02:40手动改回灰度错误率下降你看真正的修复动作只有最后那一下。前面的 23 分钟全都在找答案。灰度不是摆设要有策略和护栏Feature Flag 不是“开”和“关”两个状态。它至少应该包含四层能力1. 百分比灰度最基础的能力。先给 1% 用户开再 5%、10%、50%最后全量。每一步都有观察窗口。# 自研平台规则示例flag_key:double_points_july_2026rules:-audience:allpercentage:5start_at:2026-07-20T00:00:0008:00observe_minutes:30-audience:allpercentage:100start_at:2026-07-20T02:00:0008:00require_approval:true2. 用户画像灰度按用户属性切。比如registered_after: 2026-07-01或者membership_level: new。这是那次事故最该用的规则。3. 错误率自动回滚这是我后来加的最关键的一条。如果某个 Flag 打开后关联接口的错误率在 5 分钟内超过阈值系统自动把该 Flag 的生效范围降到 0。# 自动回滚伪代码ifflag.rollout_percentage0and\ error_rate(flag.target_api,window5m)flag.max_error_rate:flag.rollout_percentage0flag.stateauto_rolled_backalert_sre(flag)4. 审计与审批任何把灰度比例从 0 调到 100 的操作必须走审批。任何把audience改成all的操作必须记录并通知。我们改造后的发布流程事故后我对发布流程做了三件事。第一Flag 变更必须走 GitOps。运营后台不再直接写 Redis。所有规则以 YAML 形式存在 Git 仓库走 PR 审批CI 校验通过后再同步到生产环境。这样all这种危险值在代码审查阶段就能被发现。# 改造后的配置示例flags:-key:double_points_july_2026default:falserollout:-segment:new_memberspercentage:10error_rate_threshold:0.01auto_rollback:truerequire_approval_for_full_rollout:true第二引入 kill switch。每个核心功能必须有一个独立的 kill switch。出问题的时候不需要改代码不需要重启服务点一下就能关。// Java 代码示例booleanpointsDoubleEnabledflagClient.boolValue(double_points_july_2026,userContext,false// 默认值永远关闭);默认值一定要关。这是血的教训。第三Flag 生命周期管理。临时活动 Flag 必须有到期时间。到期未清理的 Flag每天早上 9 点给负责人发邮件。我们不允许一个临时开关变成永久代码分支。踩坑记录这次改造不是一帆风顺记录几条值得注意的坑。1. 命名不规范后期根本分不清哪个 Flag 是干什么的。早期我们有new_feature_2025、new_feature_2025_v2、new_feature_2025_final。整改后强制命名格式{业务域}_{功能}_{版本}_{生效日期}。例如payment_double_points_20260720。2. 没有灰度观察窗口上线即全量。很多团队以为 Feature Flag 就是“先给小部分人开”。但真正安全的是小范围开 → 观察指标 → 扩大范围。中间任何一步指标异常都必须停下来。3. 自动回滚只盯着错误率忽略了业务指标。有些 Flag 打开后接口错误率没升但下单转化率暴跌。我们后来把「核心业务指标」也纳入了回滚判断条件。4. 默认值和兜底逻辑不一致。有一次 Flag 服务本身挂了代码里默认值是true结果全量功能被打开。整改后所有关键 Flag 的默认值必须是false并且必须有独立的兜底逻辑。效果对比改造前后我们对比过几个核心指标指标改造前改造后故障发现时间平均 8 分钟平均 2 分钟故障止血时间23 分钟40 秒自动回滚全量发布审批缺失12 次/月0 次过期 Flag 未清理47 个3 个以内最让我满意的不是数字而是 on-call 同事的心理状态。以前大家最怕半夜被叫醒现在知道大部分 Flag 问题会自动止血心理负担小了很多。写在最后Feature Flag 本质上是一种发布治理工具。用好了它是渐进式交付的利器用不好它就是一颗随时会炸的雷。我后来总结了一句话Flag 可以开但必须是灰度地开、有护栏地开、能被审计地开。如果你也在用 Feature Flag建议先回答三个问题你的核心功能有没有 kill switch全量打开是否需要审批指标异常时能不能自动回滚如果这三个问题里有一个答案是“不能”那今晚就可以开始改了。别等凌晨 2 点的 PagerDuty 来提醒你。工具没有好坏只看你怎么用。Feature Flag 尤其如此。