多实例与高可用部署
应用层可以运行多个副本,但高可用还要求 PostgreSQL、Redis、反向代理和上游账号池不存在单点。
参考拓扑
┌──────────────┐
Internet ─────────▶│ Load Balancer│
└──────┬───────┘
┌───────┴────────┐
▼ ▼
Sub2API A Sub2API B
│ │
└───────┬────────┘
┌───┴────┐
▼ ▼
PostgreSQL Redis共享配置
所有副本必须一致:
JWT_SECRET。TOTP_ENCRYPTION_KEY。- 数据库和 Redis endpoint。
- 时区。
- URL allowlist 和安全策略。
- OAuth client secrets。
- 计费、定价和 Gateway 关键配置。
- 自定义 Codex instructions 模板。
推荐从同一个 Secret/Config source 注入,而不是手工编辑每台服务器。
实例本地状态
- L1 cache。
- HTTP/WS connection pool。
- 内存 worker queue。
- 本地日志。
- 静态覆盖和本地数据文件。
滚动发布会中断该副本上的流式请求和 WebSocket。负载均衡器应先摘除实例,再等待连接排空。
负载均衡
普通 HTTP/SSE 请求可以 round-robin。WebSocket 和 previous response 场景可能受益于会话亲和,但不能只依赖 LB sticky:
- Redis 会保存账号和会话提示。
- 已建立 WS 连接仍只存在某个实例。
- 实例退出后客户端必须重连。
如果开启 LB cookie sticky,确保它不影响 API 客户端或泄漏跨用户状态。
优雅发布
建议流程:
- LB 将实例标记为 draining。
- 停止新连接。
- 等待活跃 SSE/WS 到达可接受阈值。
- 发送 SIGTERM。
- 允许应用停止 worker 和关闭资源。
- 启动新版本并通过
/health。 - 加回 LB,再处理下一个实例。
长连接可能持续数十分钟,需要设置最大 drain 时间,并接受少量客户端重连。
数据库连接
例如 4 个副本,每个 max_open_conns=100,理论上应用可打开 400 个连接。数据库还需要为迁移、备份和管理员预留。
扩应用副本时同步检查:
- PostgreSQL max connections 和内存。
- Redis pool 总连接数。
- 上游账号总并发。
- 反向代理 upstream keepalive。
后台任务
周期任务通过 Redis leader lock 或 PostgreSQL advisory lock 避免重复执行。检查:
- 所有副本使用相同 lock backend。
- 实例 ID 唯一。
- Redis key 不与其他环境冲突。
- lock TTL 大于任务最坏耗时。
- job heartbeat 能看到 leader 和执行状态。
调度一致性
账号/分组变更通过缓存失效、outbox 和快照重建传播。多实例时关注:
- scheduler outbox lag。
- 某个实例是否长期使用旧快照。
- Redis pub/sub 或版本 key 是否正常。
- DB fallback 是否集中发生。
可以在不同实例分别发送带调试标识的请求,对比候选与配置版本。
PostgreSQL 高可用
应用只知道配置的数据库 endpoint。HA 方案应提供:
- 稳定写 endpoint。
- 自动主从切换。
- 可接受的 DNS/连接恢复时间。
- 备份与 PITR。
切主时旧连接会失败,应用连接池需要重新建立。把连接 lifetime 设置为有限值有助于长期回收旧连接。
Redis 高可用
Redis 选主切换期间,并发槽位、锁和缓存操作可能失败。HA 设计要验证:
- 切换后应用是否自动连接新主。
- Lua 脚本和 key 是否完整复制。
- leader lock 不会同时被两个主接受。
- AOF/RDB 丢失窗口是否可接受。
健康检查
/health 适合 LB 判断进程存活,但完整 readiness 还应通过外部探针验证:
- PostgreSQL 查询。
- Redis ping/脚本。
- 测试分组的最小模型请求。
- 用量记录是否落库。
不要让高频 LB health check 每次都调用付费上游;上游 smoke test 可以低频独立执行。
容量扩展顺序
- 确认瓶颈是应用 CPU/连接,而不是上游账号。
- 优化慢查询、日志和 worker。
- 扩 PostgreSQL/Redis 容量。
- 增加应用副本。
- 增加账号池与代理冗余。
- 重新计算所有连接池与告警阈值。
单纯增加应用副本不会增加上游账号额度。