Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

生产最佳实践

本章给出 ScootGate 的推荐生产基线。它不是替代平台安全规范的万能模板; 当可用性与授权、出口或计费副作用边界冲突时,优先保证后者正确。

1. 推荐拓扑

                              ┌──────────────────────────┐
                              │ 外部控制面                │
                              │ auth / routing snapshots │
                              └────────────┬─────────────┘
                                           │ HTTPS 拉取
客户端 ── TLS ──► ScootGate ── CONNECT ──► 专用出站代理 ── TLS ──► Provider
                    │   │
                    │   ├── MQTT:usage + snapshot notifications
                    │   └── 持久盘:snapshot cache + usage outbox
                    └── health listener(仅内网/本机)

推荐同时在两层强制出口边界:

  1. ScootGate 配置只提供一个受控 HTTP CONNECT 或 SOCKS5 出口;
  2. 主机或网络策略禁止 ScootGate 直接访问 Provider,只允许访问控制面、 MQTT、DNS 和专用出站代理。

第二层不是为了弥补应用逻辑,而是防止未来配置错误或回归绕开代理。

2. 配置与秘密

Provider 凭据

  • 优先使用 [credentials.<id>].file 指向 secret manager 挂载的只读文件;
  • 使用 env 时,仅向 ScootGate 进程注入,不写进 shell profile、镜像或日志;
  • 每个 Provider/账户使用独立 credential ID,便于撤销和审计;
  • 文件建议权限 0400,所属用户为运行 ScootGate 的无特权账户。

服务身份

当前 [auth].token[egress].username/password[mqtt].username/password 是配置字段。生产环境应由 secret manager 在启动前生成完整配置到 tmpfs 或受限目录,并设置 0600;不要把渲染后的 配置提交到 Git、烘焙进镜像或作为命令行参数传递。

routing_source.token_env 只写环境变量名,实际 token 由进程环境注入。

本地状态

将以下路径放在持久盘,并限制目录权限为 0700

  • 授权快照缓存;
  • 路由快照缓存(snapshot 模式);
  • 用量 outbox。

快照缓存与 outbox 不包含原始客户端 key 或 Provider key,但仍包含租户、 key ID、后端与流量元数据,必须按敏感运行数据保护。

3. 入口与健康面

  • 生产 API listener 必须配置 [server.tls],证书至少支持 TLS 1.2;
  • health listener 与 API listener 使用不同端口;
  • health listener 仅向本机探针、私网负载均衡器或 DNS controller 开放;
  • 不要把 /healthz/readyz 暴露到公共互联网;
  • 私有 CA 通过 SCOOTGATE_EXTRA_CA_CERTS 提供,不增加跳过校验的开关。

流量入口只依据 /readyz 接流:

  • /healthz 表示进程存活;
  • /readyz 还要求授权快照可用、路由表可用且节点不在排空;
  • snapshot 路由控制面超过 max_stale_secs 未成功刷新时,节点转为 unready,但继续使用最后一份有效路由表服务已有流量。

4. 强制代理出口

  • 为每个节点或节点组分配专用代理服务身份,不复用个人账号;
  • 跨不可信网络访问代理时启用 egress.tls = true
  • 代理 TLS 和 Provider TLS 都必须使用可信根验证;
  • connect_timeout_ms 应小于整体 response_head_timeout_ms
  • 上线前主动停止代理,确认请求返回 502 且 Provider 没收到连接。

ScootGate 不提供直连回落。代理不可用时降低成功率是预期的安全行为。

5. 模型与容量

公共模型名

公共模型名是客户端契约,应保持稳定;真实 Provider 模型名只放在 target 中。 不同协议必须使用不同模型池,不做 OpenAI 与 Anthropic 的隐式互转。

权重与能力

  • weight 表示相对容量/成本意图,不等于严格流量百分比;
  • 默认 weighted_p2c 会同时考虑权重、节点在途数、EWMA 首包延迟和慢启动;
  • 只有确认 target 支持时才开启 supports_streamsupports_toolssupports_json_schema
  • 新后端先以较低权重加入,观察首包延迟、429 和 5xx 后再逐步提高。

在途上限

max_inflight_per_node 应取 Provider 配额、代理容量和节点内存三者中的保守值。 不要把它当作全局配额:每个 ScootGate 节点独立维护本地在途数。

