Redis 主从复制原理

主从复制是 Redis 高可用架构的基石。它通过将主节点(Master)的数据自动同步到一个或多个从节点(Slave),实现数据冗余、读写分离和故障恢复。理解主从复制的底层流程、全量与增量复制的差异以及复制偏移量与积压缓冲区的作用,是构建稳定读写分离架构的前提。

2.1 主从复制流程

Redis 主从复制分为三个阶段:连接建立、数据同步、命令传播。从节点通过 REPLICAOF 命令(或旧版 SLAVEOF)发起复制请求,整个流程如下表所示:

阶段 步骤 说明
连接建立 1. 从节点发送 REPLICAOF 命令 从节点向主节点发起复制请求,携带自身 run_id 和复制偏移量
2. 主节点记录从节点信息 主节点在 repl_backlog 中注册从节点,返回 FULLRESYNC 或 CONTINUE
数据同步 3. 全量复制(首次或断连过久) 主节点生成 RDB 快照并发送给从节点,从节点清空旧数据并加载 RDB
4. 增量复制(断连后快速重连) 主节点从积压缓冲区发送缺失的写命令
命令传播 5. 持续同步写命令 主节点将每次写操作以 REPL_CONF 协议推送给所有从节点
关键点:从节点在连接建立阶段会发送自己的 repl_offset,主节点据此判断应该执行全量复制还是增量复制。这是复制效率的核心决策依据。

2.2 全量复制与增量复制

全量复制和增量复制是 Redis 主从同步的两种模式,它们在触发条件、数据量和性能开销上有显著差异:

对比维度 全量复制 增量复制
触发条件 首次复制、从节点 run_id 变化、复制偏移量超出积压缓冲区范围 从节点断连后快速重连,且偏移量仍在积压缓冲区范围内
数据量 整个 RDB 文件(可能数 GB) 仅缺失的写命令(通常 KB ~ MB)
主节点开销 高:fork 子进程生成 RDB、磁盘 I/O、网络带宽 低:直接从内存积压缓冲区读取命令
从节点开销 高:清空旧数据、加载 RDB、重建数据结构 低:逐条执行写命令
阻塞影响 主节点 fork 时短暂阻塞,从节点加载 RDB 时无法提供服务 几乎无阻塞
适用场景 新节点加入、长时间断连 网络抖动、短暂断连
避坑指南:全量复制期间,主节点 fork 子进程生成 RDB 会消耗大量内存(写时复制机制下,如果写操作频繁,内存占用可能翻倍)。建议在业务低峰期进行全量复制,并确保主节点内存不超过物理内存的 70%。

全量复制的详细流程如下:

  1. 主节点执行 bgsave 生成 RDB 快照文件。
  2. 主节点将 RDB 文件发送给从节点。
  3. 从节点清空当前所有数据,加载 RDB 文件。
  4. 主节点将生成 RDB 期间累积的写命令(存储在复制缓冲区中)发送给从节点。
  5. 从节点执行这些写命令,完成数据追赶。

增量复制的触发条件更为严格:

  • 从节点断连时间较短,其 repl_offset 仍在主节点的积压缓冲区范围内。
  • 主节点直接从 repl_backlog 中取出从节点缺失的命令,通过 PSYNC 协议发送。
  • 从节点收到命令后,从断点处继续执行,无需清空数据。

2.3 复制偏移量与积压缓冲区

复制偏移量(Replication Offset)和积压缓冲区(Replication Backlog)是 Redis 实现增量复制的两个核心机制。

复制偏移量:每个 Redis 节点(主从)都维护一个 repl_offset,表示当前节点已处理的复制数据字节数。主节点每向从节点发送一条写命令,偏移量就增加;从节点每接收并执行一条写命令,偏移量也同步增加。通过对比主从偏移量,可以精确判断数据同步的进度。

积压缓冲区:主节点在内存中维护一个固定大小的环形缓冲区(默认 1MB),用于存储最近执行的写命令。当从节点断连后重连时,主节点检查从节点的偏移量是否仍在缓冲区范围内:

  • 如果在范围内,执行增量复制。
  • 如果不在范围内(缓冲区已被新数据覆盖),执行全量复制。
核心公式:积压缓冲区大小 = repl-backlog-size(默认 1MB)。建议根据网络中断容忍时间计算:缓冲区大小 = 平均写流量 × 最大容忍断连时间。例如,写流量 10MB/s,容忍断连 60 秒,则缓冲区应设为 600MB。

下图展示了复制偏移量与积压缓冲区在增量复制中的协作关系:

复制偏移量与积压缓冲区协作流程 复制偏移量与积压缓冲区协作流程 主节点 (Master) 积压缓冲区 (repl_backlog) 环形缓冲区,默认 1MB 存储最近执行的写命令 偏移量范围: [offset_start, offset_end] 主节点偏移量 master_repl_offset = 102400 写命令输入 SET / DEL / LPUSH ... 从节点 (Slave) 从节点偏移量 slave_repl_offset = 102200 缺失命令 偏移量范围: [102200, 102400] 共 200 字节命令 执行缺失命令 追平主节点偏移量 PSYNC 请求 增量复制命令 ACK 确认偏移量 说明:从节点偏移量 102200 仍在积压缓冲区范围内,主节点从缓冲区取出 [102200, 102400] 的命令进行增量复制

2.4 复制偏移量与积压缓冲区的配置优化

合理配置积压缓冲区大小是避免全量复制的关键。以下配置项直接影响复制效率和稳定性:

配置项 默认值 推荐值 说明
repl-backlog-size 1MB 根据写流量计算 积压缓冲区大小,越大越能容忍长时间断连
repl-backlog-ttl 3600 秒 3600 ~ 7200 所有从节点断开后,缓冲区保留时间
repl-timeout 60 秒 60 ~ 120 主从连接超时时间,超时后从节点会尝试重连
repl-ping-replica-period 10 秒 10 主节点向从节点发送心跳的间隔
最佳实践:使用 INFO replication 命令查看主从偏移量差异。如果 master_repl_offset 与 slave_repl_offset 的差值接近 repl-backlog-size,说明缓冲区即将溢出,应立即增大 repl-backlog-size。

复制偏移量的监控命令示例:

# 在主节点查看复制信息
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.1.101,port=6379,state=online,offset=102400,lag=0
slave1:ip=192.168.1.102,port=6379,state=online,offset=102400,lag=0
master_repl_offset:102400
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:102000
repl_backlog_histlen:400

从上述输出可以看出:

  • master_repl_offset 为 102400,表示主节点已处理 102400 字节的复制数据。
  • slave0 和 slave1 的偏移量均为 102400,说明两个从节点已完全同步。
  • repl_backlog_first_byte_offset 为 102000,表示积压缓冲区中最早的字节偏移量。
  • repl_backlog_histlen 为 400,表示缓冲区当前存储了 400 字节的数据。
常见问题:如果从节点偏移量小于 repl_backlog_first_byte_offset,说明从节点断连时间过长,积压缓冲区已被新数据覆盖,此时必须执行全量复制。建议将 repl-backlog-size 设置为 平均写流量 × 最大容忍断连时间 × 2,以提供安全余量。