GO Feature Flag 1.57.2 配置参数详解
系统梳理 GO Feature Flag relay-proxy 1.57.2 的三类配置来源(命令行、配置文件、环境变量)与优先级,逐项实测服务端、retriever、鉴权、导出、flags 文件语义并给出生产模板。
GO Feature Flag 1.57.2 配置参数详解
目标:讲清 GO Feature Flag relay-proxy 1.57.2 的配置从哪来、谁覆盖谁、每个参数改了会发生什么,并用可复现命令验证配置生效。全部命令与回显在 Ubuntu 22.04.5 LTS(x86_64)+ relay-proxy 1.57.2 环境实测,版本查询日期 2026-10-28。
一、环境信息
本节给出复现实测所需的软件与路径清单。阅读本文不需要重新安装,只要机器上有一个可执行的 relay-proxy 与一份可写的配置目录即可。
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- 服务版本:GO Feature Flag relay-proxy 1.57.2(构建信息
goversion="go1.26.10"、tags="fips140v1.0") - 二进制:
/usr/local/bin/go-feature-flag-relay-proxy - 主配置:
/etc/go-feature-flag/goff.yaml - flags 文件:
/etc/go-feature-flag/flags.yaml - 运行用户:
goff - 监听端口:1031
- 服务单元:
go-feature-flag.service - 配置默认搜索目录:
./、/goff/、/etc/opt/goff/,文件名固定为goff-proxy.yaml
安装步骤见 《GO Feature Flag 1.57.2 Ubuntu 22.04 安装指南》;本文只讨论"装好之后怎么配"。
二、前置条件
- relay-proxy 已安装且能执行
--help; - 具备
/etc/go-feature-flag/的写权限与systemctl操作权限; - 有一个空闲端口用于对照实验(本文用 1032、1033、1035 做覆盖实验);
curl可用。
/usr/local/bin/go-feature-flag-relay-proxy --help
实测回显:
Usage of config:
--config string Location of your config file
这条回显说明了本文的一个关键事实:relay-proxy 的命令行参数只有 --config 一个,它只决定"读哪个配置文件",不参与具体参数的赋值。因此"命令行 flag > 环境变量 > 配置文件"这种常见优先级在 relay-proxy 上并不成立,真实优先级见第三章。
三、配置来源与优先级
3.1 命令行参数
--config 是唯一的启动参数,取值是配置文件路径(相对或绝对均可)。示例:
/usr/local/bin/go-feature-flag-relay-proxy --config /etc/go-feature-flag/goff.yaml
传一个不存在的路径时,程序不会立即报"文件不存在",而是回退到默认搜索逻辑,并在日志里明确写出尝试过的路径:
/usr/local/bin/go-feature-flag-relay-proxy --config /etc/go-feature-flag/not-exist.yaml
实测回显(节选):
{"level":"error","caller":"config/config_loader.go:239","msg":"not using any configuration file","error":"impossible to find config file /etc/go-feature-flag/not-exist.yaml"}
{"level":"fatal","caller":"relayproxy/main.go:76","msg":"configuration error","error":"no retriever available in the configuration"}
含义:配置文件没读到 → 没有 retriever → 直接致命退出。这类故障在 systemd 场景下表现为服务反复重启,排查入口就是 journalctl -u go-feature-flag。
3.2 配置文件与默认搜索路径
不传 --config 时,程序依次在 ./、/goff/、/etc/opt/goff/ 目录下查找名为 goff-proxy.yaml 的文件。实测把配置复制到 /goff/goff-proxy.yaml 后不带参数启动:
mkdir -p /goff
cp /etc/go-feature-flag/goff.yaml /goff/goff-proxy.yaml
SERVER_PORT=1033 timeout 3 /usr/local/bin/go-feature-flag-relay-proxy
实测回显(节选):
{"level":"info","caller":"api/server_lifecycle.go:119","msg":"Starting go-feature-flag relay proxy ...","address":"0.0.0.0:1033","version":"1.57.2"}
而把同样内容命名为 /goff/goff.yaml(其他文件名)时,日志回退为:
{"level":"error","msg":"not using any configuration file","error":"impossible to find config file in the default locations [./,/goff/,/etc/opt/goff/]"}
⚠️ 注意:默认搜索"路径 + 文件名"两者都固定。生产环境不要依赖默认搜索,
ExecStart里显式带--config最稳妥。
3.3 环境变量映射规则
配置文件里的每个字段都可以用同名大写环境变量覆盖,嵌套字段用下划线连接:
| 配置路径 | 环境变量 | 实测是否生效 |
|---|---|---|
server.port | SERVER_PORT | 是(1031 → 1032) |
retriever.path | RETRIEVER_PATH | 是(加载到另一份 flags 文件中的 env-flag) |
logLevel | LOGLEVEL | 是(出现 debug 日志) |
pollingInterval | POLLINGINTERVAL | 是(3 秒内感知 flags 变更) |
验证端口覆盖:
SERVER_PORT=1032 timeout 4 /usr/local/bin/go-feature-flag-relay-proxy --config /etc/go-feature-flag/goff.yaml
实测回显(节选):
{"level":"info","caller":"api/server_lifecycle.go:119","msg":"Starting go-feature-flag relay proxy ...","address":"0.0.0.0:1032","version":"1.57.2"}
验证 retriever 路径覆盖(flags2.yaml 中开关名为 env-flag):
RETRIEVER_PATH=/etc/go-feature-flag/flags2.yaml timeout 4 \
/usr/local/bin/go-feature-flag-relay-proxy --config /etc/go-feature-flag/goff.yaml
实测回显:
{"level":"info","ts":1793121897.106729,"msg":"flag added","key":"env-flag"}
验证日志级别覆盖:
LOGLEVEL=DEBUG timeout 3 /usr/local/bin/go-feature-flag-relay-proxy --config /etc/go-feature-flag/goff.yaml 2>&1 | grep -c '"level":"debug"'
实测回显:
2
3.4 三者优先级实测
用一个最小实验固定优先级:配置文件写 1031,环境变量写 1032,命令行只给路径。
grep -A1 '^server' /etc/go-feature-flag/goff.yaml
SERVER_PORT=1032 timeout 3 /usr/local/bin/go-feature-flag-relay-proxy --config /etc/go-feature-flag/goff.yaml \
| grep -o '"address":"[^"]*"'
实测回显:
server:
port: 1031
"address":"0.0.0.0:1032"
结论(实测优先级,从高到低):
- 环境变量:覆盖配置文件同名字段;
- 配置文件:提供其余全部字段的取值;
- 命令行
--config:不参与数值覆盖,只决定读哪份配置文件。
💡 说明:环境变量在编排平台与自动化部署里最常用(如把端口、日志级别注入),配置文件适合承载结构化的 retriever/exporter 配置。两者同时存在时以环境变量为准,排障时先
env | grep -E 'PORT|RETRIEVER|LOGLEVEL'排除环境干扰。
四、参数总览
下表是 relay-proxy 常用参数的全景,默认值与实测行为对齐(完整清单以官方配置文档为准):
| 参数 | 类型 | 默认值 | 作用 | 是否实测 |
|---|---|---|---|---|
server.port | int | 1031 | HTTP 监听端口 | 是 |
pollingInterval | int(毫秒) | 60000 | flags 重新拉取间隔,最小 1000 | 是 |
enablePollingJitter | bool | false | 拉取时间加 ±10% 抖动,避免多实例同时打存储 | 否 |
fileFormat | string | yaml | flags 文件格式:yaml/json/toml | 是(yaml) |
logLevel | string | info | ERROR/WARN/INFO/DEBUG | 是 |
logFormat | string | json | json/logfmt | 是(json) |
hideBanner | bool | false | 是否隐藏启动 Banner | 否 |
enableSwagger | bool | false | 是否开启 /swagger/ | 是(默认 404) |
enablePprof | bool | false | 是否开启 /debug/pprof/ | 是(默认 404) |
startWithRetrieverError | bool | false | retriever 失败时是否仍启动 | 是 |
persistentFlagConfigurationFile | string | 无 | 本地持久化 flags 快照,供启动兜底 | 否 |
retriever / retrievers | object / array | 无(必填) | flags 来源 | 是(file) |
authorizedKeys.evaluation | []string | 无 | 求值接口鉴权 Key | 是 |
authorizedKeys.admin | []string | 无 | 管理接口鉴权 Key | 是 |
exporter | object | 无 | 求值事件导出 | 否 |
notifier | object | 无 | flags 变更通知 | 否 |
evaluationContextEnrichment | object | 无 | 全局附加求值上下文 | 否 |
解读:真正影响"服务能不能起来"的只有 retriever(或无 retriever 时的 retrievers);其余参数都有默认值。"是否实测"列为否的项,本文给出参数语义但不虚构回显,落地前请在自己的环境验证一次。
五、服务端参数详解
5.1 监听端口 server.port
server:
port: 1031
改端口后 /health 与全部 API 都会跟着迁移。实测以 SERVER_PORT=1032 启动后,1031 上无响应、1032 上返回正常:
curl -s http://127.0.0.1:1032/health
实测回显:
{"initialized":true}
⚠️ 注意:v1.57.2 启动日志会出现
The server port is set using 'port', this option is deprecated, please migrate to 'server.port'。即使只写server.port也会出现,这是内部默认值回填触发的误报,监听地址以Starting ... address 0.0.0.0:<port>为准。
5.2 拉取间隔 pollingInterval
单位是毫秒,默认 60000。设为 3000 后,修改 flags 文件约 3 秒即生效。实测:
POLLINGINTERVAL=3000 nohup /usr/local/bin/go-feature-flag-relay-proxy \
--config /etc/go-feature-flag/goff.yaml > /var/log/go-feature-flag/poll.log 2>&1 &
sleep 2
curl -s http://127.0.0.1:1031/info
实测回显:
{"cacheRefresh":"2026-10-27T17:25:27.304969458Z"}
往 flags 文件追加一个 promo-banner 开关,等待 6 秒后再次查询:
curl -s http://127.0.0.1:1031/info
curl -s -X POST -H "Content-Type: application/json" \
-d '{"context":{"targetingKey":"user-003"}}' \
http://127.0.0.1:1031/ofrep/v1/evaluate/flags/promo-banner
实测回显:
{"cacheRefresh":"2026-10-27T17:25:33.308169786Z"}
{"key":"promo-banner","value":true,"reason":"STATIC","variant":"on","metadata":{"gofeatureflag_cacheable":true}}
cacheRefresh 相隔 6 秒、开关已可求值,证明轮询确实按 3 秒周期工作。取值小于 1000 会被拒绝/回落到最小间隔;设为负数可关闭轮询(仅适合 flags 完全静态的场景)。
5.3 日志 logLevel / logFormat
logLevel: info
logFormat: json
json 便于日志采集系统按字段解析;logfmt 输出 key=value 形式,适合直接 grep。日志中几个高频字段含义:
| 字段 | 含义 |
|---|---|
msg | 事件名,如 flag added、Starting go-feature-flag relay proxy ... |
address | 实际监听地址,排障第一现场 |
version | 运行版本 |
error | 失败原因,配置类故障几乎都在这里 |
5.4 开关端点与调试端点
enableSwagger 与 enablePprof 默认关闭,实测访问均返回 404:
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:1031/swagger/index.html
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:1031/debug/pprof/
实测回显:
404
404
生产环境保持默认关闭;确需临时排障再开启,用完立即关掉并重启。
5.5 启动容错 startWithRetrieverError
默认 false:flags 读不到就崩溃。设为 true 后,即使 flags 文件语法错误也能启动。实测用一份坏 YAML:
server:
port: 1035
retriever:
kind: file
path: /tmp/bad-flags.yaml
startWithRetrieverError: true
curl -s http://127.0.0.1:1035/health
curl -s -o /dev/null -w "%{http_code}\n" -X POST -H "Content-Type: application/json" \
-d '{"context":{"targetingKey":"u"}}' \
http://127.0.0.1:1035/ofrep/v1/evaluate/flags/any-flag
实测回显:
{"initialized":true}
404
日志同时给出原因:
{"level":"error","msg":"Impossible to retrieve the flags, starting with the retriever error","error":"yaml: line 1: did not find expected ',' or ']'"}
⚠️ 注意:该参数让服务"活着但不可用",适合与
persistentFlagConfigurationFile搭配做降级;无持久化快照时,求值请求会全部落空(未知开关返回 404),不建议在核心链路上长期开启。
六、Retriever 参数详解
retriever 是唯一必填项,决定 flags 从哪读。它由两个并列字段承载:单数的 retriever 与复数的 retrievers(多个来源并行拉取、按顺序合并覆盖)。
6.1 本地文件 retriever(本文使用)
retriever:
kind: file
path: /etc/go-feature-flag/flags.yaml
kind 固定为 file,path 为绝对路径。文件变更通过 pollingInterval 感知,无需重启。
6.2 其他 retriever 类型
kind | 必填字段 | 典型用途 |
|---|---|---|
http | url(可选 method/headers/timeout) | 从配置中心或静态站点拉取 |
github / gitlab / bitbucket | repositorySlug、path(可选 branch/token) | flags 跟代码一起评审、走 Git 流程 |
s3 / googleStorage / azureBlobStorage | 桶/对象相关字段 | 对象存储集中托管 |
redis | options、prefix | 低延迟、高频变更 |
mongodb | uri、database、collection | 已有 MongoDB 的团队 |
configmap | namespace、configmap、key | Kubernetes 内运行 |
💡 技术拓展:flags 存储位置的选择本质是"变更流程"的选择——
方案 变更入口 优点 代价 本地文件 登录服务器改 YAML 最简单、无外部依赖 无审计、多实例易漂移 Git 仓库 提 PR 改文件 有评审与历史 受仓库 API 限流影响 对象存储 上传对象 与发布流水线天然集成 需要云凭证管理 Redis/MongoDB 写库 变更即时、可做管理台 多一个高可用组件要运维 本文采用本地文件 retriever,理由是单机部署、开关量小、变更走运维工单;多实例生产建议换成 Git 或对象存储,避免各节点文件不一致。
6.3 多来源合并 retrievers
retrievers:
- kind: file
path: /etc/go-feature-flag/base-flags.yaml
- kind: file
path: /etc/go-feature-flag/override-flags.yaml
多个来源并行读取,按声明顺序合并,后者的同名开关覆盖前者,适合"基础开关 + 环境覆盖"的分层管理。
七、求值鉴权参数详解
默认没有任何鉴权,任何能访问 1031 的客户端都可求值。设置 authorizedKeys 后,请求必须带 Authorization: Bearer <key>。
authorizedKeys:
evaluation:
- eval-demo-key
admin:
- admin-demo-key
实测(配置文件 /etc/go-feature-flag/goff-auth.yaml,端口 1032):
# 不带 Key
curl -s -o /dev/null -w "%{http_code}\n" -X POST -H "Content-Type: application/json" \
-d '{"context":{"targetingKey":"u1"}}' \
http://127.0.0.1:1032/ofrep/v1/evaluate/flags/promo-banner
实测回显:
401
# 带求值 Key
curl -s -X POST -H "Authorization: Bearer eval-demo-key" -H "Content-Type: application/json" \
-d '{"context":{"targetingKey":"u1"}}' \
http://127.0.0.1:1032/ofrep/v1/evaluate/flags/promo-banner
实测回显:
{"key":"promo-banner","value":true,"reason":"STATIC","variant":"on","metadata":{"gofeatureflag_cacheable":true}}
管理接口 /admin/v1/retriever/refresh 只认 admin 列表中的 Key:
curl -s -o /dev/null -w "%{http_code}\n" -X POST http://127.0.0.1:1032/admin/v1/retriever/refresh
curl -s -w " http=%{http_code}\n" -X POST -H "Authorization: Bearer admin-demo-key" \
http://127.0.0.1:1032/admin/v1/retriever/refresh
实测回显:
401
{"refreshed":true} http=200
💡 说明:
evaluation与admin是两套独立 Key,求值 Key 不能调用管理接口。Key 属于系统级凭据,生产环境应从密钥管理系统注入(如 systemdEnvironmentFile或编排平台的 Secret),不要写进配置文件明文。
八、导出与通知参数详解
8.1 求值事件导出 exporter
用于把每次求值的结果导出到下游(对象存储、Kafka、Webhook 等),支撑"谁在什么时候命中哪个变体"的审计。典型结构:
exporter:
kind: webhook
endpointUrl: https://audit.example.com/goff
flushInterval: 10s
maxEventInMemory: 1000
flushInterval 控制批量落盘/推送周期,maxEventInMemory 是内存缓冲上限,超过即触发一次发送。本文未配置 exporter,实测的求值响应不带导出副作用;上线前建议先在预发环境验证下游能收到事件。
8.2 变更通知 notifier
flags 文件变更后可推送到 Slack/Webhook,便于团队感知"开关被改了"。结构:
notifier:
kind: webhook
endpointUrl: https://chat.example.com/hook
配合 DisableNotifierOnInit: true 可避免每次启动都推一条"flags 已加载"的噪声消息。
九、flags 文件语义
配置参数决定"服务怎么跑",flags 文件决定"开关怎么算"。一个开关由三部分组成:
| 键 | 必填 | 含义 |
|---|---|---|
variations | 是 | 变体名到取值的映射,取值可为 bool/string/number/object |
targeting | 否 | 定向规则列表,按顺序匹配 |
defaultRule | 是 | 所有规则未命中时的兜底变体 |
9.1 定向规则与 defaultRule
new-checkout-flow:
variations:
enabled: true
disabled: false
targeting:
- query: companyID eq "admin"
variation: enabled
defaultRule:
variation: disabled
query 使用 GO Feature Flag 的表达式语法,companyID 取自求值上下文的同名字段。实测结果(见第三章求值示例):companyID=admin 返回 enabled/TARGETING_MATCH,其他值返回 disabled/DEFAULT。
9.2 百分比灰度
beta-banner:
variations:
on: true
off: false
targeting:
- query: email co "@example.com"
percentage:
on: 50
off: 50
defaultRule:
variation: off
对同一批 @example.com 用户按 targetingKey 做 50/50 分流,实测:
for k in u-1002 u-1003 u-1004; do
printf "%s " $k
curl -s -X POST -H "Content-Type: application/json" \
-d "{\"context\":{\"targetingKey\":\"$k\",\"email\":\"$k@example.com\"}}" \
http://127.0.0.1:1036/ofrep/v1/evaluate/flags/beta-banner
echo
done
实测回显:
u-1002 {"key":"beta-banner","value":false,"reason":"TARGETING_MATCH_SPLIT","variant":"off","metadata":{"gofeatureflag_cacheable":true}}
u-1003 {"key":"beta-banner","value":true,"reason":"TARGETING_MATCH_SPLIT","variant":"on","metadata":{"gofeatureflag_cacheable":true}}
u-1004 {"key":"beta-banner","value":false,"reason":"TARGETING_MATCH_SPLIT","variant":"off","metadata":{"gofeatureflag_cacheable":true}}
不带 email 的用户不命中定向规则,落到默认变体:
{"key":"beta-banner","value":false,"reason":"DEFAULT","variant":"off","metadata":{"gofeatureflag_cacheable":true}}
💡 技术拓展:灰度分流算法在同类的特性开关产品里有几种常见实现——
算法 特点 适用场景 一致性哈希百分比 同一 key 稳定落在同一桶,扩缩容影响小 长周期灰度、A/B 实验 纯随机百分比 每次请求随机,比例精确但用户会来回跳 流量级实验 定向规则(属性匹配) 按用户属性精确命中 内测名单、租户白名单 渐进式发布(按时间递增) 按计划逐步放量 高风险变更的自动放量 本文示例使用"一致性哈希百分比 + 属性定向"组合:先按
十、生产配置模板
以下模板适用于"4 vCPU / 8 GB 内存 / SSD、单机承载 200 QPS 求值、flags 由 Git 仓库维护"的场景:
server:
port: 1031
pollingInterval: 60000
enablePollingJitter: true
fileFormat: yaml
logLevel: info
logFormat: json
persistentFlagConfigurationFile: /var/lib/go-feature-flag/flags-snapshot.yaml
startWithRetrieverError: true
retriever:
kind: github
repositorySlug: example/feature-flags
path: flags/prod.yaml
branch: main
token: ${GOFF_GITHUB_TOKEN}
authorizedKeys:
evaluation:
- ${GOFF_EVAL_KEY}
admin:
- ${GOFF_ADMIN_KEY}
逐项说明:
enablePollingJitter: true:多实例同时启动时打散拉取时间,避免对 Git 仓库形成尖峰。persistentFlagConfigurationFile:把最近一次成功拉取的配置落盘,配合startWithRetrieverError实现"仓库不可用也能按旧配置服务"。retriever.kind: github:开关变更走 PR 评审;token用于私有仓库。authorizedKeys:对外只暴露求值 Key,管理 Key 仅运维侧持有。- 两个
${...}为系统级凭据占位,部署时通过EnvironmentFile=或环境变量注入,不要提交到仓库。
⚠️ 注意:模板中的
/var/lib/go-feature-flag/需提前创建并chown goff:goff,否则持久化写入会失败。
十一、常见问题
11.1 改了配置文件但行为没变
先确认实际加载的是哪份文件,以及有没有被环境变量覆盖:
systemctl show go-feature-flag -p ExecStart
env | grep -E 'SERVER_PORT|RETRIEVER_PATH|LOGLEVEL|POLLINGINTERVAL'
实测回显(第一条,节选):
ExecStart={ path=/usr/local/bin/go-feature-flag-relay-proxy ; argv[]=/usr/local/bin/go-feature-flag-relay-proxy --config /etc/go-feature-flag/goff.yaml ; ... }
若环境变量存在,它会盖掉文件值(见 3.4 节实验)。清理环境变量或改用 EnvironmentFile 统一管理。
11.2 求值全部返回默认值
按顺序排查:/health 是否 initialized:true → /info 的 cacheRefresh 是否在更新 → flags 文件里开关名是否拼写一致 → 定向规则的 query 字段名是否与上下文一致。
curl -s http://127.0.0.1:1031/health
curl -s http://127.0.0.1:1031/info
curl -s -X POST -H "Content-Type: application/json" -d '{"flags":["new-checkout-flow"]}' \
http://127.0.0.1:1031/v1/flag/configuration
实测回显:
{"initialized":true}
{"cacheRefresh":"2026-10-27T17:29:04.266149696Z"}
{"flags":{"new-checkout-flow":{"variations":{"disabled":false,"enabled":true},"targeting":[{"query":"companyID eq \"admin\"","variation":"enabled"}],"defaultRule":{"variation":"disabled"}}}}
/v1/flag/configuration 返回的是服务端真实生效的开关定义,用它和本地文件比对即可确认"文件是否真的被加载"。
11.3 百分比灰度的比例看起来不对
百分比分流是按 targetingKey 做稳定哈希,不是每次请求随机。样本量小时比例偏离属于正常现象;要验证分流是否生效,用固定的一批 key 循环求值,观察是否稳定落在同一变体即可(见 9.2 节实测)。
11.4 启动告警 server port is set using port
v1.57.2 的已知误报:只要端口来自内部默认回填就会打印,即使配置只写 server.port。判断是否真的生效请看 Starting ... address,或直接 curl /health。不影响功能,无需处理。
十二、参考链接
- relay-proxy 配置文档:https://gofeatureflag.org/docs/relay_proxy/configure_relay_proxy
- flags 文件格式与表达式:https://gofeatureflag.org/docs/go_module/configuration
- API 端点清单:https://gofeatureflag.org/docs/relay_proxy/relay_proxy_endpoints
- 站内篇目:《GO Feature Flag 1.57.2 Ubuntu 22.04 安装指南》、《GO Feature Flag 1.57.2 常用 CLI 与运维命令详解》