文章

基于 Feature Flag 的开发模式

基于 Feature Flag 的开发模式

Feature Flag是什么

Feature Flag(特性开关、功能开关)是软件开发中的一种技术,它允许在不重新部署代码的情况下,在运行时开启、关闭或修改应用程序中的特定功能。

💡 核心概念

  • 将代码部署与功能发布分离: 这是 Feature Flag 最重要的作用。你可以将一个未完成或未测试的新功能代码部署到生产环境中,但通过 Feature Flag 默认将其关闭。
  • 条件逻辑: Feature Flag 本质上是代码中的一个简单条件语句(例如 if (feature_flag_enabled)),它控制着一段特定功能代码是否会被执行。
  • 外部配置: 旗帜的状态(开/关)通常存储在外部配置服务中,与代码库分离,这样你就可以随时更改其状态,而无需重新编译或部署应用程序。

Feature Flag 的主要价值在于将代码部署功能发布解耦。这使得你可以将代码推送到生产环境,但通过灵活地控制 Feature Flag 的状态, 它就像一个策略执行层,它将传统的部署工作(将代码部署服务器上)和发布工作(让用户看到新功能)彻底分开,从而让团队能够实现更安全、更灵活、基于数据的发布流程。

Feature Flag 的发展历史

Feature Flag 真正被广泛认可和系统化,主要是在 2000 年代中期到末期,随着敏捷开发 (Agile)持续集成 (CI) 实践的兴起。

核心痛点与场景

持续集成与持续发布(CI/CD)中强调主干分支的代码需要时刻保持在可部署的状态,这需要不断地将 feature 开发分支与主干分支进行合并,而不是等待一周甚至几周的时间,待所有功能开发完并通过完整的测试再合并到主干分支。CI/CD 的目的就是为了加快软件的开发与部署速度与效率,将新的功能尽快部署上线,同时尽可能降低风险。

虽然 CI/CD 能够加速软件与功能的交付速度,但是与之而来的风险并没有很好消除。当所有功能一次上线到生产环境后,如果包含比较严重的 bug 但不能及时发现,结果将很难预料。虽然 CI/CD 模型中的金丝雀发布(canary release)能够控制 bug 影响的范围,但是需要依赖比较复杂的控制系统。因此目前大部分场景下的 CI/CD 系统并不是严格意义上的持续集成与持续交付,大部分情况还是基于 feature 分支进行开发,然后在合适的时机合并到主干分支一并进行上线。

在这种强调主干分支的代码需要时刻保持在可部署的状态的开发模式。这导致了几个严重问题:

  • “代码冻结”和“合并地狱”: 在发布前,代码需要“冻结”进行测试,导致开发工作停滞。特性分支合并到主干时,经常出现大量冲突(Merge Hell)。
  • 发布周期长: 每次发布都必须包含所有已完成的功能,发布周期漫长且风险高。
  • 高风险回滚: 如果生产环境出现问题,回滚操作需要撤销整个部署包,代价高昂。

目前持续发布(CD)能够通过一些用户数据、系统监控或者一些核心指标对部署的功能进行监控,当发现问题及时回滚,以此形成一个持续迭代闭环。但是当用户体量非常大的时候,一个小的问题可能会造成难以衡量的损失,这是不可接受的。

而渐进式发布的方式将新的功能隐藏在一个 feature flag 中,并可以通过可视化界面对发布的过程进行灵活控制,这是渐进式发布与目前 CI/CD 形态的一个比较关键的区别,其示意图。此外还有一键关闭、紧急生效参数、流量控制与监控等功能,当出现问题时不需要重新部署代码,通过按键即可进行功能的回滚,进而尽可能减少故障时的影响范围。可以说渐进式发布就是为解决发布问题、提高发布稳定性而生的发布理念。

渐进式发布和持续发布对比

