跨云多活是近年来大型互联网公司在架构演进中频繁采用的模式。它的目标很明确:让业务同时运行在两家甚至多家云厂商的环境里,任何一家云出现故障,流量可以在短时间内切换到其他云,用户几乎无感知。但要真正做到这一点,难点不在应用层,而在数据层。服务本身是无状态的,复制多少份都容易,而数据库、缓存、消息队列这些有状态组件,如何在跨公网、跨厂商网络环境下保持数据一致,才是整个架构的核心命题。本文将从架构模式、数据同步、流量调度、容灾演练几个维度,系统性地讨论跨云多活的设计要点。

跨云多活的三种典型架构模式
在设计跨云多活之前,首先要明确业务适合哪种模式。常见的模式有三种:主备模式、不对称多活和对称多活。主备模式是最简单的形态,A云作为主机房承载全部流量,B云只部署核心链路的冷备或热备资源,平时不提供服务,故障时切换。这种模式成本最低,但切换时RTO通常在分钟级,而且备库长期不承接真实流量,切换那一刻的风险不可控。
不对称多活是指每个云都承接流量,但按照业务维度做切分。比如按用户地域划分,华东用户请求落到A云,华南用户请求落到B云,各自云内闭环处理自己的数据,只有少量跨云数据需要同步。这种模式的跨云数据同步压力小,是大多数业务的首选起点。它的代价是需要在入口层做精准的分片路由,一旦某个云故障,需要把它负责的分片流量接管到另一个云,此时跨云数据访问的问题就会暴露出来。
对称多活是最理想的形态,任何一笔写请求落在任何一个云都能正确处理,数据全局强一致或最终一致。这种模式对数据同步的要求极高,实现成本大,一般只有核心交易类业务才会考虑。实际工程中,大部分公司采取的是混合策略:核心交易链路按用户维度分片做不对称多活,非核心链路如查询、报表做全局只读副本,兼顾成本与可靠性。
数据同步方案的设计与冲突处理
数据同步是跨云多活的灵魂。以MySQL为例,跨云同步通常基于binlog做复制,常用工具包括Otter、Canal加自研消费端,或者直接使用云厂商提供的DTS服务。同步链路一般采用双向回环设计:A云的变更同步到B云,B云的变更同步到A云。这里必须解决回环问题,即A云的数据变更同步到B云后,B云再次产生的binlog不能再回传给A云,否则会造成无限循环复制。常见的处理方式是在同步工具中记录数据来源标记,Otter通过select和cannel管道配合,在同步时写入源库的事务标识,回传时自动跳过来自对端的数据。
双向同步必然带来冲突问题。同一行数据在A云和B云同时被修改,以谁为准?业界主流的做法有三类。第一种是时间戳仲裁,每行数据带上最后修改时间,冲突时取时间新的为准,实现简单但依赖两边的时钟精度,跨云环境下时钟偏差可能达到百毫秒级别,需要部署NTP或PTP做时钟校准。第二种是以特定机房为准,比如用户所属分片对应的云拥有仲裁权,其他云的写入在冲突时被丢弃或重放。第三种是通过分布式锁或全局序列化,把同一行数据的写入强制路由到同一个云处理,从源头消灭冲突,这其实是把异步同步变成了同步写,性能损耗较大。
除了数据库,消息队列的跨云互通也值得关注。Kafka本身不支持跨集群复制,通常用MirrorMaker 2做双向镜像,但要注意topic的自动创建策略和offset映射。更稳妥的做法是应用层双写:同一个业务事件同时发送到两个云的Kafka集群,各自云的消费者只消费本云消息,这样避免了镜像链路的顺序问题和重复消费问题,代价是业务代码要做一定的封装。下面是一个基于Canal的同步链路配置示意:
// 消费Canal推送的binlog变更事件
public void onBinlogEvent(CanalEntry.Entry entry) {
// 过滤掉来自对端云的同步写入,防止回环复制
if (isFromRemoteSync(entry)) {
return;
}
RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
for (RowData rowData : rowChange.getRowDatasList()) {
// 跨公网传输前压缩,降低带宽成本
byte[] payload = compress(rowData.toByteArray());
// 通过专线或加速通道发送到对端云的接收服务
syncClient.send(entry.getHeader().getTableName(), payload);
}
}上面这段代码展示了回环过滤的关键位置。实际生产中,回环判断通常依据同步账号的特有标记或事务注释(比如在事务中写入特定的hint),接收端写入时也使用专用账号,消费端看到该账号产生的变更就直接跳过,这个细节是双向同步能否稳定运行的生命线。
流量调度、网络与容灾能力建设
架构设计得再好,没有配套的流量调度体系也无法发挥作用。跨云多活的入口层一般采用智能DNS加HTTP DNS双通道,DNS负责粗粒度调度,HTTP DNS在客户端内置,可以做到秒级生效的精确调度。调度策略要与健康检查联动:每个云的全业务链路探活结果实时上报到调度中心,一旦某个云的核心接口成功率跌破阈值,调度中心自动把该云的权重降为零,流量全部导向健康云。要注意DNS本身存在缓存 TTL 的问题,跨云切换场景建议TTL设置在30秒以内,并且关键客户端直接使用HTTP DNS绕过运营商解析。
网络层面,跨云互联有三种方式:公网加密传输、专线接入和云厂商间的高速通道。公网方案成本最低但延迟和稳定性最差,适合同步非核心数据;专线带宽稳定、延迟可控,是数据库同步的首选,但费用高昂;高速通道介于两者之间。经验做法是数据库同步走专线,消息和缓存失效通知走公网加密通道,并且所有同步链路都要内置断点续传能力,网络抖动恢复后能自动补齐增量数据。
最后一块拼图是容灾演练。多活架构最大的风险是长期不切换,一旦真故障来临,才发现数据不一致或切换脚本失效。成熟的团队会定期做两类演练:一是计划内切换,每季度选择低峰期把某个云的流量全部切走,验证数据一致性和业务无损;二是故障注入,主动断开跨云同步链路,观察系统的脑裂保护和数据补偿机制是否符合预期。演练后必须做数据比对,用全量校验工具扫描两个云的数据差异,差异行数要控制在可解释的范围内。只有把演练常态化,跨云多活才不是一纸架构图,而是真正经得起故障考验的生产能力。