AI 网关跨云多活与流量镜像落地

日期:2026-07-24

一、项目背景

我们这个项目里,模型推理实例是分散部署的:训练集群和一部分大模型在私有云上,另一部分通用模型跑在公有云,还有少量边缘推理节点放在靠近门店的机房。但最初我们采用的 XpShop AI 网关是单云绑定的——所有流量先打到某一个云上的网关节点,再由它去转发。这带来两个大问题。

第一是故障切不动。那次某公有云 Region 网络抖动,我们想把这朵云上的流量切到私有云,但网关的配置是写死的单点出口,切流要改路由表、重新下发、等生效,整个过程拖了二十多分钟,期间这部分用户的模型调用大面积超时。第二是新版本不敢引流。我们每次上线新模型版本,都想先放一小撮真实流量验证效果和稳定性,但又怕影响生产主链路,结果只能离线压测 + 内部灰度的"伪验证",真实流量下的长尾问题根本发现不了。

痛定思痛,我们决定基于 XpShop AI 网关做两件事:一是把网关本身做成跨云多活,接入层(Gateway-In)在多个云上都有入口,后端模型实例统一纳管;二是引入流量镜像与染色能力,让新版本可以先"吃"一小撮复制流量做验证,确认无虞再按比例切流。

二、落地场景

落地主要围绕三块场景。

第一是跨云多活接入。我们在三朵云各自部署了网关接入层,但后端的模型注册表是统一的——无论模型实例在哪个云,都注册到同一个管控台(Console)的模型目录里,网关路由层(Routing)按"模型能力画像 + 实时成本 + 延迟 + 配额"做全局最优分发,而不再受物理云边界限制。

第二是流量按比例镜像与染色。我们支持把线上真实请求按百分比复制一份(镜像)到新版本模型,原请求仍走老版本,两者互不影响;也可以给特定用户群体(比如内部测试账号、或者某地区灰度用户)打上染色标签,让这部分流量强制走新版本,便于定向观察。

第三是按健康度调度。路由层持续采集每个模型实例的可观测(Observability)指标——延迟分布、错误率、GPU 利用率,一旦某云某实例健康度跌破阈值,调度器自动把流量挪到健康的实例,不需要人工介入。

案例片段(已脱敏): 跨云统一寻址 + 镜像的路由配置片段(YAML,已脱敏):yaml upstream:  - model: qwen-72b-instruct    endpoints:      - addr: grpc://priv-cloud-1:9000   # 私有云        weight: 60      - addr: grpc://pub-cloud-a:9000    # 公有云        weight: 40    mirror:      target: qwen-72b-instruct-canary   # 新版本      ratio: 10                          # 镜像 10% 流量    health:      check: "/healthz"      errorRateThreshold: 0.05           # 错误率超 5% 摘流      p99LatencyThresholdMs: 800

三、关键技术挑战与解决思路

跨云接入与统一寻址。 难点在于多朵云的网关节点如何"看到"同一份后端模型视图。我们没有让每个网关各自维护一份路由表,而是把模型注册信息收敛到管控台,网关节点通过 watch 机制增量同步。这样在任意一朵云新增或下线模型实例,其余云的网关在秒级内就能感知,避免了"某云网关还往已挂掉的实例转发"的经典故障。

流量镜像与染色。 镜像最大的工程挑战是"不能因为镜像影响主链路"。我们把镜像做成 fire-and-forget:主请求的正常返回不受镜像结果影响,镜像请求单独打标、单独计量,且镜像失败(比如新版本实例慢)绝不回传给主链路。染色则用请求 header 里的 x-route-tag 透传,从 Gateway-In 一直带到 Routing,确保染色流量在全链路被识别。

健康度调度与切流。 我们给调度器设了三级响应:告警(健康度异常但未超阈值,只记录)、降级(错误率超阈值但未全死,摘流该实例并把权重转移到其他云)、熔断(实例连续探活失败,直接剔除并触发统一寻址重新平衡)。切流决策由路由层自动做出,平均在健康度跌破阈值后约 10 秒内完成。

数据一致与成本。 跨云镜像会产生额外的推理成本,而且多活下计量层(Metering)要能区分"主流量"和"镜像流量"分别计费,避免镜像流量被算进业务账单。我们让计量层对镜像请求打上 billing=shadow 标记,单独归集到"验证成本"科目,既保证账单准确,也让业务方清楚验证开销。

案例片段(已脱敏): 一次公有云 Region 抖动的自动切流日志(已脱敏):10:31:44 WARN  route[pub-cloud-a] p99=1120ms > 800ms, errorRate=6.1% 10:31:46 INFO  scheduler degrade: weight pub-cloud-a 40 -> 0 10:31:46 INFO  scheduler promote: weight priv-cloud-1 60 -> 100 10:31:55 INFO  route recovered, traffic fully on priv-cloud-1

四、效果数据(可量化、脱敏)

改造后我们统计了一个季度的脱敏示意数据(示意值,非审计口径):

  • 跨云切换耗时:从原来手工改路由表、约 20+ 分钟,降至约 10–30 秒级自动完成,整体切换耗时下降约 95%。
  • 镜像流量占比:新版本验证阶段,我们稳定对生产流量做约 5%–15% 的镜像引流,既验证了真实负载下的长尾问题,又没冲击主链路。
  • 故障恢复时长:因实例/云异常导致的请求失败,平均恢复时长从改造前约 20 分钟降至约 30 秒以内。
  • 多活 SLA:跨三云的多活架构下,网关对外的可用性从单云时期的约 99.5% 提升至约 99.95%,全年因单云故障导致的不可用时间大幅缩短。

五、可复用经验总结

  • 多活先统一寻址。 在谈多活、谈切流之前,先把"后端模型视图"统一起来——所有云的网关看到同一份、秒级同步的模型目录。没有统一寻址,多活就是各自为战,切流时才发现对端根本不知道有哪些实例可用。这是我们在踩了单云绑定坑之后最深刻的体会。
  • 镜像先于全量。 任何新模型、新版本上线,先吃镜像流量做真实负载验证,再小比例染色灰度,最后才全量。镜像几乎零风险(不影响主链路),却能在真实流量下提前暴露长尾问题,是性价比最高的验证手段。我们后来把"无镜像验证不上线"写进了发布规范。
  • 成本要可观测。 多活和镜像都会带来额外算力开销,计量层必须把"主流量"和"影子流量"分开计费,否则验证成本会悄悄侵蚀业务账单,久而久之团队就不敢做验证了。