Feature Flag 最初是为了解决在持续集成环境下,如何安全、频繁地将未完成的特性合并并部署到生产环境这一挑战而产生的。

Feature Flag 解决的场景

Feature Flag 就是为了解决这些痛点,支持 “主干开发 (Trunk Based Development)” 这一关键 CI 实践而被广泛采用的。

  • 场景 1:频繁合并到主干
    • 需求: 开发人员需要每天甚至每小时将他们的代码合并到主代码分支 (main/master)。
    • Feature Flag 的作用: 将正在开发中的、未完成的代码用 Feature Flag 包装起来并默认关闭。这样,即使未完成的代码部署到了生产环境,它也不会对用户可见,从而解除了合并的障碍。
  • 场景 2:功能和部署解耦
    • 需求: 软件公司希望将代码部署(技术操作)和功能发布(业务决策)分开。
    • Feature Flag 的作用: 代码部署可以随时进行,而市场营销、产品经理可以独立于工程师,随时通过外部配置界面控制功能的开启和关闭时间。

Feature Flag 的一大特性在于它将发布部署和撤回控的制点从网络层(负载均衡、路由)转移到了应用层(代码、用户)。

Feature Flag 带来的主干开发模式

基于 Feature Flag 的开发模式是持续交付 (Continuous Delivery) 的核心实践之一,它彻底改变了开发团队构建、测试和发布软件的方式。

  1. 开发阶段:包装与合并

    步骤描述Feature Flag的作用
    a. 特性隔离开发者在编写新功能时,立即使用一个 Feature Flag 将其所有新的、未完成的代码路径包裹起来。初始状态:关闭 (OFF)。代码在生产环境中是不可见的。
    b. 频繁合并即使功能尚未完成,开发者也应频繁(每天数次)将他们的代码合并到主代码分支 (trunk/main)。避免了长期的特性分支和“合并地狱”。主干始终保持可部署状态。
    c. 代码审查像往常一样进行代码审查,但重点是代码质量,而不是功能是否“完成”或“准备好发布”。保证代码健康,与发布策略分离。
  2. 部署阶段:持续集成
    • 自动化测试与构建: CI/CD 管道自动构建、运行单元测试和集成测试。
    • 部署到生产环境: 通过自动化流程,将主干上的代码频繁地(可能每天多次)推送到生产服务器。
    • 关键点: 由于新功能被 Feature Flag 默认关闭,即使代码进入生产环境,它也不会影响到最终用户。
  3. 发布阶段:按需发布

    这是 Feature Flag 模式的核心优势所在。发布不再是技术部署,而是业务决策。

    步骤描述Feature Flag 的作用
    a. 内部测试 (Dogfooding)功能完成后,通过 Feature Flag 管理界面,仅对内部员工或 QA 团队开启该功能。验证功能在真实环境中的表现,确保功能完善。
    b. 灰度发布/A/B 测试产品经理或发布经理(非工程师)通过配置工具,逐步向外部用户开放功能。实现了逐步放量、风险控制和数据驱动的决策。
    c. 全量发布确认功能稳定且指标良好后,将 Feature Flag 设置为 100% 开启。功能正式向所有用户推出。
    d. 快速回滚如果功能在任何阶段出现问题,发布经理立即将 Feature Flag 设置为关闭。瞬间禁用问题功能,实现零停机回滚。
  4. 清理阶段:移除代码
    • 一旦功能完全发布并稳定运行一段时间后,该 Feature Flag 就成为了“技术债务”。
    • 移除 Flag: 开发者应将该 Feature Flag 的代码和相应的条件逻辑 (if (feature_flag_enabled)) 从代码库中删除。
    • 代码清理: 移除旧的、不再使用的功能路径,使代码库保持整洁和可维护。

