4. Feature Flag 架构设计:Flag管理服务、SDK集成、本地缓存与远程同步、高可用设计

Feature Flag 架构是灰度发布系统的核心骨架。一个生产级的 Feature Flag 系统需要同时解决 集中管理、运行时决策、性能开销 和 故障容错 四个关键问题。本章从架构分层出发,逐一拆解 Flag 管理服务、SDK 集成、本地缓存与远程同步机制,以及高可用设计策略。

4.1 整体架构分层

Feature Flag 系统通常采用 控制面(Control Plane) 与 数据面(Data Plane) 分离的架构。控制面负责 Flag 的创建、配置、发布和审计;数据面负责在应用运行时高效获取 Flag 状态并做出决策。

架构核心原则: 控制面允许最终一致性(秒级延迟),数据面必须追求高可用与低延迟(毫秒级响应)。
Feature Flag 整体架构分层 控制面(Control Plane) Flag 管理服务 CRUD / 版本管理 用户与权限 RBAC / 审批流 审计与事件 操作日志 / 事件流 数据面(Data Plane) SDK 客户端 本地缓存 / 决策引擎 远程同步代理 WebSocket / Polling 高可用网关 负载均衡 / 熔断 控制面与数据面通过 API 网关解耦,数据面 SDK 不直接依赖控制面数据库

4.2 Flag 管理服务

Flag 管理服务是控制面的核心组件,负责所有 Feature Flag 的 生命周期管理。它提供统一的 RESTful API 和 Web UI,供开发者和运维人员操作。

4.2.1 核心功能模块

功能模块 职责描述 关键技术选型
Flag CRUD 创建、更新、删除、查询 Flag 定义 PostgreSQL / MySQL + 乐观锁
版本管理 每次变更生成新版本,支持回滚 Event Sourcing + 快照
目标规则引擎 基于用户属性、百分比、环境等条件匹配 表达式引擎(如 Aviator / MVEL)
审批与发布 变更需经过审批流,支持灰度发布策略 工作流引擎(如 Temporal / Camunda)
审计日志 记录谁在什么时间做了什么变更 Kafka + Elasticsearch

4.2.2 数据模型设计要点

Flag 管理服务的数据模型需要兼顾 查询效率 和 历史追溯。推荐采用 主表 + 变更日志表 的双表设计:

  • flag_definitions 表: 存储当前生效的 Flag 配置,包含 key、name、variations、rules、status 等字段。
  • flag_changelog 表: 存储每次变更的完整快照,用于审计和回滚。
  • flag_targeting_rules 表: 存储条件规则,支持 AND/OR 嵌套逻辑。
-- 简化版 Flag 定义表结构
CREATE TABLE flag_definitions (
    id          BIGSERIAL PRIMARY KEY,
    project_id  BIGINT NOT NULL,
    key         VARCHAR(128) NOT NULL UNIQUE,
    name        VARCHAR(256),
    description TEXT,
    variations  JSONB NOT NULL,          -- [{"id":"on","value":true}, {"id":"off","value":false}]
    rules       JSONB,                   -- 目标规则配置
    status      VARCHAR(20) DEFAULT 'inactive',  -- inactive | active | archived
    version     INT NOT NULL DEFAULT 1,
    created_by  VARCHAR(64),
    updated_at  TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(project_id, key)
);

