功能开关与渐进式发布:以更低风险发布企业应用新功能
向企业应用发布新功能,常常感觉像是按下一个大按钮,然后祈祷不要出问题。代码被合并、部署到服务器,所有用户立刻看到变化。如果出了问题,唯一的出路是重新部署旧版本,这既耗时,又往往发生在最不合适的时刻。难怪许多团队选择很少发布、一次发一大包,而这反而使每次发布风险更高。
功能开关(feature flag)与渐进式发布提供了另一种方式:代码可随时部署,但新功能只在您决定的对象和时间打开。一旦出现问题,功能可在几秒内关闭,无需重新部署任何东西。本文用商业语言解释这一概念、开关的类型、渐进式发布模式、需要管理的风险,以及如何在您的企业应用中起步。
摘要
- 功能开关把通常捆绑在一起的两件事分开:把代码部署到生产环境,与向用户打开功能
- 渐进式发布先对一小群用户打开功能,监控影响,然后再扩大,使问题在波及所有人之前被发现
- 可以快速关闭的开关,是应对漏过测试的错误的最佳保障
- 不清理的开关会变成技术债,因此每个开关都需要负责人、目的和删除日期
- 从一个高风险功能、一个简单开关和清晰的监控开始,而不是上来就用大型平台
一次性发布的问题
在传统发布中,部署代码和显示功能是同一个事件。这会带来企业应用团队熟悉的若干问题。
- 风险累积:由于很少发布,每次发布一次性包含很多改动,一旦出错,很难知道是哪项改动所致
- 恢复缓慢:回滚意味着重新部署和重新测试,而用户仍在持续遭遇问题
- 发布时间的压力:团队选择午夜或周末以尽量减少影响,代价是疲劳和失误
- 长期存在的代码分支:功能在独立分支上开发数周,最后的合并充满冲突
- 排期依赖:已就绪的功能必须等待另一个尚未就绪的功能,因为它们打包一起发布
- 没有学习空间:所有用户一次性收到改动,因此在影响扩散之前没有机会检查反应
对企业来说,后果是真实的:繁忙时段的服务中断、客户投诉,以及害怕发布的团队,使创新放缓。

功能开关如何运作
从概念上讲,功能开关是应用内部一个简单的分支:如果该功能开关对这个用户是打开的,就显示新行为;否则显示旧行为。开关的值并非嵌入在代码中,而是从无需重新部署应用即可修改的设置中读取,例如来自配置表、专用服务或会重新加载的设置文件。
因此,团队可以在新功能尚未准备好展示之前,把它的代码部署到生产环境,让它保持关闭,然后以受控方式打开。部署和上线成为两个独立的决定,而第二个决定可以由产品负责人而不仅仅是开发人员来做。
寿命不同的四类开关
并非所有开关都一样。区分它们有助于管理其生命周期。
1. 发布开关
用于隐藏未完成或正在渐进上线的功能。其寿命很短:一旦功能对所有人打开且稳定,就必须从代码中删除该开关。
2. 实验开关
用于在不同用户群上测试两个变体并比较结果,如企业网站的 A/B 测试与转化优化。其寿命中等:当基于数据做出决定时即告结束。
3. 运维开关
用作紧急开关或负载控制,例如流量激增时关闭较重的功能,或停用出问题的第三方集成。其寿命可以很长,因为它本就是作为永久性保障。
4. 权限或套餐开关
用于按订阅套餐或客户类型控制可用功能,尤其是在多租户 SaaS 产品中。其寿命很长,实际上是产品模型的一部分,而不是发布工具。在SaaS 产品的多租户架构中,这一类通常被当作套餐配置,与发布开关分开处理。
渐进式发布模式
有了开关,功能可以用几种降低风险的模式上线。
- 内部发布:先只对员工或测试团队打开,他们往往能发现最明显的问题
- 试点用户:对少数愿意且已被告知的客户打开,通常是与团队关系较近的客户
- 渐进百分比:1%、5%、25%、50%,然后全部,每个阶段暂停监控
- 按分群:按分店、按地区、按套餐或按用户类型,适用于各群体影响不同的情形
- 影子或并行:新代码在后台运行,其结果与旧代码对比而不影响用户,适用于价格或税费等重要计算
- 紧急开关:当指标恶化时立即关闭功能的能力
模式的选择取决于风险。小的界面改动可以直接对所有人打开,而价格计算、支付流程或库存同步的改动则应分阶段并配合监控。
渐进上线期间监控什么
渐进式发布只有在您能看到影响时才有用。要在打开之前而不是之后设定指标。
- 被改动功能的错误率和异常率,与尚未收到改动的群体对比
- 响应时间和服务器负载,因为新功能有时比预期更重
- 业务指标:结账完成率、订单数量、完成任务的时间,或支持工单数量
- 用户反馈:投诉、评论以及相关主题的工单
- 集成健康度:支付、物流以及与之相关的其他系统
这与可观测性、日志与错误处理的原则一致:要对比收到改动与未收到改动的群体,日志和指标需要记录某个请求使用的是新行为还是旧行为。还要设定触发关闭的阈值,例如错误率上升超过某一限度,以及谁有权按下开关。