主干开发模式的优点:

  • 加速开发周期: 允许频繁合并和部署,极大地缩短了特性交付时间。
  • 降低风险: 风险被分散到小的、受控的发布中。回滚速度极快。
  • 解耦团队: 开发团队可以专注于代码质量和部署,而产品/业务团队可以独立地控制发布时间和用户群体。
  • 赋能实验: 轻松进行 A/B 测试和实验,支持数据驱动的产品决策。

Feature Flag的具体实践流程

Feature Flag 的实际实现需要跨越代码库、配置存储和发布管理界面等多个维度。要在项目中使用Feature Flag主要需要处理三个主要的技术领域和一个关键的流程领域

应用侧SDK集成

这是将 Feature Flag 逻辑嵌入到应用程序代码的过程。

  1. 引入 Feature Flag SDK/库: 在你的应用(后端服务、前端 Web 应用、移动 App)中引入一个库,用于与步骤一的配置服务通信。
  2. 查询状态: 在代码的关键决策点,调用 SDK 查询旗帜状态:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
     // 1. 构造用户上下文信息
     user_context = { user_id: 12345, location: 'CN', plan: 'Premium' }
    
     // 2. 查询 Feature Flag 状态
     if (feature_flag_client.is_enabled('new_checkout_flow', user_context)) {
         // 3. 启用新功能路径 (New Feature Code)
         render_new_checkout_flow()
     } else {
         // 4. 保持旧功能路径 (Legacy Code)
         render_old_checkout_flow()
     }
    
  3. 缓存策略: 为了性能和高可用性,客户端 SDK 应包含一个强大的缓存机制,定期从配置服务拉取最新状态,并使用本地缓存来避免每次请求都调用 API。

Flag储存系统

这是 Feature Flag 的大脑,用于存储和提供旗帜状态。

主要包含以下功能:

  • 选择存储介质: 选择一个快速、高可用的存储来保存 Feature Flag 的状态和规则。
    • 简单场景: 数据库(如 PostgreSQL, MySQL)或键值存储(如 Redis)。
    • 复杂场景: 专门的 Feature Flag 服务或配置管理系统(如 Unleash, Flagsmith)。
  • 实现配置服务 API: 提供一个高性能的 API 接口,供应用服务器查询旗帜状态。
    • 这个 API 必须能够根据传入的用户上下文信息(User Context,如用户 ID、设备类型、地理位置)实时计算并返回该用户应该看到的旗帜状态。

Flag管理UI

开发一个 Web UI,允许产品经理或发布经理非技术人员进行以下操作:

主要包含以下功能:

  • 创建、修改、删除 Feature Flag。
  • 设置旗帜状态(开/关)。
  • 定义目标规则(例如:为 用户 ID 范围 1-100 开启,或为 国家/地区 是中国的用户开启)

Flag储存系统和Flag管理UI可以使用成熟商业方案或者开源解决方案, 例如: Unleash / Flagsmith, 同时这种方案也提供了应用集成的SDK

发布流程与治理

这是确保 Feature Flag 不会成为“技术债务”的组织流程

命名规范:

制定清晰、一致的 Feature Flag 命名和标签系统。规定旗帜名称应包含项目、功能和版本信息,例如 projectX_checkout_v2_ab_test

监控和预警:

将 Feature Flag 的状态与你的监控和日志系统集成。确保新功能激活后,可以实时监测到相关的错误率、性能指标和业务指标。

Flag生命周期管理:

这是 Feature Flag 模式中经常被忽视但至关重要的一步。

  • 监控与分析: 在发布期间,监控新功能路径的技术指标(错误率)和业务指标(转化率)。
  • 全量稳定: 一旦功能达到 100% 稳定并确定是最终版本,将 Feature Flag 永久设置为开启,并通知开发人员。
  • 代码清理(Flagging Debt Removal): 开发人员必须从代码中移除 Feature Flag 的所有条件逻辑和旧的代码路径(else { ... } 部分),以减少技术债和代码复杂度。

实践案例

假设我们有一个项目是使用 Node.js/Express 构建的后端服务,并且选择使用 Unleash 来管理 Feature Flag。

