案例复盘
本案例由真实的自托管网关交付经历匿名化、泛化而来。身份信息、主机名、具体数字与厂商组合均已调整;值得借鉴的是时间线结构与故障处理模式。文中数字仅用于说明,不是账单记录。
交付前的状况
一个小型产品团队,三个服务对接两家 AI 服务商。每个服务各自在 env 文件里存了一把服务商密钥,其中一把曾在一次事故排查中被贴进聊天工具转发过,此后再没轮换。用量没有按团队的视图,账单只有一个总数。
第一阶段 · 收拢密钥(第 1 周)
- 在内部子域名上部署网关(Docker Compose、非 root、只读根文件系统),前置 Caddy,配齐 HTTPS 与 HSTS。
- 两把服务商密钥全部收入密钥库;每个服务改发一把虚拟密钥,附带月度预算与模型白名单。
- 各服务只需修改
base_url和密钥就完成了切换——网关说的是同一种 API 方言,业务代码一行不动。 - 切换完成之后,再轮换那把在聊天工具里泄露过的密钥。客户端零改动——这正是加一层网关的意义所在。
第二阶段 · 路由策略(第 2 周)
- 内部工具走低价快速的模型档位,面向客户的功能走高级档位——用密钥策略强制执行,不靠开发者自觉。
- 依据两周实测流量,为每把密钥设定速率上限。
- 启用每夜加密备份;外部健康探针按状态变化告警。
第三阶段 · 一次真正检验价值的故障
上线数周后,主力服务商出现区域性故障,错误率与延迟同时飙升(这类模式在任何一家大型服务商的 status page 历史里都能找到)。以下是网关视角的时间线,演示中用合成数据复现了同一过程:
T+0m 上游 A 错误率超过阈值;健康检查将 A 标记为 degraded
T+0m 路由器开始把失败请求重试到同档位的上游 B
T+2m 探针告警一次:"upstream-a: FAIL"——只此一条,不刷屏
T+31m 服务商恢复;健康检查连续两次通过;A 重新进入轮转
T+31m 探针告警一次:"upstream-a: RECOVERED"
客户可感知的影响:约 2 分钟的 p95 延迟升高;没有出现 5xx 峰值
为什么这次故障如此平淡(这正是设计目标)
- 故障转移在交接时做过强制断流演练——真实事故发生时,它已经是第二次运行。
- 告警做了去重,最终只有两条消息,而不是两百条。
- 复盘报告只写了一段话,因为完整时间线本来就在审计日志里。
交接
团队最终拿到 runbook、恢复演练录屏和全部管理员权限。外部参与到此为止;系统此后独立运转,不依赖任何个人——这正是本次交付的验收标准。