做AI系统的人,多少都经历过这样的阶段:第一版服务全部跑在一个地域,用户量不大时一切顺畅,等业务一铺开,跨地域访问延迟、单点故障、算力天花板这些问题接踵而至。我这次接手的就是一个典型的单地域AI推理系统,因为业务量涨得快,线上开始频繁扛不住,团队最终决定做一次从单地域到多地域的扩容改造。这篇文章我会把这套扩容方案的完整落地过程写出来,包括架构怎么选、数据怎么跨地域同步、AI推理服务在多个地域怎么部署、流量调度和容灾切换怎么设计,以及在过程中踩过的一些坑。适合正在规划多地域部署的运维、后端和AI平台团队参考。
1. 先说清楚:单地域部署到底卡在哪里
1.1 单地域架构的典型特征
先描述一下我们改造前的状态。服务全部部署在同一个公有云地域(Region)内,Kubernetes集群就一套,数据库、缓存、对象存储全部在该地域的同一个可用区(可用区A)。AI推理服务跑在一组GPU节点上,对外通过一个负载均衡入口暴露接口。整套架构简洁、易维护,部署一个新版本只需要在集群里滚动更新即可。
这种架构在早期没有任何问题,运维成本极低,出问题也容易排查。但随着业务从单一城市扩展到全国乃至海外用户,问题开始集中暴露。最直观的痛点是延迟:一个用户在另一个城市访问我们部署在北京的推理服务,一次请求可能要经过几百毫秒甚至几秒的网络传输,再加上模型推理时间,整体延迟远超用户能接受的范围。AI推理本身计算耗时就不低,网络再一拖,体验自然崩。
1.2 三个躲不开的瓶颈
总结下来,单地域部署的瓶颈集中在三个方向。
第一个是延迟。模型推理服务对延迟极其敏感。比如一个文本生成接口,模型单次推理需要500毫秒,网络往返如果再加500毫秒,用户体验直接翻倍恶化。网络链路是物理距离决定的,单纯调代码优化不了,只能把服务搬到离用户更近的地域。
第二个是可用性和容灾。所有服务集中在一个机房,一旦该地域出现电力故障、光缆中断或者云厂商大规模故障,整个系统直接停摆。我们当时就经历过一次可用区级别的故障,那一小时的对外不可用让团队意识到,必须做跨地域冗余。
第三个是算力资源。单地域的GPU供应是有上限的,尤其在业务高峰时,很难在同一地域内快速申请到足够的GPU实例。如果业务本身是多地域分布的,在各个地域分别部署推理节点,还能顺带利用不同地域的闲置算力,降低成本。
多地域扩容解决的就是这三个问题:用户在哪个区域,就把推理能力放到哪个区域;单一地域挂掉还有别的地域兜底;算力可以在多个地域之间调度,不再被单一资源池卡住。但代价也很明确:架构复杂度成倍上升,数据的跨地域同步、流量的调度、故障场景下的切换,每一项都需要重新设计。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 扩容前先盘家底:别急着上多云
很多团队一提到多地域,就觉得很酷、很先进,想直接一步到位搞“多地多活”。但实际上多地域设计是有层级的,不同业务阶段适合不同方案,盲目求大会把整个团队拖垮。所以动手之前,我建议先做一次完整的现状盘点。
2.1 先画业务拓扑和流量模型
第一步不是选技术栈,而是把现有系统的调用关系摸清楚。我们当时梳理的业务链路是这样的:用户请求先经过负载均衡进入API网关,网关负责鉴权和路由,转发给AI推理服务;AI推理服务依赖模型文件、向量数据库和业务数据库;推理结果写回业务库,同时异步上报到消息队列,供下游做日志分析和模型迭代。
这套链路里,哪些是核心依赖、哪些是可有可无的,一定要分清楚。AI推理服务是核心,业务数据库是高可用重点,消息队列如果断掉不能影响主流程,那就允许跨地域异步补偿。把依赖的轻重缓急理清了,多地域改造就能排优先级,而不是眉毛胡子一把抓。
同时,要分析用户访问的地域分布。我们当时从网关日志里统计出国内华北、华东、华南三个区域的请求量占比最高,海外也有少量流量。那么首批扩容目标就锁定这三块,而不是一上来就铺全球。
2.2 多地域架构常见的三种形态
根据对可用性等级要求的不同,多地域架构大致分三类,大家按需选择。
同城双活是目前性价比最高的方案。两个可用区在同一地域内,物理距离近,网络延迟低,数据同步可以做到接近实时。这个方案主要解决可用区级故障,比如某可用区断电或者网络割接,另一个可用区可以直接接管。部署上相对简单,数据库做主从或者双主都可以。
异地多活是真正意义上的跨地域部署。多个地域同时对外提供服务,每个地域都有一套完整的业务栈,用户被解析到就近地域。数据在多个地域之间做双向同步,复杂度最高,难点集中在数据冲突处理和流量调度上。我们最终选择的就是这种方案,但并不是所有业务都做双活,见后面的成本控制。
还有一种是混合式部署,比如核心业务走同城双活,非核心业务或者备份走异地,主要用于容灾兜底。这种形态改造幅度小,适合预算有限、但是又需要跨地域容灾能力的团队。我们最初的过渡版本就是这种状态:把数据和镜像同步到异地地域,但是不承接线上流量,只作为冷备和调试环境。
2.3 技术选型核心清单
多地域改造涉及的技术组件非常多,我列一张我们最终选型的清单,以及选择理由。
| 组件 | 选型 | 理由 |
|---|---|---|
| 容器编排 | Kubernetes 多集群独立部署 | 多地域网络隔离天然存在,一个集群管一个地域,避免跨地域的etcd同步问题 |
| 集群管理 | KubeFed + 自研发布脚本 | KubeFed负责跨集群资源分发,发布脚本控制灰度 |
| 服务访问 | Istio Service Mesh | 统一做多集群服务发现、流量策略和指标采集 |
| 全局负载均衡 | DNS GSLB + 云厂商全局流量管理 | 按用户地理位置解析到最近地域,支持健康检查自动摘除故障节点 |
| 业务数据库 | MySQL 主从复制 + Canal 同步 | 核心业务库采用一主多从,跨地域通过binlog同步CDC数据 |
| 向量数据库 | Milvus 多副本跨地域 | 用于AI知识库检索,保障就近读,数据写入回源到主地域 |
| 缓存 | Redis 按地域分片 | 不做跨地域实时复制,按地域独立缓存,容忍短时间不一致 |
| 消息队列 | RocketMQ 双地域集群 + MQ Bridge | 通过桥接组件把两地域的消息互通,保证最终一致 |
| 对象存储 | 云厂商对象存储跨地域复制 | 模型文件、数据集等静态资源自动复制到各地域 |
这里想重点说一个经验:Kubernetes 多集群千万不要用单一集群跨地域。我踩过这个坑,最初想的是用一个K8s集群,把多个地域的节点纳管进来,结果网络延迟导致kubelet与apiserver之间心跳频繁超时,节点状态反复横跳,调度器一片混乱。后面改成每个地域独立集群,再上层做统一管理,问题立刻解决。
3. 核心改造:从单地域到多地域要动哪些部件
技术选型定了之后,真正的改造工程才开始。这节说我们实际动过的四大块:网络、数据、业务无状态化、AI推理服务。
3.1 网络链路与公网入口改造
多地域部署的第一步,是把网络打通。每个地域在云厂商里是一个独立的VPC,默认互不相通,需要做VPC对等连接或者云企业网打通内网。如果涉及自建机房和公有云混合,一般会拉专线。这里一个容易踩的坑是网段规划,两个地域的VPC网段一定不能冲突,否则路由根本没法配。我们一开始就因为沿用老网段导致华东和华北的CIDR重叠,重排了一轮,浪费了不少时间。
公网入口我们改造成了三层结构。最外层是云厂商的全局流量管理,或者自建的DNS GSLB,根据用户来源IP解析到对应地域入口;第二层是每个地域各自的公网负载均衡器,承接该地域的流量;第三层才是集群内的Ingress Gateway,由Istio管理。这样每一层都有健康检查,如果某个地域的入口挂了,GSLB会自动把流量解析到其他健康地域。
链路层面还有一点容易被忽略:跨地域内网访问的带宽和延迟。即使有云企业网,地域间的数据传输也不是零成本,带宽太窄会直接拖垮数据同步。建议提前做好流量预估,把跨地域同步的数据量算清楚,再决定带宽规格。
3.2 数据层跨地域同步:一致性永远是大头
数据是这次改造中最难的部分。我们的业务数据分几类:用户和订单等结构化数据存在MySQL;AI知识库的向量存在Milvus;会话状态和热点数据存在Redis;日志和事件走消息队列。
MySQL 跨地域我们采用的方案是“主地域写入+多地域只读副本”。用户修改操作全部路由到主地域的数据库主库,其他地域通过 Canal 监听主库 binlog,同步到各自的只读副本。这样每个地域的读请求走本地副本,解决了读延迟问题,写入请求多一些跨地域RTT,但整体可控。比如用户在华东修改了一项配置,请求会转发到主地域写入,同步回华东副本后,华东本地后续读取就是最新数据。这个方案不是强一致,但满足我们的业务场景。
这里把 MySQL 的同步链路画不出来(不太方便画图),但关键点可以描述一下:Canal 伪装成 MySQL 从库,拿到 binlog 后投递到本地的 Kafka,下游消费写到对端地域的 MySQL。整个链路需要监控位点(position),一旦消费堆积要能快速报警。我们有一次就是 Canal 挂了两小时没发现,等发现时华东和华北的数据已经差了一大截,最后只能手动跑增量任务补数,费了很大劲。
Redis 我们没有做跨地域复制,而是改成按地域独立缓存。理由很简单:缓存本来就可以接受短时间不一致,跨地域复制 Redis 引入的网络开销反而会把响应拖慢。每个地域维护一套自己的 Redis,缓存 key 里加上地域标识,防止冲突。如果某个地域的缓存为空,就回源到本地的 MySQL 只读副本,不跨地域回源。
向量数据库跨地域同步稍微特殊一些。我们的做法是主地域负责数据写入,通过 Milvus 的增量备份机制把数据变更日志跨地域传输,在副本地域异步重建索引。这里需要注意的是,增量数据同步的时效性直接影响AI检索结果的准确率,如果业务上要求新写入的知识立即可被检索,那就得接受一点同步延迟,或者干脆让写请求也回到主地域处理。
3.3 业务无状态化与统一网关
多地域部署要求业务服务必须无状态,否则用户请求被调度到另一个地域的时候,内存里的会话状态就丢了。
我们把原有会话状态从本地内存迁到了Redis,但上一条说了Redis是按地域独立的,所以又引入了一个问题:用户在华东登录后,如果下一次请求被调度到华北,他的会话在华北 Redis 里不存在。解决方式有两种:一是保持用户的地域粘性,让他一直落在同一个地域,这个用网关的会话保持就能做到;二是把会话迁移到共享存储,但我们最终没选这条路,因为跨地域读Redis延迟太高,不划算。
API网关在这里承担了区域识别和路由的职责。我们在网关上根据用户 IP 定位到所属地域,把请求路由到对应地域的入口,并且在响应里返回一个地域标识,方便前端后续请求携带。实际上大部分全局负载均衡设备也能做地域识别,但网关层面做一层更灵活,方便后期加策略。
另外,所有配置文件、密钥和模型版本都要做到跨地域同步。我们统一迁移到了配置中心,并且把配置按地域维度拆成“全局配置+地域覆盖配置”两层。比如模型推理的超时时间全局一致,但某个地域的资源规格不同,就在地域覆盖配置里单独调整。
3.4 AI推理服务在多地域的部署细节
AI推理服务是整个系统中迁移最需要小心的部分,因为模型文件通常好几个GB甚至几十GB,镜像构建一次都要很久。
我们采用的做法是用对象存储跨地域复制分发模型文件。先把模型上传到主地域的对象存储,开启跨地域复制规则后,自动同步到其他各地域的对象存储桶。推理服务启动时,从本地域的对象存储下载模型到本地磁盘或者内存映射加载,不会跨地域拉文件,启动速度快很多。这里有一个经验:模型版本号必须写进镜像标签和启动参数里,绝对不能只放在数据库配置里,否则不同地域拉到的模型版本不一致,推理结果就会五花八门,排查时非常痛苦。
推理服务本身的部署和普通服务没有本质区别,还是打镜像推到各地域的镜像仓库(我们用了镜像仓库的跨地域复制功能),然后KubeFed帮忙分发 Deployment 到多个集群。不过 GPU 节点调度要比 CPU 服务小心得多,每个地域的 GPU 型号可能不同,我们就在节点上打了 GPU 型号的 label,并用 nodeSelector 约束推理服务只调度到指定型号的节点上。
多地域部署还带出一个新的问题:如果模型有更新,怎么做到平滑升级?单地域的时候滚动更新很简单,但多地域需要对每个地域单独控制发布节奏。我们做的是分地域灰度发布,先升级华北,确认推理质量指标平稳,再升级华东,最后升级华南。任何一步出问题就回滚成旧版本,不会影响全局。这套流程我们用 CI/CD 配合手动审批来管理,前几次升级全程盯监控,后面才敢逐渐自动化。
还有一个容易被忽视的点是推理服务的冷启动。我们的文本生成模型加载到显存平均需要40秒,集群自动扩容时新Pod起来之后,HealthCheck 如果设置得太短,流量会直接打到还在加载模型的 Pod 上,返回一堆超时错误。这个需要在探针里设置足够的启动时间,并且配合就绪探针等待模型加载完成后再放流量。踩过这个坑之后,我在所有推理服务的启动脚本里都加了模型加载完成的标志位检测,就绪探针只检查这个标志位,不再简单检查端口通不通。
4. 流量调度与故障切换:多地域不能只靠DNS
多地域架构搭起来之后,跨地域的流量调度和故障自动切换才是日常运维的重头戏。很多人以为配好全局负载均衡就万事大吉,实际远没有那么简单。
4.1 全局流量调度的三层设计
我们最终把流量调度分成了三层。
第一层是 DNS 层,负责把用户解析到最近的地域。这个依赖全局负载均衡器维护的地理位置库,以及各个地域入口的健康状态。如果某个地域的健康检查失败,GSLB 会把该地域的解析权重降为0,用户的解析结果自动落到其他地域。这里注意 DNS 的 TTL 不能设置太长,否则故障切换后客户端还是照着旧IP去访问,切换时间就被拉长了。我们现在 TTL 设置的是60秒,切换生效比较快,代价是 DNS 解析请求量变大,但用云厂商提供的解析服务基本扛得住。
第二层是网关层,负责地域内的路由。API网关接收到请求后,根据用户地理位置和当前地域的负载情况,决定是否转发到其他地域。比如一个华东用户的请求落到华北入口,网关解析出用户真实地域后,直接把请求转发回华东网关,或者在本华北地域内消化。定期调整转发策略很有效,能避免 DNS缓存导致的地域错配。
第三层是应用层,也就是服务之间的调用。跨地域调用要尽量避免,因为每跨一次地域就增加几十毫秒延迟,链路一长整个接口就废了。我们在 Istio 里配置了虚拟服务,限制服务默认只在本地域解析,只有部分需要主地域支撑的写请求才显式路由到主地域。
4.2 故障切换的判定与演练
故障切换是这套系统里最需要谨慎设计的环节。切换太快可能误判,切换太慢又起不到容灾作用。
我们定义了明确的判定规则:一个地域在1分钟内健康检查失败率超过80%,或者在30秒内全部入口不可达,才判定该地域故障,触发切换。同时设置了“手动确认”步骤,如果切换脚本检测到故障,会先发告警给值班人员,等待10分钟的人工确认,超时未确认才自动切换。这样既避免大规模故障时人工反应慢,也避免偶发抖动触发误切。
切换演练必须定期做。我们每季度做一次全流程的容灾演练,把华北地域的入口全部摘掉,观察华东和华南能不能正常承接全部流量。第一次演练暴露了不少问题,比如华东的数据库只读副本数据延迟过高,切过去之后用户看到的数据不完整;再比如推理服务的弹性伸缩策略只配置了单地域,流量突然翻倍后,华东的GPU节点不够用,新请求大量排队。这些问题都是在真实演练里才发现和修复的,纸上谈兵根本看不出来。
演练之后的复盘也重要。我们每次演练都会列一份检查清单,从网络连通性、数据库同步位点、消息队列积压、推理质量指标到下游计费对账,逐项确认。复盘出的问题会排进下一个迭代,避免同样的问题在真实故障中出现。
4.3 多地域监控与问题追踪
多地域环境下的监控和日志比单地域复杂得多。最基础的是每个地域的 Prometheus 都要部署一套,然后通过联邦方式把数据汇聚到中心的 Grafana,或者直接用 Thanos 做全局视图。如果只是各看各的,跨地域排查一个问题得来回切好几个面板,效率太低。
日志方面我们建立了统一的日志采集平台,所有地域的应用日志都通过 Fluent Bit 采集到中心化的日志系统里,并且自动打上地域标签。查询的时候直接按地域过滤。这样当用户反馈一个问题,我可以先确认他落在哪个地域入口,再按地域查日志,几分钟就能定位到是哪一层出了问题。
链路追踪必不可少。我们接入的是 Jaeger,每个请求都会生成一个全局唯一的 TraceID,跨地域调用的 Span 会集中上报。多地域的请求只要带上 TraceID,就能端到端串起来看耗时分布。比如用户反馈接口延迟3秒,打开链路追踪会发现,网络只占200毫秒,真正耗时在某个地域的模型推理,或者是跨地域数据库写入等待上。没有这套追踪工具,多地域的联调排查基本靠猜。
还有一个细节:多地域的告警阈值不能完全一致。华东的业务量大,延迟P99稍微高一些是正常的,如果和华北用同一个阈值,就会产生大量误报警。我们把每个地域的核心指标单独设置基线,再结合全局指标做整体判断,报警准确率明显提升。
5. 常见问题与避坑实录
最后这部分是我个人最想写的。这套系统从开始改造到稳定运行,中间踩了不少坑,很多问题在书本上根本找不到标准答案,只能靠现场排查和反复验证。我整理几个最典型的,给后来者排雷。
5.1 数据不一致比宕机更可怕
跨地域部署之后,数据一致性问题浮出水面。我们最大的教训是:不要对跨地域数据同步的时效性过于乐观。内网延迟再低,跨地域同步也是异步的,主地域写入完成之后,副本地域要经过几十毫秒到几秒才能追平。用户如果在主地域写完数据马上切到另一个地域读取,就可能读到旧数据。
我们处理这个问题分了两步走。第一步,在网关层做写入路由,写请求固定进主地域,保证写进去就成功;第二步,在应用层做读取兜底,如果读取的副本数据同步位点滞后超过阈值,就回源到主地域读一次,保证关键数据的读取一致性。虽然多一次跨地域请求,但对那些绝对不能读旧数据的接口来说值得。
另一个容易踩的坑是自增主键在双写场景下的冲突。如果两个地域都能写入同一条业务表,MySQL自增ID一定会撞车。我们虽然只让主地域处理写请求,但后面为了某个区域业务做独立的写入口时,就遇到了这种问题。最终解决方式是换成分布式ID方案,用雪花算法生成全局唯一ID,数据库主键从自增改为业务ID。这个改造要趁早做,晚了数据量大了迁移成本非常高。
5.2 域名、证书与合规问题的坑
多地域部署意味着服务域名和证书的复杂度翻倍。最典型的是 HTTPS 证书:不同地域可以用同一套域名,但需要保证证书在各地域都能正确部署和更新。我们用证书管理器做自动签发和续期,每个地域集群里的证书管理者会各自向 CA 申请,避免跨地域获取证书的延迟和失败风险。
DNS 解析还有一个容易被忽略的问题:不同地区的网络环境不一样,某些地域的 DNS 服务可能不支持你使用的解析记录类型。如果涉及跨境部署,这个问题更常见,但我们正常国内跨地域场景偶尔也会遇到。所以 DNS 配置做好之后,一定要用第三方拨测工具多地区验证一遍,确认解析结果确实到了预期地域。
合规方面,我建议在数据存储位置设计上留出弹性。不同业务对数据驻留要求不同,多地域部署时要提前考虑“哪些数据只能存在哪个地域”“哪些数据绝对不能跨境传输”。这直接影响数据同步链路的设计,如果一开始没考虑,后面再加限制会很痛苦。因为我们这里主要讲技术实操,合规细节就不展开了,但架构层面留出这个意识很重要。
5.3 资源成本控制:不该全部多活的不要多活
多地域部署的最直接后果就是成本上升。每个地域都要养一套基础设施,GPU资源的成本尤其高,如果所有业务都做多活,账单会非常难看。
我们在后期做了一个重要调整:把业务分为“双活业务”和“主备业务”。对用户主流程、核心推理接口这些,全部地域双活;对后台报表、模型离线训练、日志分析这些,只在主地域跑。备份地域只在故障切换时启用,平时处于冷备状态。这个策略让成本下降了一截,但容灾能力并没有损失太多。
另外,对象存储跨地域复制的成本也要关注。模型文件、数据集动辄几十GB,跨地域复制流量是按流量计费的。我们通过压缩和定期清理无用模型版本,把复制流量降下来了。这里也可以用“按需拉取”取代全量复制,某些冷门模型文件不在启动时同步,而是在推理服务第一次需要时从主地域拉取,配合缓存机制能省不少钱。
5.4 一些从实战里摸出来的细节
再分享几个零散的经验,虽然不系统,但每一个都是真金白银换来的。
GPU 驱动的版本管理一定要跨地域统一。不同地域的节点如果是不同批次采购的,GPU驱动很容易出现版本不一致,导致同一个推理镜像在华北跑得好好的,在华东却报 CUDA 版本不匹配。我们把节点驱动版本纳入配置中心统一管理,新节点上线时必须先做驱动检查,不合格的不允许加入调度。
推理服务的队列长度和并发数需要分地域调参。单地域时一套参数走天下,多地域后每个地域的流量模型不完全一样,盲目用相同参数会导致有的地域资源浪费、有的地域排队。我们针对每个地域单独压测后调整了并发参数,整体吞吐提升了大约20%。
多地域的配置变更要先灰度。以前改一个系统参数,全局发布就行。多地域之后,任何一个配置变更都建议先在一个地域验证,再逐步推到其他地域。我们遇到过推送配置时把某个地域的GPU推理超时时间改得太短,结果该地域频繁超时的线上事故,教训很深。后来所有配置变更都带地域维度灰度开关和回滚方案。
写在最后
从单地域到多地域的这场改造,前后花了大概三个月时间,涉及网络、数据、业务、推理、监控几乎全链路。回头来看,技术选型本身不是最大的挑战,最大的难点在于一致性保障、流量调度和故障场景的持续演练。AI系统相比普通业务系统,多了一个模型分发和GPU资源调度的维度,而这两块恰恰是很多通用教程不会讲到的。如果让我给正在规划多地域的团队一条最实用的建议,那就是:先盘清楚自己的业务到底需要什么级别的可用性,再决定架构复杂度;不要让多地域变成一种炫技,而是让它在真实的延迟降低和容灾能力上体现出价值。首次灰度发布的时候,我盯着全局监控看了一整晚,那种紧张和兴奋,做过的人应该都懂。希望这篇实战记录能帮你少走一些弯路。