下面是一个完整的集成案例,涵盖了 Unleash Server 配置、Node.js 项目集成以及如何在代码中使用 Flag。

🚀 Unleash Feature Flag 集成案例 (Node.js/Express)

步骤1: 前提条件和 Unleash Server 配置:

假设你已经按照 Unleash 的文档部署并启动了 Unleash Server。

在 Unleash 管理界面中(Server 端操作):

  1. 创建 Feature Flag: 创建一个名为 new-homepage-layout 的 Flag。
  2. 定义策略(灰度发布): 设置该 Flag 的默认策略为:
    • 对所有用户 开启 50% 的流量。
    • 对用户 ID 在白名单 ['user_A', 'user_B'] 中的用户,开启 100% 的流量。

步骤2: Node.js 项目集成 (Client 端操作):

我们将使用官方推荐的 unleash-client

1
npm install express unleash-client

在应用启动文件(例如 app.js)中进行配置, 配置和初始化 Unleash 客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// app.js (或 index.js)

const express = require('express');
const { initialize, isEnabled } = require('unleash-client');
const app = express();
const port = 3000;

// 替换为你的 Unleash Server 地址和应用名称
const UNLEASH_URL = 'http://localhost:4242/api/'; 
const APPLICATION_NAME = 'my-node-service';
const INSTANCE_ID = 'node-app-instance-1'; // 确保每个实例ID唯一

// 初始化 Unleash 客户端
const client = initialize({
    appName: APPLICATION_NAME,
    instanceId: INSTANCE_ID,
    url: UNLEASH_URL,
    // 默认回退机制:如果服务器不可用,将使用本地缓存或默认值。
    // 默认情况下,如果无法连接,所有特性都将被视为关闭 (false)。
    disableMetrics: false, // 启用发送心跳和使用指标给服务器
});

client.on('error', console.error);
client.on('ready', () => {
    console.log('✅ Unleash Client Ready!');
});

// Middleware 来模拟用户登录和上下文信息
app.use((req, res, next) => {
    // 假设我们从请求头或 Session 中获取用户信息
    const userId = req.headers['x-user-id'] || 'guest_user';
    req.unleashContext = {
        userId: userId,
        // 你可以在此添加其他属性,如 environment, sessionId, customProps
    };
    next();
});

// 导出客户端供其他模块使用
module.exports = { app, isEnabled: isEnabled };

现在,在业务逻辑中,使用 isEnabled 方法来决定执行哪个代码路径来实现 Feature Flag 的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// routes/homepage.js

const { app, isEnabled } = require('../app');

app.get('/', (req, res) => {
    // 1. 获取当前请求的用户上下文信息
    const context = req.unleashContext;

    // 2. 查询 Flag 状态
    // isEnabled('flag-name', context) 返回一个布尔值
    const isNewLayoutEnabled = isEnabled('new-homepage-layout', context);

    if (isNewLayoutEnabled) {
        // --- A 组:新功能路径 ---
        console.log(`用户 ${context.userId} 看到新布局`);
        res.send(`
            <h1>欢迎来到全新的主页 (A/New Layout)</h1>
            <p>这是新布局的功能代码...</p>
        `);
    } else {
        // --- B 组:旧功能路径 ---
        console.log(`用户 ${context.userId} 看到旧布局`);
        res.send(`
            <h1>欢迎来到旧的主页 (B/Old Layout)</h1>
            <p>这是旧布局的功能代码...</p>
        `);
    }
});

app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});

运行和测试结果:

  • 用户未在白名单,50% 灰度:
    • 请求头 X-User-ID: random_user_1:大约 50% 的概率看到新布局,50% 看到旧布局(Unleash 内部随机分流)。
  • 用户在白名单,100% 开启:
    • 请求头 X-User-ID: user_A:始终 看到新布局,因为白名单策略优先级更高。
  • 关闭 Flag:
    • 在 Unleash 管理界面中,将 new-homepage-layout 彻底关闭。
    • 所有请求都会看到旧布局,即使是 user_A,实现了即时回滚。

