案例研究
由真实的自托管网关运维工作匿名化、泛化而来。身份信息、主机名、精确数字与厂商组合均已修改;时间线结构与故障模式才是要传达的经验。下文数字用于说明模式,不是账单记录。
起点
一个小型产品团队用三个服务对接两家 AI 服务商。每个服务在自己的 env 文件里各存一把服务商密钥;其中一把曾在一次事故中经聊天工具转发过、此后从未轮换。没有按团队的用量视图——账单就是一个总数。
阶段 1 · 收拢(第 1 周)
- 在内部子域名上部署网关(Docker Compose、非 root、只读根文件系统),前置 Caddy,启用 HTTPS 与 HSTS。
- 两把服务商密钥全部移入密钥库;每个服务发一把虚拟密钥,带月度预算与模型白名单。
- 各服务只改
base_url和密钥即完成切换——不改代码,因为网关说的是同一种 API 方言。 - 在切换之后轮换那把经聊天泄漏的服务商密钥;客户端零改动——这正是加一层间接的意义。
阶段 2 · 路由策略(第 2 周)
- 内部工具走廉价快速的模型等级,面向客户的功能走高级等级——用密钥强制执行,而不是靠自觉。
- 按两周实测流量为每把密钥设定速率上限。
- 每夜加密备份,外部健康探针基于状态变化告警。
阶段 3 · 那次"值回票价"的宕机
几周后,主力服务商出现局部故障——错误率与延迟升高(任何一家大服务商的 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、恢复演练录屏和管理员权限。我的参与按设计终止;系统不需要我也能运转——这就是交付物。