异地多活架构的核心难点是什么?
简化版
异地多活最难的不是部署多套应用,而是控制跨地域写冲突、稳定路由数据归属、处理网络分区、保证故障后容量,并完成安全切换与回切。 实践通常优先采用单元化和每份数据单写归属,跨地域异步复制;只有业务能合并冲突时才做真正多主写。
详细版
广域 RTT 高且网络会分区,跨地域强同步会抬高写延迟并在丢多数时拒写;异步复制延迟低,却产生 RPO 和冲突窗口。设计要为每类数据选择单主、分区单主、共识或 CRDT/业务合并,而不是全站统一模型。
路由以 user/tenant/shard 的稳定归属为核心,标签沿调用链传播,确保请求、缓存、消息和数据库都留在同一 cell。故障转移必须提升 ownership epoch 并 fencing 旧站,目标站还要有 N-1 容量。恢复后回补、对账与 Failback 是独立流程。
完整版教学
一、“多套部署”为什么不等于多活
如果 B 地域只有机器却没有生产流量,它是灾备;如果请求到 B 仍同步访问 A 的唯一数据库,A 故障时 B 也不可用。多活要求流量、数据和关键依赖都能在多个故障域独立工作,而不是只复制应用层。
记忆钩子:多活要问三遍——流量是否活、数据是否活、依赖是否活。
二、广域网络改变一致性选择
北京到上海 RTT 假设 30ms,一次跨地域多数派写至少引入额外网络往返,P99 还会更高。若选择本地提交后异步复制,正常写快,但北京刚成功的订单在上海可能晚 2 秒可见。网络分区时不可能同时保证任意一侧可写和同一数据强一致。
| 模型 | 正常延迟 | 分区行为 | 冲突风险 |
|---|---|---|---|
| 跨域共识 | 高 | 少数侧拒写 | 低 |
| 每分区单主 | 本地低 | 转移所有权后写 | 可控 |
| 异步多主 | 本地低 | 两侧继续写 | 高,需合并 |
三、单元化与数据归属
按 tenantId 哈希到 cell,每个 cell 在一个地域拥有写主,应用、缓存、消息和数据形成闭环。用户请求先查归属再路由,跨地域只做复制或必要调用。这样把跨域一致性问题缩小到所有权迁移,而不是每次写都协调全球。
tenant A -> cell-east (write owner epoch=18)
tenant B -> cell-south (write owner epoch=27)
四、全局业务与冲突处理
全局唯一库存、余额等不可随意多主,可选择单主归属或共识;点赞、浏览计数等可交换数据可分区累加再合并;用户资料并发编辑则需要版本向量、字段级合并或人工决策。LWW 简单但会受时钟偏差并丢掉并发写。
业务必须明确冲突概率、检测证据和最大收敛时间,不能把“最终一致”当作无需处理冲突。
五、故障转移和容量
地域失效时,控制面先 fencing 旧 owner,再提升新地域 epoch,追平到目标 RPO 后切流。三个地域各承载 1/3 流量,失去一个后其余各约增至 1/2,相对原负载增加 50%;应用、数据库和带宽都要有这部分余量。
缓存命中下降会放大回源,第三方白名单和密钥也要预置。只有计算容量富余而数据层满载,多活仍无法接管。
六、全局控制面与观测
归属目录、GSLB 和配置平台是潜在全局单点。数据面应缓存带版本的最后有效归属,并通过 epoch 防旧路由写错;控制面故障时避免全站同步查询。跨地域 Trace、业务流水和数据对账用于定位串线与复制缺口。
监控每地域 SLO、复制 lag、跨域调用、ownership 冲突、写错地域拒绝、剩余容量和真实 RPO/RTO。定期拔掉一个地域做演练,才能验证所有隐藏依赖。
七、常见误区与追问
- 误区:部署三个地域就是三地多活。 仍可能共享单一数据库或控制面。
- 误区:多主写能让 RPO 永远为零。 并发冲突可能无法无损合并。
- 误区:最终一致会自动收敛到正确结果。 必须定义版本、合并和对账。
- 误区:每地域各 33% 就有接管容量。 还要验证失去一地后其余层级容量。
- 追问:为什么优先分区单主? 本地写延迟低且避免同一数据并发冲突,复杂度更可控。
- 追问:全局 ID 怎么办? 使用地域位/号段或协调方案,但唯一 ID 不等于业务状态无冲突。
- 追问:怎样发现流量串 Cell? 传播归属标签,并监控写 owner epoch 与跨域依赖。
八、加强记忆
异地多活的主线是“数据归属、稳定路由、网络分区、冲突语义、接管容量、可逆切换”。优先让每份数据只有一个写 owner,用 epoch 和 fencing 安全迁移;必须多写的数据才设计合并。最后用整地域演练证明应用、数据和依赖都真正能活。
多活成本还包括跨地域带宽、数据驻留合规和统一发布协调,不能只按多部署几套机器估算。
若某个全局依赖仍只能单地域写,整体架构的可用性上限依然受它约束,应把它显式标为多活链路中的例外。