异地多活
When to Invoke
明确要跨城同时写、机房级容灾且 RTO 接近 0、面试追问多活。文旅默认 先同城多 AZ,不要一上来多活。
When NOT
普通高可用、备份、主从 → ha-dr。多活比容灾贵一个数量级(冲突、数据同步、路由)。
风险(面试考点)
灾备:异地冷/热备,切过去才服务,RTO/RPO 较大。
多活:多个城市 同时 接流量。难点是 写冲突 和 会话路由。
没有单元化(按 user_id 固定落到一个单元)就会双写同一订单。跨单元查询(全国排行、商户看所有门店)会变难。时钟、延迟、分区(脑裂)都要预案。
微信红包一类是单元化 + 尽量不跨单元写。不是「两个机房随便写同一行再 last-write-wins」。
方案选型(轻量优先)
| 优先级 | 方案 |
|---|---|
| 1 | 单城多 AZ + 异地备份(默认) |
| 2 | 同城双活(距离短、同步复制可接受) |
| 3 | 异地单元化多活:用户/商户哈希到单元,写不跨单元 |
| 禁止默认 | 多城对同一主键同时写 + 无冲突规则 |
默认方案
单元键与分片键类似:不可变、查询总带着(user_id 或 merchant_id)。DNS/网关按单元路由。跨单元只走异步消息,接受延迟。全局唯一 ID 带单元号,避免冲突。
资金类:支付渠道本身有区域限制时,更不要假装全球同一钱包双活。
反例
错误:两个机房都连同一主库叫多活。 正确:那是计算多活、存储仍单点。
错误:冲突用「谁新谁赢」覆盖支付状态。 正确:资金状态机,不允许无序覆盖。
错误:没单元化就上异地双写。 正确:先单元化。
验证
- 单用户请求稳定落到同一单元。
- 一城宕机,该城用户有预案(切换或降级),他城用户不受影响。
- 没有跨城同步改同一余额行。
评审清单
- 是否其实 ha-dr 就够
- 有单元键且写不跨单元
- 资金冲突规则不是 last-write-wins