如何基于 FeatureFlag 实现渐进式发布

发布模式的发展历程

渐进式交付(Progressive Delivery)被认为是当前大规模、高成熟度发布流程演化中的最新、最先进的形态, 它代表了从简单的部署策略向智能、持续、自动化发布策略的重大飞跃。

软件发布流程的演化可以概括为四个阶段,每个阶段都引入了新的技术和理念来解决上一个阶段的痛点:

阶段 1:传统发布

  • 形态: 全量发布 (Big Bang)。
  • 关注点: 代码是否成功部署。
  • 痛点: 风险极高,一旦出错影响所有用户,需要漫长的停机时间来回滚。

阶段 2:基础设施优化发布

  • 形态: 蓝绿发布 (Blue/Green)。
  • 关注点: 降低部署风险,通过完全相同的两套硬件环境部署副本, 配合负载均衡器 (L.B.) 流量切换实现零停机。
  • 痛点: 成本高(需要两套环境),且只解决部署问题,不解决新功能本身的代码或业务逻辑问题。

阶段 3:风险最小化发布

  • 形态: 灰度发布 (Canary Release)。
  • 关注点: 降低代码风险,通过小流量验证稳定性。
  • 痛点: 灰度过程通常是手动或半自动化的。工程师需要手动监控仪表盘,并决定何时扩大流量或回滚。这种过程是缓慢且依赖人工经验的。

阶段 4:智能与自动化发布

  • 形态: 渐进式交付 (Progressive Delivery)。
  • 关注点: 自动化、数据驱动、持续优化整个发布生命周期。
  • 核心优势: 它将灰度发布自动化和智能化了。

渐进式发布是什么

渐进式发布(Progressive Delivery)被认为是持续发布(Continous Delivery)的下一代形态,其专注于增强发布过程控制与降低发布风险,最终提高整体收益。

CD 与 PD 的关系和演化

我们可以从它们解决的问题和它们的核心目标来理解这种演化关系:

特性持续交付 (CD)渐进式交付 (PD)
核心问题如何实现高频、可靠的部署。如何实现高频、安全、智能的发布。
核心目标确保代码随时处于可发布状态。确保功能安全地、逐步地到达正确用户。
主要关注点工程效率(CI/CD Pipeline)。产品策略和用户体验。
风险管理通过自动化测试和蓝绿/金丝雀部署来降低风险。通过 Feature Flag 和自动化指标监控来分阶段降低风险。
驱动力工程师(将代码部署到生产环境)。产品经理/数据科学家(通过实验和指标控制发布节奏)。

为什么 PD 是 CD 的下一代形态?

持续交付(CD)的核心理念是:将所有代码更改快速、安全地交付到生产环境。 CD 解决了部署的挑战。

然而,CD 留下了一个“空缺”:代码部署后,谁来决定何时、以何种方式、向哪些用户开放功能?

渐进式交付(PD)正是填补了这个空缺:

  1. 从部署到发布
    • CD 的终点: 成功部署代码到生产环境。
    • PD 的起点: 从部署开始,利用 Feature Flag 将功能发布(让用户看到)视为一个独立的、受控的过程。它将“功能激活”变成了业务决策,而不是工程部署的副作用。
  2. 从人工到智能
    • CD 下的灰度: 工程师部署后,通常需要手动或半自动地监控指标,人工决定流量的推进或回滚。
    • PD 下的灰度: PD 引入了智能自动化。它使用 AI/ML 或预定义的 SLO/SLA(服务水平目标/服务水平协议)来自动判断新版本是否健康,并自主决定流量推进或自动回滚。这实现了真正的“持续”和“自动化”发布。
  3. 从系统健康到业务健康
    • CD 的重点: 关心系统是否崩溃、延迟是否过高(技术指标)。
    • PD 的重点: 不仅关心系统健康,更关心新功能是否对业务有利(如转化率、留存率、收入——业务指标)。它将 A/B 测试 和 灰度发布 结合起来。

