高可用设计原则:冗余、故障转移、负载均衡、弹性伸缩

推理服务的高可用并非依赖某一项单一技术,而是由一组相互配合的设计原则共同支撑。这些原则如同建筑的承重结构——冗余提供备用容量,故障转移负责快速切换,负载均衡实现流量分发,弹性伸缩则动态匹配资源与需求。理解它们各自的职责与协作方式,是构建稳定推理系统的前提。

核心原理:四条原则的定位与关系

在推理服务场景中,四条原则分别解决不同层面的可用性问题:

  • 冗余(Redundancy):消除单点故障。对无状态推理实例,部署多副本;对有状态组件(如模型版本管理、推理结果缓存),采用主从或多数派机制。冗余是可用性的静态基础。
  • 故障转移(Failover):当某个实例异常时,将流量或角色自动切换至健康实例。解决的是“检测到故障后怎么办”的动态响应问题。
  • 负载均衡(Load Balancing):将请求均匀或按权重分发至多个实例,避免单实例过载。它既是日常流量调度手段,也是故障转移的执行载体。
  • 弹性伸缩(Auto Scaling):根据实时流量或队列深度,自动增加或减少实例数量。解决的是容量与时间维度的匹配问题,是冗余的动态补充。

四者的协作关系可概括为:冗余提供资源池,负载均衡调度资源池,故障转移剔除坏节点并重新调度,弹性伸缩调整资源池规模。缺少任何一环,高可用都难以闭环。

推理服务高可用四原则协作模型 客户端请求 负载均衡器 健康检查 + 流量分发 弹性伸缩控制器 指标监控 → 扩缩容决策 指标 推理实例组 A(主) 实例 A-1(健康) 实例 A-2(健康) 实例 A-3(健康) 推理实例组 B(冗余) 实例 B-1(健康) 实例 B-2(健康) 实例 B-3(扩容中) 权重 60% 权重 40% 实例 A-2(故障) 故障转移:流量切换 扩容指令 冗余:多副本消除单点 弹性伸缩:按需增减副本 健康检查失败 → 负载均衡摘除故障节点 → 弹性伸缩补充新实例 → 故障转移完成

方法流程:从故障发生到服务恢复

以一次典型的推理实例宕机为例,完整的高可用响应流程如下:

  1. 健康检查失败:负载均衡器每 5 秒探测一次实例的 /health 接口,连续 2 次失败即标记为不健康。
  2. 摘除节点:负载均衡停止向故障实例分发新请求,已建立的连接在超时后断开。
  3. 故障转移:原本发往故障实例的流量自动切换至其他健康实例。若配置了备用实例组,则按优先级切换。
  4. 弹性伸缩介入:若整体队列深度持续超过阈值(如 100ms 延迟超过 2 秒),伸缩控制器启动新实例。
  5. 恢复与回切:故障实例修复后重新通过健康检查,负载均衡逐步恢复其权重,避免流量突增。

以下为 Kubernetes 环境中常用的探针配置示例,用于实现上述流程中的健康检查环节:

readinessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5
  failureThreshold: 2
  successThreshold: 1
livenessProbe:
  httpGet:
    path: /live
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10
  failureThreshold: 3

其中 readinessProbe 控制实例是否接收流量,livenessProbe 决定是否重启容器。两者配合,实现了“先摘流量、再重启恢复”的优雅故障处理。

案例场景:大语言模型推理服务的扩容决策

某在线客服系统部署了基于大语言模型的推理服务,初始配置为 4 个 GPU 实例。某日营销活动带来 3 倍流量突增,系统表现如下:

时间点QPSGPU 利用率平均延迟系统动作
14:0012065%380ms正常
14:0528092%1.2s触发扩容阈值
14:0831088%650ms扩容至 6 实例
14:1535090%720ms继续扩容至 8 实例
14:3018060%400ms缩容至 5 实例

该案例中,弹性伸缩策略基于 GPU 利用率超过 85% 持续 3 分钟 或 P95 延迟超过 1 秒 触发扩容,缩容则需利用率低于 40% 持续 10 分钟。同时,负载均衡器在扩容期间将新流量优先分发至延迟最低的实例,避免新实例因冷启动而成为瓶颈。

设计要点:推理服务的弹性伸缩需考虑模型加载时间。若模型冷启动需 30 秒以上,应提前扩容或保持最小冗余实例数,否则流量高峰到来时扩容来不及生效。

误区与复盘:常见设计缺陷

在实践中,以下误区经常导致高可用设计失效:

  • 误区一:只做冗余不做故障转移。多副本部署了,但负载均衡未配置健康检查,或健康检查路径错误,导致流量持续发往故障实例。
  • 误区二:故障转移后无容量兜底。2 个实例承载全部流量,1 个宕机后剩余实例过载,引发雪崩。应预留至少 30% 冗余容量或配置快速扩容。
  • 误区三:弹性伸缩指标选择不当。仅以 CPU 为指标,但推理服务瓶颈常在 GPU 显存或推理队列深度,导致扩缩容与实际需求脱节。
  • 误区四:忽略有状态组件的故障转移。推理服务本身无状态,但模型版本管理、API Key 校验、会话状态等有状态依赖未做高可用,成为新的单点。

一次典型的复盘案例:某团队为推理服务配置了 3 副本,但未设置 podAntiAffinity,导致 3 个副本调度到同一台物理机。当该机器宕机时,所有副本同时丢失,负载均衡无健康节点可用。复盘结论是:冗余必须考虑故障域隔离,副本应分布在不同可用区或至少不同物理机。

关键提醒:故障转移不是“事后补救”,而是需要提前演练的机制。建议每月进行一次故障注入测试(如手动 kill 一个实例),验证健康检查、流量切换和弹性伸缩的完整链路是否按预期工作。未经过演练的故障转移,在真实故障发生时往往不可靠。

高可用设计原则的落地,本质上是对“故障必然发生”这一前提的理性应对。冗余、故障转移、负载均衡与弹性伸缩并非独立选项,而是一个闭环系统:冗余提供容量基础,负载均衡负责日常调度,故障转移处理异常,弹性伸缩动态适配。只有四者协同,并经过持续演练与指标校正,推理服务才能在各类故障场景下维持稳定的可用性。