Redis 主从复制:全量同步、命令传播和增量复制怎么串起来
Redis 高可用与主从复制章节,讲清主从库读写分离、第一次全量复制、正常运行时的命令传播、断线重连后的增量复制,以及为什么全量同步通常使用 RDB。
相关工具
主从复制解决的不是单机恢复
上一篇讲持久化,重点是 Redis 重启后如何从磁盘恢复数据。主从复制解决的是另一件事:一台 Redis 不够稳,也不一定扛得住所有读请求,所以要把主库的数据复制到从库。资料 在高可用章节里先讲主从库模式,核心是保证数据副本一致,并采用读写分离。
读写分离的规则很清楚:读操作可以到主库,也可以到从库;写操作先到主库执行,然后主库把写操作同步给从库。这样做以后,从库可以分担一部分读压力,主库故障时也有数据副本作为后续故障转移的基础。
不过主从复制不是把数据简单复制一份就结束。真正要理解它,得分三段看:第一次建立关系时的全量复制,正常运行时的命令传播,断线重连后的增量复制。三段连起来,才是 Redis 主从同步的完整故事。

第一次同步走全量复制,正常运行靠长连接命令传播,从库断线重连后尽量走增量复制;如果复制积压缓冲区不够,就退回全量复制。
主库和从库各自做什么
主从复制里,一个 Redis 服务器被视为主节点 master,其他服务器作为从节点 replica。文中的描述是:主服务器可以进行读写操作,发生写操作时,会自动把写命令同步给从服务器;从服务器一般只读,并接收主服务器同步过来的写操作命令,然后执行这些命令。
这里要抓住两个关键词:主库写,从库跟。客户端写入主库后,主库先把命令执行掉,再把同样的写命令传播给从库。从库执行命令后,数据状态就向主库靠齐。它不是共享同一块内存,也不是从库直接读主库文件,而是通过复制协议把数据变化同步过去。
在业务架构上,主从复制常被放在缓存层的基础设施里。读多写少的系统可以把部分读请求打到从库,主库承接写请求和复制源头。这样读能力更容易扩展,也为后面的哨兵故障转移留下空间。
第一次同步通常是全量复制
从库第一次连到主库时,本地还没有主库的数据,靠几条增量命令追不上完整状态,所以需要全量复制。资料 把这个过程拆成几个阶段:从库和主库先建立连接,并告诉主库自己要同步;主库确认后,主从库之间开始同步。
接着,从库会发送 psync 命令。如果是初次同步,主库会用 FULLRESYNC 响应,并带上两个重要信息:主库 runID 和当前复制进度 offset。runID 可以理解为主库身份,offset 是复制进度。后面判断能不能增量复制,就要靠这些信息对齐。
随后主库会创建 RDB 快照,把当前内存数据保存成文件并发送给从库。从库收到 RDB 文件后加载它,把自己的数据状态更新到快照那个时刻。到这里,从库终于有了主库的一份完整数据基础。
全量复制期间的新写入不能丢
全量复制不是瞬间完成的。主库生成 RDB、发送 RDB、从库加载 RDB 都需要时间。在这段时间里,主库还在继续处理客户端写请求。如果这些新写入不处理,从库加载完快照后就会落后一截。
文中提到,主库会把生成 RDB 快照期间新收到的写命令再发送给从库。另一段同步过程也写到,主节点创建 RDB 快照后,会把 RDB 文件发送给从节点,同时把缓冲区中的写命令也发给从节点。这样从节点先加载 RDB,再执行这段期间的写命令,就能追赶到主库更新的位置。
所以全量复制可以理解成两步:先给一份完整底稿,再补上底稿生成期间发生的修改。这个设计和前面讲混合持久化时的“全量数据加增量命令”很像,都是为了避免长时间操作期间的数据变化被漏掉。
正常运行靠命令传播
第一次同步完成后,主从库进入常规同步阶段。资料 把它称为基于长连接的命令传播。主库正常接收写请求,执行写命令后,通过主从之间保持的连接,把写命令继续发送给从库;从库收到后执行同样的命令。
这一步听起来简单,但它是主从复制长期工作的核心。全量复制只适合建立基础数据,不能每次写入都重新生成 RDB。正常情况下,写命令一条条传播过去,成本更低,也更接近实时。
主从之间还会维持心跳连接,用来检测彼此是否还存活。如果网络抖动、从库重启或连接断开,主从之间的复制进度就可能拉开。等从库重新连回来,就进入增量复制或重新全量复制的判断。
增量复制看 offset 差距
从库宕机或网络断开后,主库不会因为一个从库掉线就停止写入。文中说,主库会把断连期间收到的写操作命令写到 repl_backlog_buffer 中。从库重连后,会给主库发送 psync 命令,并带上自己的 slave_repl_offset。
主库收到后,会比较自己的 master_repl_offset 和从库的 slave_repl_offset。两个 offset 之间的差距,就是从库断开期间缺少的那段命令。如果这段命令还在 repl_backlog_buffer 里,主库就可以只把缺失命令发给从库,从库执行后追上来,这就是增量复制。
增量复制的价值很大。它避免了每次短暂断线都重新走全量复制。尤其是数据量大的实例,全量同步会消耗网络、磁盘和 CPU;如果只是漏了几秒或几十秒命令,用增量复制补齐就轻得多。
缓冲区不够就只能重新全量复制
增量复制有一个前提:缺失的命令还在 repl_backlog_buffer 里。文中写得很直白,如果 master_repl_offset 和 slave_repl_offset 的差值大于 repl_backlog_buffer 能覆盖的范围,说明从库断连太久,前面的值已经被覆盖了。为了避免数据不一致,就不能继续增量复制,只能重新全量复制。
这也是为什么复制积压缓冲区大小很重要。缓冲区太小,网络稍微抖久一点,从库就可能被迫全量同步。全量同步越频繁,主库压力越大,从库恢复越慢,甚至可能形成连锁影响。
实际排查复制问题时,可以围绕几个点看:从库断开了多久,主库写入量有多大,repl_backlog_size 是否足够,主从 offset 差距是否超出缓冲区范围。只说“从库会自动追主库”是不够的,追不追得上,要看缺失历史还在不在。
为什么全量同步用 RDB,不用 AOF
这里还解释了主从全量同步为什么使用 RDB 而不是 AOF。第一,RDB 文件是经过压缩的二进制数据,不同数据类型还会做针对性优化,文件通常更小。AOF 记录的是每一次写操作命令,写得越多文件越大,其中还可能包含很多对同一个 key 的重复操作。
第二,AOF 需要选择刷盘策略,策略选不好会影响 Redis 性能。RDB 则通常只在定时备份和主从全量同步时触发生成一次快照,不需要持续为每条写命令安排刷盘。对于全量复制来说,主库给从库一份当前数据快照,比给一长串历史命令更干净。
从恢复角度也能理解。新从库想要的是“当前完整状态”,不是“从很久以前到现在的所有修改过程”。RDB 直接表达当前状态,AOF 表达历史过程。全量同步当然更适合用 RDB 打底。
主从复制能缓解读压力,但不是强一致
主从复制经常和读写分离一起出现,所以很多人会自然地把读请求分给从库。但要注意,从库数据来自主库同步,复制有延迟。主库刚写完,从库还没执行到这条命令时,从库读到的就是旧数据。
如果业务读的是商品详情、配置缓存、非关键列表,这种短暂延迟通常可以接受。如果读的是刚下单后的订单状态、支付状态、余额变化,就要谨慎。可以让强一致读走主库,或者在写后短时间内把相关读请求固定到主库。
后文也提到避免主从数据不一致的方向:持久化和复制配置要正确,网络连接要稳定,最好让主从节点处于同一机房降低延迟,还要监控复制延迟和连接状态。主从复制是高可用基础,但它不自动消除所有一致性问题。
和持久化、哨兵的关系
主从复制和持久化经常一起被问,但它们负责的事情不同。持久化负责把数据落到磁盘,帮助 Redis 重启后恢复;主从复制负责把主库数据同步到从库,提供副本和读扩展。一个偏单机恢复,一个偏多节点同步。
哨兵则站在主从复制的下一层问题上。只有主从复制还不够,如果主库宕机,系统需要有人判断它真的不可用,并从从库里选出新的主库。资料 在主从复制后接着讲哨兵模式,正是因为哨兵依赖主从结构来完成自动故障转移。
所以这条学习线可以这样记:持久化解决重启恢复,主从复制解决副本同步和读扩展,哨兵解决主库故障后的自动切换,切片集群解决单机容量和单主节点压力。每个机制都在补 Redis 单机模型的一块短板。
面试可以这样组织答案
如果被问 Redis 主从复制,先说模式:Redis 提供主从库,主库可读写,从库通常只读;写操作先到主库,再同步给从库,读操作可以由主库或从库承接。然后分三段讲同步过程:第一次同步走全量复制,正常运行靠命令传播,断线重连尽量走增量复制。
全量复制时,从库通过 psync 请求同步,主库返回 FULLRESYNC,并带上 runID 和 offset;主库生成 RDB 快照发给从库,从库加载 RDB,再执行同步期间主库缓冲的新写命令。正常运行时,主库通过长连接把写命令传播给从库。
断线重连时,从库带着自己的 slave_repl_offset 找主库,主库比较 master_repl_offset。如果缺失命令还在 repl_backlog_buffer 里,就发送缺失部分做增量复制;如果缓冲区不够,说明历史被覆盖,只能重新全量复制。最后补一句:全量同步通常用 RDB,因为 RDB 文件小、加载快,比重放大量 AOF 命令更适合传输当前完整状态。
常见问题
Redis 主从复制和持久化有什么区别?
持久化把数据写到磁盘,主要用于重启恢复;主从复制把主库数据同步到从库,主要用于副本、读扩展和后续故障转移基础。
Redis 第一次主从同步为什么是全量复制?
因为从库还没有主库完整数据,只靠增量命令无法构建当前状态。主库需要生成 RDB 快照发给从库,再补上生成快照期间的新写命令。
增量复制什么时候会失败?
当从库断线太久,缺失命令已经不在 repl_backlog_buffer 中,主库无法只发送缺失部分,为避免数据不一致,就会退回全量复制。
主从复制是否保证强一致?
不保证。主库写入后,从库需要接收并执行命令,期间可能有复制延迟。强一致读通常应走主库,或根据业务设计读写策略。