单个机房承载全部流量,一旦机房故障业务就会完全中断,因此越来越多团队选择多机房部署架构。但Redis作为内存数据库,天生不具备跨机房自动同步的能力,数据一旦写到A机房的Redis实例,B机房的Redis是看不到的。如果两地都在跑读写业务,缓存不一致的问题马上就会出现:用户在A机房修改了昵称,请求被负载均衡到B机房时读到的还是旧数据。要解决这个问题,就必须设计一套可靠的跨机房同步方案。下面我们从几个常见思路入手,逐一分析它们的实现方式和适用场景。

方案一:主从复制直接跨机房同步
最直观的思路是利用Redis自带的主从复制机制,把A机房设为主节点,B机房部署从节点,从节点通过replicaof命令指向主节点。数据写入主节点后,会通过 replication stream 异步推送到从节点。这种方式的优点是实现成本几乎为零,不需要额外的中间件,运维心智负担小。
但它的问题也很突出。首先是延迟问题,机房之间的网络往返时间通常在几毫秒到几十毫秒,主从复制是异步的,跨机房链路一旦抖动,从节点的数据滞后会明显加大,读到的脏数据概率随之上升。其次是可用性问题,从节点默认是只读的,跨机房客户端对从节点的读请求要绕回主机房的话,等于多机房部署形同虚设。最严重的是脑裂风险:如果主从之间链路中断,B机房的从节点被误提升为主节点,两边各自接收写入,网络恢复后数据就会冲突丢失。
# 在B机房的从节点上执行 redis-cli replicaof 10.0.1.100 6379 # 查看复制状态 redis-cli info replication
如果一定要用这种方案,建议从节点只做同城灾备,不承接写流量,并且部署哨兵集群时把仲裁节点放在第三个机房,避免单边判断导致误切换。跨城市场景下,这种纯主从架构一般只适合对一致性要求不高、读多写少的业务。
方案二:客户端双写与消息队列异步同步
第二种思路是不依赖Redis自身的复制能力,由应用层来承担同步职责。客户端双写是指业务代码在写A机房Redis成功后,再异步写一次B机房,通常配合线程池或消息队列把第二次写操作变成非阻塞的。这种方式灵活性最高,可以做到只同步部分热点key,也可以针对不同key设置不同的同步策略,带宽成本可控。
// 伪代码:双写示例
public void cachePut(String key, String value) {
redisA.setex(key, 3600, value); // 写本机房
mqProducer.send("sync-topic", key + "|" + value); // 异步同步到对端
}双写的核心难点在于失败处理。如果写A成功、写B失败,两边数据就不一致了,是重试、记录补偿日志,还是允许最终不一致,需要业务方明确决策。引入消息队列可以缓解这个问题:写操作先落消息队列,两边机房的消费程序各自订阅并写入本地Redis,消息队列的重试和持久化机制天然提供了可靠性保障。Kafka、RocketMQ都支持跨机房镜像队列,配合消费位点管理,基本可以做到秒级最终一致。
这种方案的代价是侵入性强,所有写缓存的地方都要改造,遗漏一处就是一致性漏洞。另外消息队列本身也成为需要跨机房同步的组件,架构复杂度上升了一个量级。它更适合key数量可控、写入路径集中的业务,比如配置中心、用户维度的热点数据。
方案三:redis-shake与CRDT类专用同步工具
对于存量数据迁移或者持续性同步需求,阿里开源的redis-shake是使用最广泛的工具之一。它支持sync模式,可以模拟成一个从节点连上源Redis,读取增量数据流后写到目标机房,同时也支持全量恢复和RDB文件迁移。redis-shake基于Go实现,部署简单,支持断点续传,适合做机房搬迁、双机房热备搭建这类场景。
# redis-shake同步配置示例(toms shake.toml) type = "sync" [source] address = "10.0.1.100:6379" password = "源机房密码" [target] address = "10.2.1.100:6379" password = "目标机房密码" # 启动同步 ./redis-shake shake.toml
如果目标是真正的多活架构,即两边机房都能读写且数据自动双向合并,可以关注基于CRDT冲突解决的数据结构。Redis官方的Redis Enterprise提供了CRDT版本的String、Hash、Set等类型,写入会在多实例间自动同步,冲突通过最后写入时间戳等策略收敛。开源社区也有一些双向同步代理的实现思路,即拦截两边写命令,通过转换通道互发并解决冲突,但自研成本高,需要处理幂等、乱序、删除同步等一系列边界问题,没有深厚中间件积累的团队不建议轻易尝试。
机房断网与脑裂场景的处理建议
无论选择哪种同步方案,都必须提前设计断网时的行为。机房间链路中断后,最危险的操作是两边各自提升为主并继续接受写入。比较稳妥的策略是引入第三方仲裁:部署一个独立的探测服务或利用共识组件判断哪边是多数派,少数派一侧自动进入只读状态。对于双写方案,可以在消息队列同步链路中断时把本地写操作降级写入日志文件,待链路恢复后再补偿重放。
另一个实践细节是数据校验。跨机房同步链路长期运行后,难免出现静默丢失,建议定期用抽样比对或校验工具对两边key的分布和值做一致性检查,发现漂移及时触发重同步。同时监控指标里一定要加上复制延迟积压(master_repl_offset与slave_repl_offset的差值)和同步通道的队列堆积,在故障扩大前发出告警。
总结一下选择思路:灾备为主选主从复制加哨兵,改造能力强且key可控选双写加消息队列,一次性迁移选redis-shake,真双活多写则要评估CRDT或商业方案。架构没有银弹,结合业务对一致性和成本的容忍度做取舍,才是跨机房同步方案落地的关键。
Redis跨机房同步Redis主从复制数据一致性修改时间:2026-09-03 05:12:40