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%。
全量复制的详细流程如下:
- 主节点执行
bgsave生成 RDB 快照文件。 - 主节点将 RDB 文件发送给从节点。
- 从节点清空当前所有数据,加载 RDB 文件。
- 主节点将生成 RDB 期间累积的写命令(存储在复制缓冲区中)发送给从节点。
- 从节点执行这些写命令,完成数据追赶。
增量复制的触发条件更为严格:
- 从节点断连时间较短,其
repl_offset仍在主节点的积压缓冲区范围内。 - 主节点直接从
repl_backlog中取出从节点缺失的命令,通过PSYNC协议发送。 - 从节点收到命令后,从断点处继续执行,无需清空数据。
2.3 复制偏移量与积压缓冲区
复制偏移量(Replication Offset)和积压缓冲区(Replication Backlog)是 Redis 实现增量复制的两个核心机制。
复制偏移量:每个 Redis 节点(主从)都维护一个 repl_offset,表示当前节点已处理的复制数据字节数。主节点每向从节点发送一条写命令,偏移量就增加;从节点每接收并执行一条写命令,偏移量也同步增加。通过对比主从偏移量,可以精确判断数据同步的进度。
积压缓冲区:主节点在内存中维护一个固定大小的环形缓冲区(默认 1MB),用于存储最近执行的写命令。当从节点断连后重连时,主节点检查从节点的偏移量是否仍在缓冲区范围内:
- 如果在范围内,执行增量复制。
- 如果不在范围内(缓冲区已被新数据覆盖),执行全量复制。
核心公式:积压缓冲区大小 =
repl-backlog-size(默认 1MB)。建议根据网络中断容忍时间计算:缓冲区大小 = 平均写流量 × 最大容忍断连时间。例如,写流量 10MB/s,容忍断连 60 秒,则缓冲区应设为 600MB。
下图展示了复制偏移量与积压缓冲区在增量复制中的协作关系:
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,以提供安全余量。