什么是功能旗标 (feature flags)? 为什么要用功能旗标?

2025年1月20日

💎 加入 E+ 成長計畫 如果你喜歡我們的內容,歡迎加入 E+,獲得更多深入的軟體前後端內容

AWS 的 S3 是全世界最多人使用的网路服务之一,而也正是因为非常多服务依赖 S3,在 2017 年 S3 发生的一次重大事故,让全世界许多网站无法被使用,造成 AWS 损失超过 1.5 亿美元。

你可能会想,是什么重大技术困难,导致如此高额损失的事故?

事实上,该次重大事故的原因是打错字 (typo)。你没有看错,该事故不是什么重大技术难题导致的,而是因为多数人认为应该要能避免的错字问题造成的。

虽然很多人可能会把打错字当成低级错误,但事实上打错字、差一个空格、差一行等看似简单的问题,假如当到了一个完全不熟悉,且有复杂历史程式码的程式码库中,即使是很细心的人,也可能会出错。

因此,从工程的角度来看,该思考的是如何让相同的错误「不可能」再发生。只要有足够完善的机制,很多人为的错误将变得不可能。对此,如果想要成为资深工程师,从这个视角出发思考是很重要的。

在 S3 当年的事故检讨中,针对这个打错字的问题,总结了几个最关键且能够透过工程手段避免的点,分别如下:

  • 输入框没有做校验 (input not validated)
  • 配置的更动一次全量推送 (config change pushed out everywhere at once)
  • 回滚没有自动化 (rollback not automatic)
S3 当年的事故检讨中
S3 当年的事故检讨中
圖片來源:https://youtu.be/AH_LNzgdmjs?si=dHOnhaEEb8XulW_z

试想,假如今天输入框有校验,这样打错字就能够在配置阶段就被发现。再退一步,假如配置不是一次全部推送,而是逐步推送给终端使用者,这样可以在一开始只推送给小量使用者时就发现,能避免一次推送给全世界,导致一出问题影响范围就遍及全世界。最后,如果出事故时能有自动侦测并回滚,那将能够让问题影响立即止损。

这一期的主题文,我们将会专注在上述三个解决方案中的第二个,来讨论如何做到让更动可以避免一次全部推送。而如同这期主题文标题,具体要实现这个方案的常见做法,会是透过功能旗标 (feature flags)。

什么是功能旗标 (feature flags)?

所谓的功能旗标,是现代软体经常会使用的技术,该技术做的事情很简单,透过某个旗标 (flag),让软体在不需用重新部署的状况下,能够切换开启或关闭某个功能。在业界有另一个词叫功能切换 (feature toggle) 也是指同样的概念,但由于近年来相关的技术,已经发展到不只是切换开与关,所以目前更多人会用功能旗标这个词。

这样讲起来很抽象,让我们透过一个具体的例子来了解。假如今天你在开发一个餐厅论坛的应用程式,想要在该应用程式中,加上一个 AI 聊天机器人,让造访的使用者,可以直接问 AI 机器人问题,例如可以问「请告诉我大坂最热门的 10 间大坂烧店」。

但在上线这个聊天机器人前,假如不想要一次让所有使用者使用 (因为担心 AI 的幻觉问题,想要先小部分使用者测试),这时可以透过功能旗标,仅对部分的使用者开启该 AI 聊天机器人的功能,以下我们以图示的方式解说。

首先,从程式码的角度,功能旗标的概念就像下面这段程式码,透过一个布林的判断,来决定是否展示某个功能。特别注意,这边的 user.shouldSee("aiChatbot") 的值,不会是写死在程式码库,而会是写在某个设定档 (config file),然后透过功能旗标的管理平台 (例如 LaunchDarkly、PostHog 这种平台,或是 AWS 的 AppConfig) 来管理,所以不需用动程式码,也可以透过平台去改变 user.shouldSee("aiChatbot") 的值。

if (user.shouldSee("aiChatbot")) {
  showAIChatbot();
} else {
  showOldFeature();
}