可以说: CD 提供了高速公路,而 PD 提供了智能交通控制系统,确保功能以最优速度安全到达目的地。

渐进式发布有两个特点:发布进度控制和发布阶段授权

其中发布进度控制即按一定的节奏将新的软件或者功能向用户推送,发布节奏可以是连续的也可以是分步骤的,以此控制每次生效的范围。这种做法建立在持续交付的核心原则之上,即将“代码部署”与“功能发布”分开。

发布阶段授权是指在不同的阶段将功能的操作权限授权给不同的团队,比如将功能的所有权慢慢从工程转移到产品,然后从产品管理转移到营销等等。

发布权限共享

发布进度控制和发布阶段授权并用,降低了持续交付相关的风险,并赋予团队在整个发布周期中更多的控制权。

渐进式交付不仅仅是一种发布策略,它是一种方法论,它将灰度发布、A/B 测试和 Feature Flag 融合在一个自动化、智能的流程中, 通过引入以下关键能力,超越了传统的手动灰度发布:

  1. 基于目标和指标的发布

    传统的灰度发布只关注技术指标(如 CPU 使用率、错误率)。渐进式交付则同时关注业务指标。

    • 定义发布目标: 在发布前,定义成功标准(例如:“错误率必须低于 0.1% 且 转化率必须高于基线 5%”)。
    • 实时评估: 系统持续监控新版本在小流量下的表现。
  2. 自动化和智能决策

    这是渐进式交付的核心区别。它消除了工程师手动监控和操作的需要。

    • 自动化推进: 如果所有技术和业务指标都在安全范围内,系统将自动将流量从 1% 提升到 5%,再到 25%,直到全量。
    • 自动化回滚: 如果系统检测到任何指标(无论是错误率还是转化率)超出预设阈值,系统将自动触发回滚,将 Feature Flag 关闭或将流量切回旧版本。
  3. Feature Flag 深度集成

    渐进式交付平台将 Feature Flag 作为核心组件,并将其与监控、实验和 CI/CD 管道深度集成。

    • 统一控制: 所有的分流、实验和流量决策都在一个平台内完成,而不是分散在负载均衡器、A/B 测试工具和代码逻辑中。

发布进度控制

发布进度控制指如何、何时、以多快的速度将新功能的功能激活范围从 0% 扩大到 100% 的过程。它强调的是自动化和数据驱动的流量管理。消除人工干预的延迟,使发布过程持续、平稳、安全地进行。

主要是通过 Feature Flags 和 自动化监控系统实现。

其核心目标包括

  • 流量分级: 将发布分解为明确的阶段(例如:内部测试 -> 1% 用户 -> 10% 用户 -> 50% 用户 -> 100% 用户)。
  • 自动化推进: 每个阶段的推进是基于实时数据和预设指标的。
    • 安全指标(技术 SLO): 如果新版本在 10% 流量下的错误率 $E_{new}$ 维持在目标阈值 $T$ 以下 ($E_{new} \le T$) 达 30 分钟,则自动将流量推进到 25%。
    • 回滚决策: 如果指标恶化,系统自动将流量切回旧版本。

进度控制案例:

新功能的灰度测试

Feature Flag能够帮助用户在生产环境测试新的feature效果,并可以通过开关快速的控制新feature的状态,以最大化的降低因新feature出现问题对线上环境的影响。

例如某个界面对一个看板进行了优化,那么可以通过配置 feature 的方式,让一部分用户先体验新的看板功能,另一部分用户维持原样,这样一来可以根据线上效果判断这个功能对系统稳定性带来影响,也可以避免新看板存在的 bug 影响到整体的用户。

