Flipt:用 Git 管理开关定义,也要单独设计评估高可用
把 feature flag 定义放进 Git,能获得 diff、review、commit、branch 和 revert;它解决的是“配置如何变更、谁批准、怎样回到旧版本”。业务请求能否在 Flipt 进程故障、Git 远端失联或新实例冷启动时继续得到结果,则是另一套运行时问题。最危险的误判是看见 Git 有三份副本,就认为线上评估也天然高可用。
Flipt v2 将环境映射到 Git 原生存储,把 namespace、flag、segment、variant、rule 和 rollout 作为可版本化资源。应用可以通过 REST 或 gRPC 请求 Flipt 做 server-side evaluation,也可以使用 client-side SDK 同步规则并在本地评估。前者把每次评估的可用性绑定到 Flipt 服务,后者把规则同步、缓存陈旧与 SDK 兼容性带进应用。架构选择必须同时回答配置权威源、运行时状态、失败默认值和恢复证据。
部署前还要把版本和许可当成架构输入。Flipt v2 服务端采用 Fair Core License:组织可以自托管、修改并用于通常的内部商业系统,但不能用它向第三方提供竞争性的托管特性开关服务;各版本发布两年后转为 MIT。语言 SDK、OpenFeature Provider 与集成库保持 MIT。Free 版包含评估引擎、UI、多环境、Git 存储与同步、认证和 SSE 更新;SCM merge proposal、GPG commit signing、外部 Vault/云 Secret 集成、离线 license 等属于 Pro 边界。采购评审不能把“源码可见”和“OSI 开源许可”视为同一结论,也不能先按 Pro 文档落配置、上线时才发现 license 不具备。
v2 对象模型从环境落到实体评估
Environment 位于 namespace 之上,并通过配置引用某个 storage backend;可以让开发、预发、生产分别使用不同 Git 分支、目录或仓库。环境不是在每个请求里随便传入的字符串,而是部署和存储边界。把生产与测试指向同一可写分支,会让一次 UI 修改跨环境扩散。
Namespace 是资源组织层,也可以成为授权策略的 namespace scope,内部包含 flags 和全局可复用的 segments。它适合表达团队或领域边界,例如 checkout,而不是给每个开发者创建一个 namespace。创建 namespace 本身不会自动产生隔离:只有启用 authorization、加载 default-deny 策略并验证拒绝路径后,环境和 namespace 才真正成为权限边界。namespace key 进入评估请求,改名会破坏调用方,因此应当按 API 标识治理。
Flag 有 Boolean 和 Variant 两类。Boolean flag 通过按顺序求值的 rollouts 返回 true/false;第一个匹配的 rollout 获胜,没有命中时返回 default rollout。Variant flag 包含多个 variants,通过 rules 关联 segment 并按 distribution 选择结果。Variant 的 key 是代码契约,description 和 attachment 才是人类说明或小型 payload。
Segment 由 constraints 组成,match type 为 Match All 时每个 constraint 都要满足,Match Any 时至少一个满足。没有 constraint 的 segment 默认匹配所有请求,这在实验中方便,在生产中也可能把一个误配置扩大到全部实体。Rule 和 rollout 都有顺序,调整 rank 不是视觉排序,而是改变求值语义。
每次评估至少包含 flag key、namespace key、稳定 entity ID 和可选 context。distribution 需要稳定 entity ID 才能让同一实体保持相同 variant;用请求 ID、时间戳或每次重新生成的 UUID 会让用户换组,也会使实验归因失真。Context 只传规则所需字段,不把完整用户画像、访问令牌或订单对象交给评估层。
二进制与 Homebrew 适合单机学习和受控主机
Flipt v2 提供 Linux 与 macOS 的 x86-64、ARM64 二进制,当前稳定 release 为 v2.10.0。官方安装脚本会把程序安装到系统路径,便利但不利于审计脚本在执行前做什么;团队环境应从 release 下载固定版本,记录版本、edition 和 license 状态,验证 checksum 或签名,再放入受控工具仓。不要让 v2、chart 浮动版本或 latest 成为生产升级策略。个人 macOS 或 Linux 也可以使用 Homebrew:
brew install flipt-io/brew/flipt@2
flipt --version
flipt server --config ./config.yml安装脚本入口适合一次性实验:
curl -fsSL https://get.flipt.io/v2 | sh
flipt --version
flipt server --config ./config.yml企业代理会同时影响二进制下载、Git HTTPS、OIDC/JWKS 与遥测出口。先确认 shell 的 HTTPS_PROXY、NO_PROXY 和系统 CA;SSH Git 还需要出站 22 端口或企业规定的 SSH over HTTPS。不要用 insecure_skip_tls 或 insecure_ignore_host_key 作为长期修复,正确做法是挂载内部根证书与 known_hosts,并保留证书轮换 owner。
进程默认查找显式 --config、用户配置目录和 /etc/flipt/config/default.yml。生产服务应始终显式指定配置路径和工作目录,避免 systemd 用户变化后意外加载另一份文件。主机部署还要创建非登录服务账号、只读配置目录、可写状态目录、日志收集和文件权限;二进制存在不代表 Git 工作树、SSH 私钥和 CA 对该账号可读。
Docker 实验要同时持久化状态与配置
Docker Engine 需要支持 Flipt v2 镜像,主机需空闲 8080 HTTP 与 9000 gRPC 端口。官方镜像以非 root 用户运行,bind mount 必须允许容器用户写入。先建立只属于实验的目录:
mkdir -p flipt-lab/data# flipt-lab/config.yml
log:
level: INFO
encoding: json
server:
http_port: 8080
grpc_port: 9000
meta:
check_for_updates: false
telemetry_enabled: false
storage:
local:
name: Local
backend:
type: local
path: /var/opt/flipt
branch: main
environments:
default:
name: Default
storage: local
default: truedocker run -d \
--name flipt-lab \
-p 127.0.0.1:8080:8080 \
-p 127.0.0.1:9000:9000 \
-v "$PWD/flipt-lab/data:/var/opt/flipt" \
-v "$PWD/flipt-lab/config.yml:/etc/flipt/config/default.yml:ro" \
docker.flipt.io/flipt/flipt:v2.10.0
docker logs --tail=100 flipt-lab
curl --fail http://127.0.0.1:8080/metrics | head预期证据是 UI 可访问、日志没有配置解析或权限循环错误、/metrics 输出 Prometheus 文本,并且在 UI 创建 flag 后重启容器仍能看见资源。若日志显示 repository 不存在或写入失败,检查配置中的 path 是容器内路径 /var/opt/flipt,而不是主机目录;再检查 bind mount owner。不要把 backend 改成 memory 来掩盖持久化错误,memory 只适合可丢弃测试,重启后状态会消失。
清理时先导出或提交需要保留的定义,再执行:
docker rm -f flipt-lab
rm -rf ./flipt-lab第二条会永久删除本地 Git 数据,只能对明确的实验目录执行。共享主机应由目录 owner 审核绝对路径,不使用带变量展开的递归删除脚本。
Helm 是集群入口,不是自动获得高可用
Flipt v2 使用独立 chart flipt-v2,不要套用 v1 的 flipt chart values:
helm repo add flipt https://helm.flipt.io
helm repo update
helm show values flipt/flipt-v2 > flipt-values.reference.yaml
helm install feature-flags flipt/flipt-v2 \
--namespace feature-flags \
--create-namespace \
--values values.yaml
kubectl -n feature-flags get pods
helm -n feature-flags status feature-flagsvalues.yaml 应设置固定 chart/app 版本、镜像 digest、requests/limits、readiness/liveness、PodDisruptionBudget、反亲和、NetworkPolicy、Service、Ingress TLS、认证、metrics 和 storage。使用 local backend 时,每个副本拥有独立工作树会产生状态和写入冲突;共享 RWX volume 也不能自动提供正确的 Git 并发语义。多副本前先决定唯一写入口、远端 Git 同步策略、每副本只读快照与冲突处理,再用故障实验验证。
chart 默认能启动不等于生产就绪。Kubernetes 内通常用 Secret 注入 Git、OIDC、license 与 client token,ConfigMap 只放非敏感配置。环境变量和 file secret reference 可以避免把 PAT 或私钥直接提交到 values;HashiCorp Vault、AWS Secrets Manager、GCP Secret Manager 与 Azure Key Vault 的集成属于当前 Pro 能力,不能把示例中的 ${secret:vault:...} 当成 Free 版天然可用。内部 Git 或 OIDC 使用私有 CA 时,把 CA 加进容器系统 trust store;对 SSH Git 挂载只读 /etc/ssh/ssh_known_hosts。
升级前执行 helm diff 或等价审查、备份 Git 权威源和本地状态、在隔离 namespace 验证目标 chart。回滚 chart 只能恢复工作负载清单,不能撤销已经推送到 Git 的规则提交,也不能自动恢复被新版本改写的本地状态。
v2 Git 原生存储的权威链与冲突语义
v2 的 local backend 在本地文件系统中服务 Git 仓库,定期从磁盘重建状态;memory backend 适合开发测试,也可以配置 remote 后把远端 Git 同步到内存快照。每个 storage 有唯一 ID,environment 通过 ID 引用它。多个环境可以共享 backend,但必须用不同目录或 branch 明确隔离,否则“环境不同”只是标签不同。
下面把生产环境绑定到远端 Git 的 production 分支,并从内存提供当前快照:
storage:
production:
name: Production
remote: https://git.example.invalid/platform/feature-flags.git
branch: production
poll_interval: 30s
fetch_policy: strict
credentials: git-app
backend:
type: memory
credentials:
git-app:
type: access_token
access_token: "${secret:file:git-token}"
environments:
production:
name: Production
storage: production
default: true示例域名不可直接用于运行;真实环境把 token 放入 secret provider,并将 Git 凭据限制为目标仓库和必要分支。优先使用短期 GitHub App 或工作负载身份,其次才是可轮换的细粒度 PAT。SSH 方案要固定 host key,私钥只读挂载;insecure_ignore_host_key 会让中间人替换规则仓库。
Flipt 从远端按 poll_interval 同步。直接写入路径会在本地形成 Git 变更并与远端协调;如果远端文件自上次基线后已改变,冲突必须作为变更失败处理,要求拉取、审查并重新合并,不能无限重试同一个写请求。Free 版的 Git-backed storage/sync 不等于具备 SCM proposal 工作流:从 Flipt UI 自动向 GitHub、GitLab、Bitbucket、Azure DevOps 或 Gitea 创建 PR/MR 是 Pro 能力。Free 部署若要求所有生产变更经过 PR,应让 CI/SCM 成为唯一写入口并限制 Flipt 管理写权限,而不是假设 UI 写入天然经过审批。
Git 仓库初始化时,features.yaml 或 features.yml 位于环境目录。已有定义可以这样纳管:
mkdir -p flags/production
cp ./reviewed-features.yaml flags/production/features.yaml
git -C flags init -b main
git -C flags add .
git -C flags commit -m "纳管生产开关定义"再让 local backend 指向 flags 并启动 Flipt。验收不能止于 git log 有 commit,还要在 UI、API 或 Playground 中看见同样的 namespace、flag 和 segment,并执行代表性评估。YAML 语法正确但对象关系错误时,Git 仍会忠实保存一个不可用版本。
OCI 要按 v1 能力看待,不能套进 v2 配置
Flipt v1 的 declarative storage 支持把 flag 定义打成自定义 OCI bundle,推送到 OCI registry,由 Flipt 周期性拉取。它适合已有制品签名、镜像晋级、不可变 digest 与多区域 registry 的团队。关键配置包括 storage.type=oci、repository、poll interval、bundle directory、manifest version 和 registry authentication;私有 ECR 等场景还可能使用工作负载身份。
Flipt v2 的主线存储模型是 Git 原生 local/memory backend 加 remote Git 同步。v1 的 storage.oci.* 不是 v2 storage.<id> 的等价字段。仍在 v1 使用 OCI 的系统可以继续把 bundle digest 作为发布证据,但迁移到 v2 时要先把 bundle 中的 namespace、flags、segments、variants 与规则导出为 v2 支持的 features.yaml,在隔离环境比较评估结果,再切换应用。直接复制旧 YAML 配置会导致启动失败或回到默认存储。
OCI 也不天然带来运行时高可用。registry 可用只保证能获得制品,Flipt 进程、已拉取 bundle、本地缓存、评估 API 和应用 fallback 仍需独立设计。使用 tag 回滚还可能受可变 tag 与缓存影响;生产晋级应记录不可变 digest、签名、manifest 版本和目标环境,回滚后验证实际加载 digest 与评估结果。
从 namespace、flag、segment 到 variant 建立最小模型
在默认 environment 与 default namespace 中创建一个 Variant flag checkout-layout,增加 classic 与 compact 两个 variants。创建 segment beta-tenant,Match All,constraint 为 tenant 等于 tenant-lab。再为 flag 创建 rule:命中 segment 时两个 variants 各占一半。
Playground 使用固定 entityId=user-001 和 context {"tenant":"tenant-lab"} 重复评估,应持续返回相同 variant;改成 tenant-other 应不命中该 rule。再创建 Boolean flag payment-v2,默认 false,第一条 rollout 只允许内部 segment,第二条 threshold 从 0% 调到 10%。由于 rollouts 按 rank 首个匹配获胜,把广泛 threshold 放在内部规则之前可能改变预期,调整顺序必须进入 diff 与评审。
每个对象都应有清晰 owner:namespace 由领域团队拥有,segment 由使用它的业务与数据 owner 联合维护,flag owner 负责 fallback 和删除,variant payload 由消费代码 owner 维护。共享 segment 修改前列出所有引用;删除 variant 前搜索 SDK 中的字符串与反序列化分支。
Server-side evaluation 把网络放在请求路径
Server-side 模式由应用每次通过 REST 或 gRPC 把 entityId、namespace、flag 和 context 发送给 Flipt。REST 容易调试,gRPC 在连接复用、类型和吞吐上更合适;两者语义等价,但都依赖 Flipt 的实时可用性。
启用静态 client token 后,可以直接验证 Variant 评估:
export FLIPT_URL=http://127.0.0.1:8080
export FLIPT_CLIENT_TOKEN='<client-token>'
curl --fail-with-body -X POST "$FLIPT_URL/evaluate/v1/variant" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H "Authorization: Bearer $FLIPT_CLIENT_TOKEN" \
-d '{
"flagKey": "checkout-layout",
"entityId": "user-001",
"namespaceKey": "default",
"context": {"tenant": "tenant-lab"}
}'预期响应包含匹配结果和 classic 或 compact variant。换用同一 entity ID 重复请求,结果应稳定;换一组 ID 后分布才会变化。接口超时、401、flag 不存在和规则无匹配必须映射成不同指标,应用层再按业务风险选择 fallback,不能把所有错误吞成 false 后失去故障证据。
生产客户端设置短连接超时、有界重试和熔断。只对网络瞬时错误重试,且重试总时长必须小于业务预算;无权限或请求非法不应重试。高吞吐路径优先连接本地或同区域 Flipt,做容量测试时观察 evaluation latency、错误率、并发连接、CPU、内存和规则规模。增加 Flipt 副本之前先证明各副本加载同一 commit,否则负载均衡会让同一请求在不同规则版本间跳动。
Client-side evaluation 把规则和可用性带入进程
Client-side SDK 会获取本地规则副本并在应用内评估,降低延迟和 Flipt QPS。v2 支持 streaming mode,SDK 可订阅服务端变更;网络中断后能否继续、缓存是否持久、初始化失败返回什么、stream 恢复是否全量对齐,都取决于所用语言 SDK 与固定版本,必须用真实客户端验证。
应用接入需要统一封装,而不是在业务代码散落 SDK 调用:
FlagDecision evaluate(flagKey, entityId, context, fallback)
FlagDecision:
value / variant
reason
sourceCommit
cacheAge
usedFallback封装层负责:初始化屏障、默认值、context 白名单、超时、日志脱敏、metrics、优雅关闭和测试替身。业务层只消费强类型结果。flag 不存在、规则解析失败、尚未同步和缓存过期是不同 reason;如果 SDK 不提供全部细节,也要至少记录 ready、最近同步成功与 fallback 计数。
client-side 模式的代价是每个应用实例持有规则,升级 SDK 可能改变求值实现;大 segment 或大量规则会增加下载、解析、内存和刷新成本。多语言系统用同一组固定 entity IDs 建立契约样本,升级前比较每种 SDK 的 Boolean 与 Variant 结果。不要只测“能返回值”,还要测跨语言是否得到同一值。
认证与授权必须分别闭环
生产实例先启用 authentication.required: true,再启用 authorization.required: true 并装载 default-deny 策略。前者证明调用者是谁,后者才决定这个身份能否对某个 environment、namespace 执行 read、create、update 或 delete。只开 authentication 会把“已登录”误当成“最小权限”;只写 Rego 却没启用 authorization,则策略根本没有进入强制路径。
人类 UI 使用 OIDC 等 session-compatible 方法;静态 token 不是会话认证,适合应用和自动化。应用也可使用 IdP 签发的 JWT,或在 Kubernetes 中用 service account token 交换 Flipt client token。静态 client token 通过 Authorization: Bearer <client-token> 发送,外部 JWT 使用 Authorization: JWT <jwt>,两种 header 语义不能混用。JWT 必须校验 issuer、audience、允许算法、exp/nbf/iat 和时钟偏差,不能只验证签名;Kubernetes 交换模式仍要限制 service account、namespace、audience 和 token exchange 网络路径。
评估接口与管理接口也要分开决策。authentication.exclude.evaluation 和 authentication.exclude.ofrep 可以把对应评估入口排除在认证外,但这会把是否可调用交给网络边界,不能为了少发一个 header 就在公网入口开启。若应用使用 client-side SDK,同步规则的 token 可读取足够完成本地评估的数据,应按环境单独签发、轮换和撤销,不能与管理 API 身份共用。
静态 token 用 CSPRNG 生成,例如 openssl rand -hex 32,通过环境变量或 file secret reference 注入。人类身份与应用身份不能共用一个长期 token。Flipt 的会话存储默认 memory,重启会丢失会话,多副本也不能共享;需要稳定 UI 会话时使用 Redis 并为其设置 TLS、认证、容量和备份边界。CSRF key 必须是足够强的独立 secret,轮换会使现有会话失效,应在变更窗口执行。
v2 授权输入支持 global、environment 与 namespace scope。策略应 default deny,显式允许生产只读、非生产写和发布机器人生产写;UI 的 viewable_environments、viewable_namespaces 只是可选过滤查询,未实现时资源可能仍显示,但后端授权必须继续拒绝。验收至少用三个身份做反证:只读者修改生产得到拒绝,开发发布者不能跨 environment,生产机器人不能管理认证与全局配置。Git PAT 只授予目标仓库必要权限;GPG commit signing 属于 Pro,签名只能证明某个 key 参与提交,不能替代分支保护和身份审计。审计要关联 UI/API 身份、Git commit、PR、环境、实际加载 commit 和评估变化,单独的 Git author 字段不足以证明操作人。
正向实验:从 Git 提交到稳定评估
在隔离仓库提交一个 features.yaml,通过 PR 将 payment-v2 从 0% 调到 50%,合并后等待 Flipt 拉取。记录 Git commit SHA、Flipt 日志中的同步成功、UI 中环境与资源、/metrics 状态,以及固定 100 个 entity IDs 的评估结果。
预期证据:
Flipt 加载的环境、branch 和 commit 与合并目标一致;同一 entity ID 连续请求、跨两个 Flipt 副本和进程重启后结果一致;0% 与 100% 是确定边界,50% 的样本数量接近一半但不会每次重新抽取;
不满足 segment constraint 的实体得到默认结果;server-side 与目标语言 client-side SDK 对契约样本得到相同结果;评估指标增长,日志没有输出 client token 或完整敏感 context。
反向对照把 entity ID 改为每请求随机 UUID,结果会在 variants 间变化。再把一个广泛匹配 rule 排到精确 rule 之前,观察第一个匹配规则遮蔽后者。修复后恢复稳定 entity ID 和正确 rank,并把这两种错误写入自动化契约测试。
反向实验:分别打断控制面与数据面
Git 远端失联但 Flipt 仍运行
先让 Flipt 成功同步 commit A,再阻断测试实例到 Git 远端的网络,向远端提交 commit B。预期 Flipt 继续按 A 评估,同时 fetch 错误和规则陈旧时间增长;它不能谎称已加载 B。恢复网络后,预期加载推进到 B,契约样本按新规则变化。
这个结果证明 Git 故障影响配置新鲜度,不必立即影响运行中评估。新启动实例是否能使用已有本地仓库或内存为空,要按 backend 分开测试:local backend 有完整工作树时可以读取旧状态;memory backend 若启动时无法 clone/fetch,可能没有可用规则。
Flipt 服务失联
暂停 Flipt 测试容器,继续向 server-side 应用发请求。预期在有界超时后触发熔断和业务 fallback,不能等待到上游网关超时。client-side 应用若已同步规则,应继续返回缓存结果并暴露 cache age;清空其缓存后冷启动,预期进入明确 fallback 或拒绝就绪,不能伪造正常同步。
恢复 Flipt 后,server-side 熔断进入半开并成功恢复;client-side stream 重新连接并完成版本对齐。验收记录至少包含故障起止相对时序、错误类型、fallback 数、缓存 commit、恢复 commit 和业务结果。
错误配置与凭据撤销
向测试分支提交引用不存在 segment 或非法分布的配置,验证 CI schema/语义检查阻止合并;绕过 CI 的隔离实验应让 Flipt 拒绝加载坏版本并保留 last-known-good,而不是清空全部规则。然后撤销应用 token,server-side 应得到明确认证失败,client-side 后续同步失败但已缓存规则的行为要被观测。
清理顺序是恢复网络和服务、确认 commit 与规则同步、删除测试 flag/segment、合并清理提交、撤销临时 token、删除测试 secret,最后卸载 Helm release 或容器。Git 仓库保留实验 commit 可供审计;含敏感值的日志和临时工作树按数据保留策略销毁。
版本回滚必须同时验证 commit 与运行时状态
Git 原生回滚优先用 git revert <bad-commit> 生成新提交,保留错误版本与回滚因果;不要强推分支删除历史。合并 revert 后等待 Flipt 拉取,并验证实际加载 commit、代表性 evaluation、metrics 和应用 fallback 退出。仅看到 PR 已合并不能证明运行时已经回滚。
如果 UI/API 同时可写远端仓库,回滚期间冻结写入或规定单一变更入口,避免 Flipt 在旧基线上产生新 commit 与远端冲突。远端变化后写入同一 flag 文件,Flipt 可能拒绝 push;自动化应把冲突交给人工合并,而不是覆盖远端。
应用版本与规则版本也可能存在兼容窗口。新代码认识 compact variant,旧代码只认识 classic;先回滚应用再回滚 flag,旧代码可能收到未知 variant。安全发布顺序是先部署能兼容新旧定义的代码,再改变规则;回滚先把规则收敛到双方都认识的值,再回滚代码。将允许的 variants 作为契约测试,可以在 PR 阶段发现不兼容。
备份恢复要覆盖权威 Git、工作状态和密钥
远端 Git 是首要权威源时,备份包括完整 refs、对象、默认与环境分支、保护规则、PR 审计和 LFS/外部附件。只下载工作树会漏掉历史与其他分支。定期做 mirror clone 到独立故障域,并验证 git fsck 和从镜像恢复新仓库。
local backend 还要备份 Git 仓库本身、Flipt 配置、environment 到 storage 映射、部署版本和本地 state directory。memory backend 不需要备份内存,但必须证明新实例能从远端重建。认证 secret、OIDC 配置、CSRF key、Git App 私钥、commit signing key 和内部 CA 由密码库或 PKI 独立恢复,不能混入公开 Git 仓库。
如果启用 ClickHouse 分析或外部 Prometheus,评估历史的备份与保留是单独的数据治理问题。丢失 analytics 不应改变 flag 当前结果,但会影响审计和实验解释。Flipt 的 Prometheus metrics 默认在 /metrics;生产应限制抓取网络,防止 namespace/flag 标签成为不受控信息出口。
恢复演练使用一套隔离 Flipt:恢复 Git mirror、配置和 secret 引用;禁用 webhook、SCM 写入和外部通知;启动后比较 branch、commit、namespace、flag、segment 数量;运行固定评估样本;再模拟向新远端提交和回滚。恢复时间与可接受配置丢失量由 owner 签字,不能用“Git 本来就有备份”代替演练。
控制面与数据面要有独立 SLO 和告警
Flipt 同时承载 UI/API 变更、Git 同步和 server-side evaluation 时,一次 CPU、连接池或认证故障可能同时影响控制面与数据面。生产可以将写入口与评估入口通过网络、限流和副本职责隔离,或用 client-side evaluation 把请求路径移出中心服务。无论怎样拆,至少监控:
HTTP/gRPC evaluation QPS、p50/p95/p99、错误码、超时与熔断;Git fetch/push 成功、远端延迟、最后成功 commit、冲突数与规则陈旧时间;client-side stream 连接、最近同步、缓存 commit、fallback 和 cache age;
进程 CPU、内存、goroutine、文件描述符、GC、重启和 readiness;flag/segment/namespace 数量、单文件大小、解析耗时与每次重建时长;认证失败、token 使用、管理写入、签名失败和授权拒绝;
analytics buffer、外部 sink 错误、标签基数、存储保留与成本。
控制面 SLO 可以定义“合并后的合法规则在目标环境可见的传播延迟”;数据面 SLO 定义“评估成功率和延迟”;client-side 还要定义“规则最大可接受陈旧时间”。三者不能用一个 /health 绿灯替代。
团队治理把 Git 优势变成可执行规则
每个 flag 创建时记录 namespace、业务 owner、技术 owner、类型、默认值、entity ID 规范、context 字段白名单、预期生命周期、放量阈值、观测指标、fallback、代码删除工单和紧急联系人。没有 owner 与删除条件的 flag 不允许进入生产分支。
生产规则仓库启用 branch protection、CODEOWNERS、必需 CI、签名验证和禁止 force push。CI 至少检查 YAML 解析、schema、对象引用、distribution 合计、重复 key、未知 variant、空 segment、环境目录、敏感值和契约样本。PR 展示语义 diff,例如“默认 false 改 true、受影响 segment、rollout 从 10% 到 50%”,不让审批者只读原始 YAML。
权限分成四类:平台管理员维护 Flipt 部署与认证;领域 owner 审批 namespace 资源;发布自动化合并或推进环境;应用身份只读取或评估。Git 写权限、Flipt UI 写权限和生产部署权限不能默认落在同一长期个人账号。离职和团队调整时同时回收 SCM、Flipt、Kubernetes、OIDC group、client token 与签名密钥。
成本不仅是 Flipt 计算资源。server-side 模式有每请求网络和中心容量成本;client-side 模式有每实例内存、流量、SDK 升级和一致性测试成本;Git 有托管、CI、审查和冲突处理成本;analytics 有标签基数、ClickHouse/Prometheus 存储与保留成本。每季度由平台 owner 汇总实例数、评估量、规则规模、陈旧 flag、存储和人力,再决定扩容、引入本地评估或拆分 namespace。
排障表先回答“当前结果来自哪一版规则”
| 现象 | 证据入口 | 高概率原因 | 修复与再验证 |
|---|---|---|---|
| Git 已合并但 UI 没变化 | 目标 branch、Flipt 最后 commit、fetch 日志 | branch/目录映射错、凭据过期、代理或 CA 失败 | 修复映射/凭据,确认 commit 推进并跑契约样本 |
| UI 修改保存失败 | push 错误、远端 HEAD、本地 last commit | 同一文件被远端修改导致冲突 | 拉取并人工合并,不覆盖远端;重新提交后评估 |
| 两个副本结果不同 | 每副本 commit、backend 路径、rule rank | 独立本地仓库未同步或加载时间不同 | 收敛权威源,等待同 commit 后再纳入负载均衡 |
| 同一用户 variant 跳变 | entity ID、context、distribution | 使用随机/可变 ID,或规则顺序改变 | 固定实体 ID,回滚规则并重跑稳定性样本 |
| server-side 请求超时 | evaluation latency、连接与熔断指标 | Flipt 不可达、负载过高、重试放大 | 有界 fallback,恢复或扩容,验证业务预算 |
| client-side 一直旧规则 | cache commit、stream/fetch 错误、cache age | 连接断开、token 失效、SDK 未全量对齐 | 修复认证网络,确认 commit 更新且 stale 告警恢复 |
| 重启后全部资源消失 | backend type、volume、工作目录 | 使用 memory 或未挂载持久卷 | 从 Git 恢复并修正 storage,验证再次重启 |
| Helm rollback 后规则仍是新版 | Git HEAD、Flipt loaded commit | chart 回滚不改变 Git | revert 规则 commit,等待加载并验证评估 |
最后的架构判断很朴素:Git 提供配置历史和协作一致性,Flipt 服务或 client-side SDK 提供运行时评估。两者可以互相增强,却不能互相替代。只有当团队能在日志和指标中指出“当前请求按哪个 environment、namespace、commit、flag、entity ID 与 fallback 得出结果”,Git 原生才真正从漂亮的存储口号变成可恢复的渐进交付系统。