与测试和发布的关系
功能开关是对测试的补充,而不是替代。自动化测试和CI/CD确保代码在部署前能正常工作,而开关管理部署之后、在无法完全模拟的真实环境下的风险。需要记住的几点:
- 两种状态都要测试:每个开关都会使代码路径翻倍,所以要测试开启时和关闭时的行为,包括开启后再关闭的情形
- 谨慎对待数据库变更:变更后的结构在过渡期必须同时兼容新旧版本,这样关闭开关才不会损坏数据
- 开关组合:当多个开关相互依赖时,组合数量增长很快,因此要限制同时启用的开关数量并记录依赖关系
- 仍然需要[用户验收测试](/blog/uat-pengujian-sebelum-aplikasi-diluncurkan),而开关使其更容易,因为可以只对生产环境中的测试人员打开功能
对移动应用来说,远程开关尤其有价值,因为应用商店发布需要审核,用户也按自己的节奏更新。新功能可以先随应用发出,稍后再打开,正如向 App Store 和 Google Play 发布应用一文所讨论的。有了开关,出问题的功能可以直接关闭,而不必等待修复版本通过应用商店审核。
风险及其管理
功能开关并非没有成本。一些常见的风险:
- 被遗忘的开关:完成后没有删除的开关会使代码充满死分支,难以阅读和测试。这是[技术债](/blog/utang-teknis-technical-debt-mengukur-dan-melunasinya)的真实表现
- 配置错误:在生产环境错误打开的开关可能影响巨大,所以要限制谁可以修改,并记录每次变更及操作者
- 行为不一致:用户在两次访问之间突然看到功能出现又消失会感到困惑,因此要确保同一用户始终一致地停留在同一变体上
- 对开关服务的依赖:如果开关值从外部服务获取,要为该服务无法访问时规定安全的默认行为
- 测试复杂度:启用的开关越多,需要测试的组合就越多
简单而有效的管理做法:
- 为每个开关设置清晰的名称、负责人、目的、创建日期和目标删除日期
- 维护一份启用中的开关清单并定期复核,例如每月一次
- 把删除开关纳入功能“完成”的定义
- 为无法读取开关值的情形规定安全的默认行为
- 限制修改生产开关的权限,并保留审计痕迹
自己搭建还是使用服务
对大多数中小企业来说,功能开关可以从非常简单的方式起步:数据库中的设置表或应用读取的配置文件,再配一个用来修改的小型管理页面。这足以满足紧急开关以及基于用户名单或百分比的简单渐进上线。
当您需要复杂的定向、可衡量的实验、多环境管理、细致的访问权限或完整的审计痕迹时,专门的功能开关服务才有用。要考虑订阅成本、依赖第三方的风险,以及保障用户数据安全的需要。从简单开始,当真实需求出现时再升级。
几周内起步的步骤
1. 选择下一个将发布的高风险功能,例如结账流程或价格计算的改动。
2. 构建一个无需重新部署应用即可修改的简单开关机制。
3. 确定谁有权修改,以及如何记录变更。
4. 设定监控指标和触发关闭的阈值。
5. 渐进上线:内部、试点用户,然后逐步提高百分比,并设监控暂停。
6. 稳定之后,对所有人打开,并安排删除该开关。
7. 评估结果,然后把这一做法推广到其他高风险功能。
还要把上线后的应用维护纳入计划,因为渐进发布的习惯在配合日常监控时最为有用。
常见问题
功能开关只适合大团队吗?不是。简单的版本,即设置表中的一个开关,对小团队也非常有用,因为它提供了无需重新部署即可关闭功能的能力。
开关会拖慢应用吗?如果开关值保存在内存中并定期刷新,影响通常很小。只有当每次请求都从网络服务获取开关时才需要留意。
开关可以保留多久?发布开关应在功能稳定后的几周内删除。运维开关和套餐开关可以长期保留,前提是有文档记录并有人负责。
渐进式发布是否意味着把用户当作小白鼠?做得好就不是。目的是通过从小群体开始、监控并在必要时关闭,保护用户免受同时波及所有人的问题。对于敏感改动,应选择已被告知的群体。
结论
功能开关与渐进式发布把发布从一次大赌注变成一系列小而可逆的步骤。通过把代码部署与功能上线分开、在每个阶段监控指标,并准备好紧急开关,团队可以更频繁地发布,同时降低风险。用纪律加以平衡:为每个开关指定负责人和删除日期,使其不会变成技术债。从一个高风险功能和一个简单机制开始,再按需发展。
为您推荐
与此主题相关的阅读
免费清单:如何选择软件公司
签约前评估供应商的 24 个要点,可保存为 PDF。