看板灰度测试

定向发布

即只对指定用户生效特定新功能。Feature flag可以通过用户分群或自动以目标受众的方式,控制新功能只对小范围用户生效。

例如:

  • 比如某些用户已经是老粉了,而且倾向于尽早体验到产品的新功能,那么可以据此创建内测用户分群,新功能优先向这些用户推送。内测用户往往能够尽早为新功能提供反馈,进而及时做出功能调整。
  • 国际化公司,在不同国家上线功能,可以通过国家圈选不同用户,进而为不同区域定制功能开发。
  • 新的功能可以使用免费用户进行测试,查看功能的效果。

随机发布

即从线上所有用户抽取一部分流量做验证,如下图所示。

例如:

  • 新功能逐步上线,较指定日期全量上线,大大减小风险,即使出问题也只会影响一小部分用户,能够及时回滚。
  • 风险较大的变更上线(例如基础设施迁移,数据迁移,大型重构或基础架构更改),基本不会对你的产品或业务产生负面影响。
  • 提早暴露性能等问题,通过一部分流量的数据可以预测未来服务性能的变化,而不至于新功能的上线导致服务不可用。

随机发布测试

发布阶段授权

发布阶段授权指在发布流程的关键节点上,谁拥有批准和干预的权限,以及在哪个阶段需要人工或业务决策的介入。它强调的是治理和跨职能团队的协作。

依赖于 Feature Flag 平台或 PD 管道中的权限管理审批流程集成点

其核心功能包括

  • 业务决策点: 某些阶段的推进不能仅靠技术指标。例如,从 50% 用户到 100% 全量,可能需要产品经理 (PM) 确认 A/B 测试的业务结果(如转化率)是正向的,然后手动批准。
  • 风险授权: 某些高风险或高影响力的功能(例如支付系统升级),即使技术指标安全,也可能要求运维领导或合规团队手动批准才能进入下一个阶段。
  • 角色分离: 渐进式交付通过 Feature Flag 平台,将代码部署(工程师权限)和功能激活(产品经理/发布经理权限)的权限彻底分离。
  • 目标: 确保高风险决策被正确记录和审批,并让非工程团队(如市场、法律、产品)能够以受控的方式参与发布。

发布阶段授权场景:

结合账号体系

可以对每个feature按角色和用户设置权限。如果一个feature还在测试早期那么可以只为角色为研发的用户开通权限,以此类推。慢慢的将权限的控制移交给售前或者运营,实现功能上线与生效的分离。

权限管理

工作流程管理

可以对发布过程进行控制,在不同的发布阶段可以引入不同的角色或者用户进行审核,灵活调整每个发布阶段的授权范围,确保发布过程的可控性。

工作流管理

PD 的价值就在于它提供了一个框架,允许在低风险阶段(如 1% 流量)实现完全的自动化进度控制,同时在关键的高风险阶段(如 A/B 测试结果确认或全量)保留必要的发布阶段授权,从而实现工程效率和业务风险控制的最佳平衡

FeatureFlag 渐进式发布能力的应用场景

FeatureFlag的应用场景非常多,基于其提供的渐进式发布能力,可以加速产品迭代过程,提升服务稳定性。下面从几个方面介绍下常见的应用场景。

新功能灰度发布

新功能发版可逐步灰度扩量,先让小部分用户体验新功能,观察用户反馈和数据表现,再初步扩量,潜藏问题及时发现快速止损,如下图所示。

  1. 白名单测试+内测+众测

    新功能上线前,先用白名单测试,并让内部用户和外部众测用户参与验证运行一段时间保证稳定性。

  2. 发布审核

    内测通过后,邀请组内其他人参与Review,通过后再进行后续的灰度。

  3. 流量灰度+增量发布

    优先选择1%小流量,没问题逐步调整流量比例,灰度放量。在小流量过程发现了问题,我们及时回滚了配置,让旧版本配置生效。修复后再逐步放量新版本。