6. 故障隔离与重试

  • 保持 max_pre_send_attempts = 2:总共最多两次选择;
  • 只有连接代理或 Provider TLS 失败等 DefinitelyNotSent 场景允许改选一次;
  • 请求字节可能发出后(PossiblySent)绝不重试;
  • 401/403 表示网关持有的 Provider 凭据失效,整个 backend 会被停用;
  • 429 原样返回,并让 backend 进入短暂冷却;
  • 熔断半开探测固定单飞,避免恢复瞬间放大流量。

不要在外层反向代理、SDK 或 service mesh 中对 POST Provider 请求增加自动重试, 否则会绕过 ScootGate 的发送状态判断并产生重复计费风险。

7. static 与 snapshot 的选择

条件推荐模式
单节点、路由很少变化、由配置发布系统管理static
多节点、频繁调整后端/权重、需要集中控制snapshot

两种模式严格互斥:

  • static:本地必须声明 [backends][models]
  • snapshot:本地禁止声明 backends/models,只保留 credentials;
  • 不存在字段级合并、局部覆盖或“本地兜底”。

snapshot 发布必须遵守:

  1. 版本严格递增;
  2. 每份快照完整包含全部 backends/models;
  3. 先在控制面完成引用与协议校验,再发布;
  4. MQTT 只发送 {"version": N} 提示,真实配置仍由受认证 HTTPS 拉取;
  5. max_stale_secs >= poll_interval_secs,并与流量摘除窗口匹配。

坏快照会被整体拒绝,不会覆盖最后一份有效表。

8. 用量 outbox 与 MQTT

  • outbox 必须位于持久盘,而不是容器临时层;
  • max_outbox_bytes 必须小于卷可用容量,并预留快照、日志与文件系统空间;
  • 控制面按 event_id 去重;QoS 1 和重启重放都可能产生重复投递;
  • 监控 health 响应中的 pending_eventspending_bytesoldest_event_age_secsdropped_events
  • broker 故障时数据面继续服务;outbox 满后按 drop_newest 丢新并告警;
  • token 只取 Provider 原生 usage;缺失保持 null,不得按响应字节估算。

该通道固定 authoritative = false,不能直接作为权威账单。

9. 发布与回滚

推荐按以下顺序滚动:

  1. 在预发布节点验证配置解析、代理失败、TLS、授权与模型目录;
  2. 新节点启动后等待 /readyz 为 200;
  3. 逐步加入流量并观察 429、5xx、熔断、首包延迟和 outbox;
  4. 再排空旧节点;
  5. snapshot 模式先发布新凭据到节点,再发布引用该凭据的新快照;
  6. 回滚时发布更高版本的“回滚内容”,不要重放旧版本号。

请求在开始时固定使用一份路由表;热更新不会改变进行中的请求。

10. 上线前故障演练

注入故障必须观察到的结果
无授权快照冷启动/readyz 非 200,客户端 key 被拒绝
吊销客户端 key新授权快照生效后返回 401
停止出站代理请求返回 502,Provider 无直连连接
Provider TLS 不可信请求失败,无跳过校验回落
Provider 401/403客户端收到 502,backend 被停用
Provider 429当前 429 原样返回,后续流量短暂避开该 backend
非法路由快照版本不切换,最后有效表继续服务
路由控制面超期不可达/readyz 转非 200,旧表继续服务
MQTT 不可达请求继续服务,outbox 积压增长
outbox 达上限新事件丢弃、计数增长,数据面继续服务
SIGTERM节点先排空并在 grace period 内退出

11. 生产检查清单

  • API listener 使用可信 TLS 证书;
  • health listener 未暴露公网;
  • 网络策略禁止 Provider 直连;
  • 代理、控制面与 MQTT 使用专用服务身份;
  • Provider 凭据只来自环境或只读文件;
  • 配置文件与状态目录权限已收紧;
  • 公共模型名、target 能力与协议已核验;
  • 每 backend 在途上限与 Provider 配额匹配;
  • /readyz 已接入入口摘除;
  • snapshot 版本、staleness 与回滚流程已演练;
  • outbox 容量与四项健康指标已监控;
  • 外层组件没有对 Provider POST 请求自动重试;
  • 上表中的高风险失败路径已在预发布环境演练。