CHAPTER 01

什么是异地多活

一句话:在多个地理区域同时部署业务系统,每个区域都能独立、完整地对外提供服务(可读可写、能扛流量)。一个区域挂了,其他区域能立刻顶上,用户几乎无感知。

🌍

异地

地理位置足够远(通常跨城市、>100km),使它们不会同时遭遇同一灾害:光缆被挖断、断电、地震、洪水。

北京上海深圳
🔢

多

至少 2 个及以上区域同时运行。区别于"主 + 备份"的单点结构,多活没有永远闲置的备。

≥ 2 个 Region
⚡

活

每个单元都是"活的"——平时就在接流量,而非出事才启用。这是和冷备/热备最本质的区别。

平时就在跑
关键区分:异地多活 ≠ 多地备份。备份是"数据多份存",多活是"业务多份跑"。多活里每个区域都是生产环境,都在产生价值(承接真实流量)。
❌ 主备(单活)

一个主、一个备

平时只有主机房接流量,备机房空转等故障。主机房宕机后,需手动/半自动切换,期间业务中断(RTO 分钟~小时级)。

备机资源浪费切换有中断
VS
✅ 异地多活

多区域同时接流量

每个区域都正常服务用户。某区域故障,流量被路由到其他区域,用户几乎无感知,RTO 趋近于秒级。

资源都利用故障无缝
CHAPTER 02

为什么需要异地多活

单机房再强,也扛不住"物理世界"的意外。多活是把"业务连续性"从概率事件变成确定性能力。

🛡️

容灾兜底

机房断电、光缆被挖断、自然灾害……单机房是单点。多活让"一个城市没了"也不影响全局。

⚡

就近接入降延迟

北京用户访问北京region,深圳用户访问深圳region,跨城几十~上百ms的延迟被省掉,体验更好。

📈

突破单机房上限

单机房电力、机柜、配额、带宽都有天花板。多活横向铺开,总容量不再是瓶颈。

⚖️

合规与属地化

某些数据法规要求"数据不出省/国"。多活可在合规地域部署对应单元,满足数据驻留要求。

真实教训:历史上多次大型故障源于"单机房 + 主备切换慢"——光缆被施工挖断导致整城市服务不可用、切换耗时过长引发大面积超时。异地多活就是为这类"城市级灾难"而生的。
CHAPTER 03

容易混淆的概念辨析

同城双活、异地多活、冷备、热备、两地三中心、单元化……这些词经常被混用,先理清边界。

概念距离备是否接流量故障时典型 RTO
冷备任意否(停机待命)需启动+恢复,中断久小时级
热备同城居多数据同步但不接流量切换较快,仍有中断分钟级
同城双活<50km是几乎无缝秒级
异地多活>100km(跨城)是几乎无缝秒级
两地三中心同城+异地同城活/异地备或活同城优先,异地兜底秒~分钟
多活 ≠ 多副本:多副本(主从复制、3 副本)解决的是存储层的高可用;多活解决的是业务层都能接流量。一个 MySQL 一主两从,从库只读,那它不是"多活"——只是"高可用副本"。真正的多活,每个 region 的应用都能写。
🧩

单元化(Cell)

按用户维度(如 user_id 哈希)把业务切成自包含的小单元,每个单元部署在固定 region,请求在该单元内闭环。这是多活最主流的落地姿势。

📐

RTO / RPO

RTO=恢复时间目标(中断多久);RPO=恢复点目标(最多丢多少数据)。多活追求 RTO 秒级、RPO 接近 0。

CHAPTER 04

典型架构长什么样

多个 region 各自有完整链路(接入→应用→存储),GSLB 做 DNS 级分流,region 之间通过数据同步保持最终一致。

👤 用户 GSLB 就近分流 Region 北京 接入 应用 DB 完整链路 · 接流量 Region 上海 接入 应用 DB 完整链路 · 接流量 Region 深圳 完整链路 · 接流量 数据同步

每个 Region 都是一套完整的接入+应用+存储,平时都在接流量;红色虚线表示 region 之间的异步数据同步。

🧭

流量调度

GSLB(基于 DNS 的全局负载均衡)按用户地理位置/运营商把请求导到最近 region;细粒度可结合 HTTPDNS、应用层路由。

🔄

数据同步

MySQL 跨城主从/双向复制、Redis 跨城同步、消息队列跨城投递。一般异步、最终一致,避免跨城强一致拖慢主链路。

🪧

单元化路由

按 user_id 把用户固定到某 region(单元),其读写尽量在本 region 闭环,跨城同步只发生在必要场景。

CHAPTER 05

最难的一环:数据一致性

多活最头疼的是"多个 region 都能写,怎么不冲突、不丢数据"。核心矛盾:跨城网络延迟 vs 一致性要求。