灰度发布应用

FeatureFlag 与 A/B 测试打通

具体场景可分为以下三个部分:

  1. A/B实验产生优胜版本后,可直接将实验固化为feature,实现A/B实验的快速全量,并可采用灰度发布更加稳健全量。
  2. 在FeatureFlag智能发布创建feature后,可直接由feature开启A/B实验,快捷实现实验的开启和后续的管理。
  3. A/B实验的参数可固化为feature,放在FeatureFlag智能发布统一管理,产品可全局查看feature版本与实验的关系。

那么A/B测试与FeatureFlag两者间可以相互转化,他们之间的关系是怎么样的以及使用场景应该如何抉择?

A/B测试场景应用

A/B测试是效果测试(一般用来验证某个想法是否符合预期),同一时间有多个版本功能对外提供服务,这些功能都是经过足够测试,达到了上线标准的服务,有差异但是没有新旧之分。它关注的是不同版本功能的实际效果,比如说转化率、留存等。其目的是为了验证产品的迭代方向是否正确。

Feature Flag强调的是发布策略,目标是确保新上线的系统稳定,关注的是新系统的BUG、性能隐患及稳定性,强调在发布过程中能够较早发现问题的存在

Feature Flag与A/B测试的抉择流程可以参考下图。

A/B测试场景流程

异常监控智能告警

FeatureFlag可以和APM应用性能监控打通,可实现从应用—>Feature—>Flag级别的监控 。当某个监听的技术指标出现异常时自动触发报警,快速发现线上异常问题。后续对服务端技术指标的支持。

异常监控应用

人群差异化发布

基于FeatureFlag中灵活的自定义目标受众条件,可以实现不同用户下发不同的配置参数,真正实现千人千面,灵活发布。

  • 可以根据不同人群特点展示功能,比如安卓用户推荐QQ登录,IOS用户推荐微信登录,提 升不 同人群的个性化体验。
  • 运营活动时,可针对不同地域、人群采用差异化的运营策略,实现细分人群的精细化运营。
  • 自定义目标受众参数,满足业务定制化的定向发布需求。

差异化发布应用

增强持续集成与持续部署能力

CI/CD使得开发者可以快速开发、迭代与发布新功能。持续部署符合企业软件实践,它是完善持续集成原则的自然演化。但持续集成与部署案例却非常罕见,其中原因可能是需要复杂的管理以及担心部署失败而影响系统的可用性。

目前在开发过程中,开发者会从develop分支checkout新的分支出去开发自己的新功能,在充分测试完成后再合并到主干分支,这样主干分支能够保证在任意时刻都是可以上线的状态。但是这种开发方式存在一些问题,比如分支分出去时间越长往往代码合并难度越大。一旦代码库中存在了分支,也就不再是真正的持续集成了。当然你可以给每个分支建立一个对应的CI,但它只能测试当前分支的正确性。如果在一个分支中修改了函数功能,但是在另一个分支还是按照原来的假设在使用,在合并的时候会引入bug,需要大量的时间来修复这些bug。

而基于Feature Flag的CI过程则如下图所示。开发完成的代码可以在任意时刻合到主干分支中,并通过Feature Flag开关控制未开发完成的功能对用户不可见;新的特性可以提前上线,产品或者运营等角色可通过开关控制何时与什么范围生效新的Feature;对线上问题的修复,可以通过控制发布范围,使用线上流量进行验证。

  • 进一步加快CI/CD进程,主干分支随时可以部署,提高迭代效率。
  • 功能上线与代码部署的分离,通过flag将新功能隐藏,一方面方便线上小流量测试,另一方面产品或者运营可以按需开启功能,不需要再问研发要排期,提高协作效率。

代码发布和部署分离与耦合的工作流对比

参考

本文由作者按照 CC BY 4.0 进行授权