当功能旗标的设定档中把 AI 聊天功能关上,使用者进到网站就看不到 AI 聊天功能

+------------------------------------+
|              云端                   |
|                                    |
|    +------------------------+      |
|    |      功能旗标服务        |      |
|    |  +------------------+  |      |
|    |  | 设定档            |  |      |
|    |  | AI 聊天功能:关    |  |      |
|    |  +------------------+  |      |
|    +------------------------+      |
|             ^     |                |
|             |     v                |
|    2. 确认功能设定  3. 回应设定结果    |
+------------------------------------+
             ^       |
             |       v
     使用者进入网页  AI 聊天功能未显示

然而,可以针对部分使用者,把设定档中的 AI 聊天功能开启,这样这些使用者就能看到

+------------------------------------+
|              云端                   |
|                                    |
|    +------------------------+      |
|    |      功能旗标服务        |      |
|    |  +------------------+  |      |
|    |  | 设定档            |  |      |
|    |  | AI 聊天功能:开    |  |      |
|    |  +------------------+  |      |
|    +------------------------+      |
|             ^     |                |
|             |     v                |
|    2. 确认功能设定  3. 回应设定结果    |
+------------------------------------+
             ^       |
             |       v
     使用者进入网页  AI 聊天功能显示

金丝雀部署

如前面对功能旗标的介绍,在有了功能旗标后,新的功能就能做到部分上线。举例来说,可以先把使用者分群,在最开始时只有内部使用者 (例如开发人员、产品经理、 QA 测试人员) 可以看到。

在这个阶段,虽然程式码已经部署到线上环境,但因为有功能旗标,多数使用者不会真的能用到功能,因此不会真的对使用者有影响。等到测试完后,就可以开始逐步扩量。

逐步扩量时,可以透过功能旗标,开始可以先对 5% 使用者展示功能,然后 10%、30%、50% 到最后才 100% 全量上线。在这个过程中,开发者可以持续监控,假如在 5% 或 10% 放量时,发现监控中的指标有异常,这时就可以即时停止继续放量,甚至回滚原本的少部分放量。

透过这种做法,可以有效避免一次全上线,结果出问题会导致所有线上使用者都受影响的状况。以上面提到的例子来说,如果在 10% 放量时,就观测到指标有异常,这时及时介入,异常就能限缩在 10% 的使用者,这大大降低了爆炸半径。

事实上,这样的做法,在业界普遍会用金丝雀 (canary) 这个名词来描述。这种方式之所以叫金丝雀部署,是源自早年矿场为了确保矿坑没有毒气,在矿工实际进入矿坑前,会先放金丝雀去探勘,假如金丝雀能顺利飞回来,代表矿坑没有毒气;反之,如果金丝雀没有飞回来,那估计因为矿坑中的毒气导致金丝雀死亡,这时矿工团队就知道不该继续往下挖矿。

而对应到程式码的部署,金丝雀部署就像放出金丝雀,先以金丝雀去探勘,而不是直接全量上线,这样遇到问题的话,也只有前面有被放出的小流量会被影响,而不会造成过于巨大的损失。在早期许多团队也会用一种叫蓝绿部署的方式,也是先有测试后,直接把所有流量都切到最新的版本。然而这种方式的灵活性相对低,因此目前业界更偏向金丝雀部署。

因此,回到最开始的问题,如果在上线时,想要避免一次推全量,可以怎么做呢? 一句话总结来说,我们可以透过功能旗标,来做到金丝雀部署,这样就能避免一次全量。

阅读更多

如果你对「功能旗标」这主题感兴趣,我们在 E+ 有更深入的讨论。有兴趣的读者,欢迎加入  E+ 成长计划。我们在 E+ 有更深入的内容,包含透过功能旗标做到在生产环境测试 (testing on production)、 主干导向的开发 (Trunk-based Development)、透过功能旗标的分群部署做到 A/B 测试 等不同议题

本文为 E+ 成长计划的深度内容,截取段落开放免费阅读。欢迎加入 E+ 成长计划阅读完整版本 (点此了解 E+ 的详细介绍)。

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們