物理约束:北京到上海光纤往返约 30~50ms,到更远城市更高。若要求"跨城强一致"(写必须等所有 region 确认),每次写请求都要付这笔延迟,主链路会被拖垮。所以跨城多活几乎必然走 AP + 最终一致(CAP 里分区容错 P 必须保,只能牺牲强一致 C)。
方案思路一致性适用
全局单写某数据只在固定 region 写,其他 region 异步复制只读最终一致全局配置、库存中心
单元化单写按 user_id 分片,每片只在自己 region 写单元内强一致、跨单元最终一致交易、账户(最主流)
多写 + 冲突解决各 region 可写,靠版本号/CRDT/业务规则合并最终一致可合并的弱序数据
跨城同步复制写需等异地确认(半同步)接近强一致金融强一致场景(牺牲延迟)
单元化是破局关键:把"大部分请求在本地闭环"作为设计目标——让一次用户操作涉及的多个写都落在同一个 region 的同一个单元里,跨城同步只在"跨单元交互"(如转账给异地用户)时发生。这样90%+ 的请求不受跨城延迟影响,一致性问题被隔离在小范围内。
CHAPTER 06

容灾与切换

多活不是"部署完就高枕无忧",真正考验的是故障时的发现、决策、切流能力。

📡

故障检测

健康探针、拨测、黄金指标(延迟/错误率/QPS)异常告警。误判会导致"误切流",需防抖。

🔀

流量切流

调整 GSLB 权重/解析,把故障 region 的流量逐步导走。支持按比例灰度切,避免雪崩。

🧠

脑裂防护

网络分区时两 region 都以为对方挂了、各自"升主"导致双写冲突。需租约/仲裁(quorum)机制防脑裂。

💥

常态化演练

红蓝对抗、混沌工程注入机房故障,验证切换链路真的有效。不演练的多活=纸面多活。

体验闭环:许多团队把"切流"做成一键按钮 + 审批流,配合定期真实演练(如主动摘掉一个机房),才能确保真出事时 RTO 达标。
CHAPTER 07

单元化设计实战

单元化是异地多活最主流、也最落地的实现方式。下面用一个路由演示直观感受。

请输入 user_id 后点击按钮。规则:user_id % 3 → 0=北京 / 1=上海 / 2=深圳(演示用,真实按 region 数与哈希策略)。
✂️

按维度切分

用 user_id(或租户id、订单id)做分片键。同一用户的全部数据落在同一单元,读写闭环。

🌐

全局 vs 单元数据

单元数据(用户资料、订单)本地闭环;全局数据(商品目录、汇率)走单写+广播。

🔁

跨单元交互

转账给异地用户 = 跨单元。需异步对账/补偿(Saga、消息最终一致),不能卡住主链路。

前置条件:单元化要求服务无状态(见《数据与状态分离》)、数据可水平分片、写操作幂等。这也是为什么多活往往伴随着一整套架构改造,而不是"加个机房"。
CHAPTER 08

难点与代价(避坑)

异地多活很香,但很贵也很难。先想清楚值不值得,再动手。

💰

成本翻倍

每多一个活 region,就是一整套计算+存储+带宽。平时都在跑,没有"备机省钱"这回事。

🧩

一致性复杂

冲突检测、补偿、对账、幂等……分布式一致性工程量是多活的主要技术债。

🔧

业务改造大

要去状态、要分片、要幂等、要梳理全局/单元数据。老系统改造成本可能超过重建。

🚨

运维门槛高

跨城网络、时钟漂移、切流决策、脑裂处理……对团队 SRE 能力要求极高。

不是所有业务都要多活:内部后台、离线分析、对中断不敏感的系统,用"主备 + 定期演练"往往更划算。多活应优先投在核心、高可用要求极高的用户面业务(支付、交易、IM、登录)。
CHAPTER 09

总结与决策清单

一句话记住:异地多活 = 多个城市都跑着完整业务,平时就接流量,挂一个其他顶上。

你的处境建议
单机房、能接受分钟级中断主备 + 定期切换演练即可,不必上多活
核心业务、RTO 要求秒级、怕城市级灾难上异地多活,优先单元化
用户分散全国、延迟敏感多活 + 就近接入(GSLB)双重收益
数据有属地化合规要求按地域部署合规单元
团队 SRE/分布式经验不足谨慎,先补"主备演练"再考虑多活
落地路线图:① 服务无状态化 → ② 数据可水平分片 + 幂等 → ③ 按 user_id 单元化路由 → ④ 跨城异步同步 + 冲突/补偿机制 → ⑤ GSLB 就近接入 → ⑥ 故障检测 + 一键切流 + 常态化混沌演练。一步步来,别想一步到位。