feature flag / 灰度发布:decide 出一个 variant
「先为 10% 用户开启新版结算」「内测账号直接开启,美区暂不开启」——feature flag 的求值,同样是这个函数:who(用户 + 属性)决定看到哪个 variant。与 HTTP、会员价与优惠券 两个实例一样,它将 policy 略作推广:输出不是 permit/deny,而是一个
variant(ON/OFF,或 A/B/C);而 targeting 规则从上到下、第一条命中即生效——这正是 first-applicable。
注 · flag 的求值顺序(LaunchDarkly 等均采用此模型):先看 flag 总开关,关闭就直接 OFF(kill switch);再看个体定向(allowlist,QA / 内部账号直接开);然后 targeting 规则从上到下,第一条命中就用它的 variant;都没命中则进百分比灰度(按 hash 分桶,命中就 ON);最后落到 default variant。每一步都对应 policy 里的一个概念。
1 · flag 求值:targeting 规则与个体定向
顺序即优先级。Ben(US · pro)身上,规则「美区 → OFF」排在「Pro → ON」前面,第一条命中即胜出;停用前者,后者接管。Cody(US · 内测)则因「内测 → ON」位于最前,即便在美区也是 ON。调换两条规则的顺序,结论可能反转——这就是 first-applicable,与防火墙规则链同一机制。
2 · 百分比灰度的确定性分桶
未被规则命中的用户进入百分比灰度。关键在于不能每次随机取值,否则同一用户时而看到新版、时而看到旧版。做法是将 hash(flagKey + ":" + userId) 映射到一个固定的桶 0–99,桶号小于放量百分比即开启。
建议 · 这样分桶在工程上可靠有三个理由。稳定(sticky):同一 userId 的桶号始终不变,用户体验一致,不会闪烁。单调(monotonic):放量从 30% 提到 50%,只会新增用户进入,已开启的绝不会被关闭,放量始终安全、可回滚。每个 flag 独立:hash 中包含 flagKey,因此一个用户在
flag A 进入了灰度,在 flag B 未必如此,避免「同一批人覆盖所有实验」。这实际上为 policy 增加了一种特殊的 who 分组:伪随机,但确定、可复现。
3 · feature flag 概念映回 policy 概念
| flag 里的说法 | policy 里的概念 |
|---|---|
| targeting 规则的条件 | 规则条件 when(req)(看 who 的属性 = ABAC) |
| 规则从上到下、第一条命中 | first-applicable「顺序即优先级」 |
| 个体定向(allowlist) | 显式 allow 覆盖(像 RBAC 的 UserAllow) |
| 百分比灰度(hash 分桶) | 确定性的 who 分组:伪随机但稳定可复现 |
| default / fallthrough variant | 默认决策(没规则命中时的最终取值) |
| flag 总开关(kill switch) | 全局 disable / 一次关闭 |
| variant(ON/OFF 或 A/B/C 多分支) | decision 是枚举值,不是布尔(像定价是个价) |
4 · 参考文献
- LaunchDarkly. Target with flags. targeting 规则、个体定向与默认 variant 的工业实现。launchdarkly.com
- LaunchDarkly. Percentage rollouts. 按 hash 分桶的百分比灰度,本页第 2 节的工业对照。launchdarkly.com
- Unleash. Activation strategies. 开源 feature flag 的策略模型(Gradual rollout / Standard / Custom strategies)。docs.getunleash.io