-- 变更日志表
CREATE TABLE flag_changelog (
    id          BIGSERIAL PRIMARY KEY,
    flag_id     BIGINT NOT NULL REFERENCES flag_definitions(id),
    version     INT NOT NULL,
    snapshot    JSONB NOT NULL,          -- 变更时的完整 Flag 快照
    operator    VARCHAR(64),
    operation   VARCHAR(20),             -- create | update | delete | rollback
    created_at  TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

4.3 SDK 集成与本地缓存

SDK 是数据面的核心组件,嵌入到业务应用中。它的职责是:从远程同步 Flag 配置,在本地缓存中决策,并返回 Flag 的最终值。

4.3.1 SDK 核心接口

接口方法 说明 典型实现
getFlag(key, userContext) 根据用户上下文获取 Flag 值 先查本地缓存,命中直接返回
getFlagDetail(key) 获取 Flag 的完整配置(含规则) 用于调试和展示
getAllFlags() 获取当前项目所有 Flag 的快照 用于批量评估或导出
onFlagChanged(callback) 注册 Flag 变更回调 WebSocket 推送时触发

4.3.2 本地缓存策略

本地缓存是 SDK 性能的关键。推荐采用 两级缓存 架构:

  • 一级缓存(L1): 使用 ConcurrentHashMap 或 CopyOnWriteArrayMap,存储最近访问的 Flag 值。TTL 设置为 5~30 秒。
  • 二级缓存(L2): 使用本地文件或嵌入式数据库(如 RocksDB),存储全量 Flag 配置。用于 SDK 重启后快速恢复,避免冷启动时大量请求穿透到远程服务。
最佳实践: 本地缓存不要设置过长的 TTL。Feature Flag 的变更通常需要秒级生效,建议 L1 缓存 TTL 不超过 30 秒,并配合远程推送机制实现即时更新。

4.4 远程同步机制

远程同步负责将控制面的 Flag 变更实时或准实时地推送到所有 SDK 实例。常见的同步方式有三种:

同步方式 延迟 服务端压力 适用场景
长轮询(Long Polling) 秒级(通常 1~5s) 中等 内网环境、连接数可控
WebSocket 推送 毫秒级(实时) 较低(事件驱动) 公网环境、需要即时生效
gRPC Stream 毫秒级 低(双向流) 微服务架构、高性能要求

生产环境推荐 WebSocket + 定期轮询 的双通道策略:WebSocket 负责实时推送,轮询作为兜底机制,防止 WebSocket 连接意外断开导致配置滞后。

远程同步与本地缓存交互流程 Flag 管理服务 控制面 同步服务 WebSocket / Polling SDK 客户端 数据面 推送变更 实时推送 本地缓存 L1 缓存 内存 Map L2 缓存 本地文件 业务应用 调用 SDK 获取 Flag 同步流程:控制面变更 → 同步服务推送 → SDK 更新本地缓存 业务应用从本地缓存读取 Flag,不直接请求远程服务

4.5 高可用设计

Feature Flag 系统的高可用设计需要覆盖 控制面 和 数据面 两个层面。数据面的高可用优先级更高,因为 Flag 决策直接影响线上业务。

4.5.1 数据面高可用策略

  • 本地缓存兜底: 当远程同步服务不可用时,SDK 继续使用本地缓存的 Flag 配置。即使缓存过期,也返回最后一次成功同步的值,而不是抛出异常。
  • 默认值策略: 每个 Flag 在 SDK 中配置一个 静态默认值。当本地缓存为空且远程不可达时,返回默认值(通常为关闭状态)。
  • 熔断与降级: SDK 对远程同步请求实施熔断机制。连续失败超过阈值(如 3 次)后,暂停重试 30 秒,避免雪崩。
  • 多副本部署: 同步服务至少部署 2 个副本,通过负载均衡分发 SDK 请求。

4.5.2 控制面高可用策略

组件 高可用措施 故障影响
Flag 管理 API 无状态 + 水平扩展 + 数据库主从 控制面不可用,数据面不受影响
数据库 主从复制 + 自动故障转移(如 Patroni) 写入中断,读取仍可用
消息队列 Kafka 集群 + 副本机制 变更推送延迟,不丢失
缓存(Redis) 哨兵模式或 Redis Cluster 同步服务降级为轮询模式

4.5.3 故障场景与应对

关键故障场景: 假设同步服务完全宕机,所有 SDK 实例同时丢失远程连接。此时 SDK 应继续使用本地缓存,并定期尝试重连。业务应用不会感知到任何异常,Flag 状态停留在最后一次同步的值。这是 Feature Flag 系统最重要的 韧性设计。

下表总结了常见故障场景及系统行为:

故障场景 系统行为 对业务的影响
同步服务宕机 SDK 使用本地缓存,定期重试 无影响,Flag 状态冻结
数据库主库故障 自动切换到从库,写入暂不可用 控制面无法变更 Flag,数据面正常
网络分区 SDK 本地缓存 + 默认值兜底 无影响,分区恢复后自动同步
SDK 内存溢出 L2 缓存(本地文件)恢复数据 重启后快速恢复,冷启动延迟降低

4.6 架构设计总结

一个生产级的 Feature Flag 架构需要做到:

  • 控制面与数据面分离: 控制面负责管理,数据面负责决策,两者通过同步服务解耦。
  • 本地缓存优先: SDK 始终优先读取本地缓存,远程同步仅用于更新缓存。
  • 多通道同步: WebSocket 实时推送 + 轮询兜底,确保配置及时生效。
  • 韧性设计: 任何远程组件故障都不应导致业务应用崩溃,本地缓存和默认值是最后防线。
架构设计黄金法则: Feature Flag 系统的高可用不是让所有组件都不故障,而是确保在部分组件故障时,业务应用仍然可以正常运行并做出正确的 Flag 决策。