跳到正文

做到高可用

高可用的核心是消除单点:单模型多节点 → 单供应商多份 → 多实例共享状态。本页串起网关的相关能力,不重复建 LB 的逐步操作(见 多上游负载均衡)。

目标与失效面

失效面典型原因对策
单把上游 key 失效限流、被吊销上游配多 key,失败自动轮换
单个上游实例不可用上游宕机、网络分区同模型多上游做 LB
单个供应商不可用供应商级故障跨供应商 LB
单个网关进程不可用进程崩溃、主机故障多实例 + 共享存储

单模型多节点:负载均衡器

把同一模型的多个上游+模型组合做成一个负载均衡器的 entries,客户端只调 LB name。某节点返回可重试错误(5xx、连接/读取超时)时,网关自动换节点重试。建法见 创建负载均衡器多上游负载均衡 的案例 A。

灰度上线新模型

引入新模型(或新节点)时,用权重把流量灰度放量,不必一次全切:

  1. 把新节点加进现有负载均衡器的 entries,给一个小权重——如老节点 weight=10、新节点 weight=1,网关按权重比例分发,新节点只承约 1/11 的流量。
  2. 观察新节点的成功率与延迟(控制台 → 负载均衡器 → Entries 面板,或统计页按模型看),稳定后逐步调大它的权重。
  3. 发现问题就把新节点权重调小或置 0 回滚,流量自动切回老节点。

weight=0 备用节点的区别:备用节点平时不承流量、仅在正常节点全不可用时兜底;灰度节点则是给一个小的真实权重,真实承接一部分流量以验证质量。权重语义见 负载均衡字段

供应商级容灾

主用 OpenAI、备用 Azure OpenAI 的 LB:两个 entry 不同上游、不同模型名,retry_on_different_node=true。主节点全挂时切到备用。见 多上游负载均衡 的案例 B。

重试与流式的边界

  • 重试次数受 MAX_UPSTREAM_RETRIES 控制(见 负载均衡字段)。
  • 流式重试仅在第一个 SSE 数据块发出之前尝试。一旦客户端开始接收数据,不能中途换节点——否则会破坏已发出的部分状态。因此流式场景的故障转移窗口在「首字节前」。

探针与灰度下线

  • /health 返回 200 即存活。
  • /ready 在数据库不可达、网关排空(drain 模式)或入口落盘卷挂死时返回 503——把外部负载均衡器(Nginx / ALB)的健康检查指向 /ready,可在网关排空或磁盘故障时自动停止分发流量,实现灰度下线、零停机重启与挂死卷自动摘除。

多实例共享状态

单机用 SQLite;多实例用 PostgreSQL 共享统计与配置(控制台改动 30s 跨实例同步),并配 Redis 共享会话/限流/IP 封禁/日志广播。字段见 环境变量配置参考STORAGE_MODE / POSTGRES_URL / REDIS_URL

不配 Redis 的多实例

多实例不配 Redis 时,会话、限流、IP 封禁都退化为每实例独立——一个调用方的失败次数分散到不同实例上,封禁阈值形同虚设。多实例务必配 Redis。

接入监控(Prometheus / OpenTelemetry)

网关对外暴露运行指标,接进你现有的可观测体系:

  • PrometheusGET /metrics 暴露 Prometheus 指标。先用环境变量 METRICS_AUTH_TOKEN 设一个鉴权 token,再以 Authorization: Bearer <token> 访问;未设 token 时该端点返回 403(防未授权抓取)。在 Prometheus 的 scrape 配置里把网关地址加上、带上 Bearer 头即可,Grafana 再以 Prometheus 为数据源出图。
  • OpenTelemetry:设 OTEL_ENDPOINT 指向你的 OTLP 收集器,网关即上报 trace/span;OTEL_SERVICE_NAME(默认 protoflux)用在多服务里区分来源。不配 OTEL_ENDPOINT 则不上报。

字段与默认值见 环境变量配置参考,端点清单见 端点 · 认证 · 协议互通

上线前自检

上线检查清单

常见问题

Q:流式响应中途上游断了怎么办? 首块已发出则不换节点,网关记录 body_incomplete 并把已收部分返回客户端。客户端按 SSE 协议处理中断。

Q:备用节点(weight=0)什么时候启用? 仅当所有 weight > 0 的正常节点都不可用时。正常节点恢复后流量自动切回。

Q:多实例的会话怎么共享? 会话存于 Redis(REDIS_URL),所有实例共享;不配 Redis 则每实例独立,登录只对当前实例生效。

下一步多租户隔离 看隔离;上线检查清单 看上线自检;负载均衡字段 看字段。