目录
阶段 2:全量复制 (Full Synchronization)
阶段 3:增量复制 / 命令传播 (Partial Synchronization / Command Propagation)
方式 2:运行时使用命令 (REPLICAOF / SLAVEOF)
1、核心概念与角色
原理: 一个主节点可以有多个从节点。主节点处理写操作,并将写命令异步复制给从节点。从节点处理读操作(分担读负载)并提供冗余备份。
拓扑结构:
-
星型拓扑 (一主多从): 最常见。所有从节点直接连接主节点。主节点负责所有写和复制分发。优点:结构简单,延迟最低(从节点直接获取主节点数据)。缺点:主节点复制压力大(带宽和 CPU)。
-
链式复制 / 级联复制 (树状拓扑): 从节点 (
Slave A
) 可以连接另一个从节点 (Slave B
) 作为其主节点。Slave B
的数据来自Slave A
(最终源头还是主节点)。配置:在Slave B
上设置replicaof <SlaveA-IP> <SlaveA-Port>
。-
优点: 减轻主节点的复制压力(特别是从节点很多时),节省主节点出口带宽。
-
缺点: 增加了数据到达末端从节点的延迟(每级都有延迟)。末端从节点数据不一致风险更高。
Slave A
故障会导致其下所有子从节点断开。 -
适用场景: 跨地域复制(主节点在中心机房,
Slave A
在区域机房,区域机房内的其他从节点连接Slave A
)。
-
核心角色:
1> 主节点 (Master):
-
负责处理客户端的写操作(
SET
,HSET
,LPUSH
,SADD
,ZADD
,DEL
等)。 -
数据变更后,主节点会将这些变更命令异步地发送给所有连接的从节点。
-
一个 Redis 实例只能是一个主节点(在非集群模式下)。
2> 从节点 (Slave / Replica):
-
连接到一个主节点,接收主节点发送的数据更新流。
-
默认情况下是只读的(
replica-read-only yes
),处理客户端的读操作(GET
,HGET
,LRANGE
等)。可以修改配置允许写入,但强烈不推荐(数据会与主节点不一致且不会被同步)。 -
一个从节点可以连接一个主节点(标准模式),也可以连接另一个从节点形成级联复制(链式复制)。
-
可以配置为在断开连接后尝试部分重新同步或全量重新同步。
-
从节点可以有多个。
主从节点关系:
-
1:N 关系: 一个主节点可以有多个从节点。
-
单向数据流: 数据只能从主节点流向从节点。
-
异步复制: 默认情况下,复制是异步的。主节点在本地执行写命令后立即返回给客户端,然后才将命令传播给从节点。这意味着主从之间可能存在短暂的数据不一致(复制延迟)。
2、复制流程
复制过程主要分为两个阶段:初始连接时的全量复制和后续持续进行的增量复制。
-
全量同步:新从节点连接主节点时,主节点执行
BGSAVE
生成 RDB 文件发送给从节点加载,同时将期间的写命令缓存到复制缓冲区
。 -
增量同步:全量同步完成后,主节点持续将收到的写命令发送给从节点执行。
阶段 1:建立连接与协商 (Handshake)
1> 配置从节点: 在从节点配置文件 (redis.conf
) 中设置 replicaof <masterip> <masterport>
或在运行时使用命令 REPLICAOF <masterip> <masterport>
(Redis 5.0+,旧版本为 SLAVEOF
)。
2> 从节点发起连接: 从节点启动或执行 REPLICAOF
命令后,会尝试连接到指定的主节点。
3> 身份验证 (可选): 如果主节点配置了密码 (requirepass
),从节点需要在配置文件中设置 masterauth <password>
或在连接后发送 AUTH <password>
命令进行认证。
4> 端口监听 (可选): 从节点默认监听 TCP 端口接收主节点数据(端口号与客户端端口相同)。可以使用 replica-announce-port
配置从节点向主节点报告的端口(常用于 Docker/NAT 环境)。
5> 能力协商: 主从节点交换彼此的版本信息和支持的复制能力(如 PSYNC2
)。
阶段 2:全量复制 (Full Synchronization)
当从节点是首次连接主节点,或者无法进行部分同步(见阶段 3)时,会触发全量复制。这是最重、最耗资源的阶段。
1> 主节点创建 RDB 快照:
-
主节点调用
fork()
创建一个子进程。 -
子进程将当前内存中的数据生成一个 RDB 快照文件。生成期间,父进程(主进程)继续处理命令。
-
Copy-On-Write (COW):
fork()
后,父子进程共享内存页。只有当父进程修改数据时,被修改的页才会被复制一份给子进程使用。因此,如果主节点在生成 RDB 期间有大量写操作,会导致内存使用增加(峰值可能接近 2 倍原始内存)。
2> 主节点缓存写命令:
-
在子进程生成 RDB 文件期间,主节点将所有新接收到的写命令写入一个复制缓冲区 (
replication buffer
)。
3> 发送 RDB 文件:
-
子进程完成 RDB 文件生成后,将其发送给从节点。
-
从节点接收 RDB 文件,将其保存到磁盘,然后清空自身旧数据,再加载这个 RDB 文件到内存中。加载过程会阻塞从节点。
4> 发送缓冲区的写命令:
-
RDB 文件发送完毕后,主节点开始将步骤 2 中缓存在复制缓冲区内的写命令发送给从节点。
-
从节点执行这些命令,使其数据状态尽可能追赶上主节点在发送完 RDB 文件那一刻的状态。
5> 完成全量同步:
-
复制缓冲区内的命令发送执行完毕后,从节点的数据状态基本与主节点一致(忽略这期间主节点的新写入)。
-
此时,复制状态转为增量复制阶段。
阶段 3:增量复制 / 命令传播 (Partial Synchronization / Command Propagation)
完成全量同步后,复制进入增量复制阶段。主节点持续地将新的写命令异步地发送给从节点,从节点执行这些命令以保持数据同步。
1> 复制偏移量 (replication offset
):
-
主节点和每个从节点都维护一个复制偏移量。
-
主节点每次向从节点发送一个字节的数据(无论是 RDB 还是命令流),自身的偏移量就增加。
-
从节点每次成功接收到并处理一个字节的数据,自身的偏移量也增加。
-
通过比较主从偏移量,可以判断数据同步状态和延迟。
2> 复制积压缓冲区 (replication backlog
):
-
主节点维护一个固定大小的环形缓冲区(配置项
repl-backlog-size
,默认 1MB)。 -
主节点在增量复制阶段发送给从节点的所有写命令都会写入这个缓冲区。
-
缓冲区按偏移量记录命令流。
3> PSYNC
命令与部分重新同步:
-
当从节点与主节点短暂断开连接后重连时,它会向主节点发送
PSYNC
命令,并携带自己当前的复制偏移量 (slave_repl_offset
) 和之前连接的主节点 ID/runid(如果知道)。 -
主节点收到
PSYNC
后:-
检查 runid 是否匹配(是否是之前连接的主节点)。
-
检查从节点提供的偏移量是否还在自己的复制积压缓冲区 (
repl_backlog
) 的范围内。
-
-
如果都满足: 主节点回复
+CONTINUE
,表示可以进行部分重新同步。然后主节点将复制积压缓冲区中从该偏移量之后的所有命令发送给从节点。 -
如果任一条件不满足: 主节点回复
+FULLRESYNC <runid> <offset>
,表示需要触发全量复制。 -
PSYNC2
(Redis 4.0+): 改进了PSYNC
,支持在主节点故障切换(如哨兵或集群故障转移)后,新的主节点也能尝试与旧主节点的从节点进行部分重新同步(通过存储历史主节点的 runid 和 offset),大大减少了故障切换后的全量同步需求。
阶段 4:心跳与保持连接
从节点定时 REPLCONF ACK
:
-
在增量复制阶段,从节点默认每秒向主节点发送一次
REPLCONF ACK <replication_offset>
命令。 -
作用:
-
向主节点报告自己当前的复制偏移量 (
<replication_offset>
),主节点据此计算复制延迟 (lag
)。 -
心跳检测,维持 TCP 连接活性。
-
辅助主节点判断从节点的在线状态(用于
min-replicas-to-write
等功能)。
-
主节点检测超时:
-
主节点通过
repl-timeout
(默认 60 秒) 配置项判断从节点是否超时。 -
如果超过
repl-timeout
时间没有收到从节点的REPLCONF ACK
或任何通信,主节点认为该从节点已断开。 -
断开后,从节点需要重新执行连接协商和同步流程(可能是部分同步或全量同步)。
3、重要配置项
3.1 主Redis配置
主节点(Master)通常不需要特殊的配置来启用复制,它默认就准备好接受从节点的连接。
基本要求:
-
主节点需要正常运行并监听在某个端口(默认
6379
)。 -
确保主节点的
bind
配置(redis.conf
中)允许从节点服务器的 IP 地址连接。通常设置为bind 0.0.0.0
(监听所有接口,生产环境需结合防火墙策略)或绑定到特定网络接口的 IP。 -
确保主节点的防火墙(如
iptables
,firewalld
, 云服务商安全组)开放了 Redis 端口(默认6379/tcp
),允许从节点的 IP 地址访问。
可选配置(但强烈建议):
-
requirepass
: 设置主节点的密码。如果设置了密码,从节点连接主节点进行复制时也需要提供这个密码(在从节点配置masterauth
)。 -
持久化配置(
save
,appendonly
): 虽然不是复制直接要求的,但强烈建议主节点启用持久化(RDB 或 AOF 或混合),以保证在主节点重启或故障时,从节点重新连接后能获得有效数据进行同步。
3.2 从Redis配置
主要的配置工作集中在从节点(Replica/Slave)上,告诉它去复制哪个主节点。
配置从节点有两种主要方式:修改配置文件 (redis.conf
) 和 运行时使用命令(REPLICAOF
/ SLAVEOF
)。
方式 1:修改配置文件 (redis.conf
)-推荐
1> 定位并编辑配置文件: 找到从节点 Redis 服务器的配置文件(通常名为 redis.conf
)。
2> 关键配置项:
-
replicaof
(Redis 5.0+) /slaveof
(旧版本)-
这是最核心的配置项。告诉从节点它要复制哪个主节点。
-
将 `` 替换为主节点的 IP 地址。
-
将 `` 替换为主节点的 端口号(默认是
6379
)。 -
例如:
replicaof 192.168.1.100 6379
-
-
masterauth
(如果主节点设置了requirepass
)-
如果主节点设置了密码(
requirepass
),从节点必须配置此选项,值为主节点的密码。 -
例如:
masterauth YourStrongMasterPassword
-
-
replica-read-only yes
(默认值)-
设置从节点为只读模式。强烈建议保持
yes
,防止数据在从节点被意外修改,导致主从不一致。
-
3> 其他相关配置:
-
replica-serve-stale-data yes
(默认值):当从节点与主节点失去连接或正在同步时:-
yes
:从节点仍会响应客户端请求(可能返回过期数据)。 -
no
:从节点会对所有请求返回错误"SYNC with master in progress"
(除了INFO
,REPLICAOF
,AUTH
等少数命令)。
-
-
replica-priority
(默认100
):在 Redis Sentinel 自动故障转移时,Sentinel 会优先选择优先级数字更小的从节点提升为新主节点。数值范围通常是 0-100,0
表示永远不会被选为主节点。 -
min-replicas-to-write
/min-replicas-max-lag
:主节点配置项(注意:这是在主节点的redis.conf
里配!),用于配置写入安全。它要求主节点只有在至少有N
个从节点的延迟(lag
)都小于等于M
秒时,才会接受写操作。这可以增强数据安全性(确保写操作被传播到一定数量的从节点),但会牺牲一些可用性(如果从节点不够或延迟太高,主节点会拒绝写入)。生产环境按需谨慎配置。
4> 保存配置文件并重启从节点 Redis 服务: 使配置生效。
方式 2:运行时使用命令 (REPLICAOF
/ SLAVEOF
)
这种方式配置在 Redis 服务重启后会失效。适用于临时调整或测试。
1> 连接到从节点 Redis 实例: 使用 redis-cli
连接到你的从节点服务器。
2> 执行命令:
-
建立复制关系:
-
Redis 5.0+:
REPLICAOF
-
旧版本:
SLAVEOF
-
例如:
REPLICAOF 192.168.1.100 6379
-
-
如果主节点有密码: 在建立复制关系前或后,执行:
-
CONFIG SET masterauth
(运行时配置密码认证) -
例如:
CONFIG SET masterauth YourStrongMasterPassword
-
-
设置只读模式(默认是只读,通常不需要改):
-
CONFIG SET replica-read-only yes
-
3> 验证: 执行 INFO replication
命令查看复制状态。
3.3 验证主从复制是否配置成功
连接到从节点,执行命令:INFO replication
-
查看输出中的关键字段:
-
role: replica
(确认当前节点角色是从节点) -
master_host:
(应为配置的主节点 IP) -
master_port:
(应为配置的主节点端口) -
master_link_status: up
(表示连接主节点成功) -
master_last_io_seconds_ago:
(一个较小的数字,表示最近一次与主节点通信是在几秒前) -
slave_repl_offset:
和master_repl_offset:
(这两个值应该非常接近,且在不断增长,表示数据正在同步) -
稍等片刻后,检查
slave0:
部分(或其他slaveN
,表示该从节点在主节点视角的状态),确认ip
和port
正确,state=online
。
-
连接到主节点。执行命令:INFO replication
-
查看输出中的
connected_slaves:
数量应大于 0。 -
在
slave0:
(或其他slaveN
) 部分,确认ip
和port
匹配你的从节点服务器地址,state=online
,offset
值接近。
3.4 复制相关命令
-
INFO replication
: 最重要! 查看主从复制状态信息(角色、连接状态、偏移量、积压缓冲区大小、从节点列表等)。 -
REPLICAOF host port
/SLAVEOF host port
: 将当前服务器设置为指定 host:port 的从节点。REPLICAOF no one
停止复制,变为主节点。 -
ROLE
: 快速查看当前实例的角色(master/slave)和复制状态。 -
PSYNC
: 内部命令,用于从节点请求部分重新同步。
4、复制中的关键问题与注意事项
复制延迟 (Replication Lag):
-
原因: 异步复制本质、网络延迟、从节点负载高(处理慢查询或持久化 RDB/AOF)、主节点写入压力过大。
-
监控: 使用
INFO replication
查看slaveX
的lag
值(秒级延迟)。第三方监控工具。 -
影响: 读从节点可能读到旧数据。故障切换时可能丢失最近写入。
-
缓解: 优化网络、提升从节点性能、分散读请求、容忍延迟或强制读主节点(特定业务)。
主节点持久化与数据安全:
-
如果主节点未开启持久化 (
save ""
),且发生故障重启,内存数据将全部丢失。即使有从节点,从节点也会被清空(复制断开后,从节点数据可能比主节点旧,但主节点重启后为空,从节点会同步这个“空”状态)。强烈建议主节点开启持久化 (RDB 或 AOF)。 -
即使主节点开启持久化,在故障瞬间尚未落盘的写入也会丢失。
min-replicas-to-write
可以增加一层保障(确保写入被同步到至少 N 个从节点)。
全量复制的代价:
-
资源消耗大: 主节点 fork 子进程生成 RDB (CPU、内存峰值)、网络传输 RDB (带宽)、从节点加载 RDB (阻塞、CPU、磁盘 IO)。
-
规避策略:
-
合理设置
repl-backlog-size
避免不必要的全量同步。 -
避免频繁重启主节点或大规模从节点同时重连。
-
使用
PSYNC2
(Redis 4.0+),利用故障切换后的部分同步。
-
复制中断与恢复:
-
原因: 网络故障、主节点或从节点宕机、主节点超载断开从节点(
client-output-buffer-limit
触发)、主节点重启。 -
恢复: 网络恢复或节点重启后,从节点会自动重连主节点并尝试
PSYNC
进行部分重新同步。失败则触发全量同步。
读写分离的挑战:
-
数据一致性问题: 由于复制延迟,读从节点可能读到过期数据。
-
解决方案: 业务容忍延迟;对一致性要求高的读操作走主节点;使用
WAIT
命令(强制等待 N 个从节点复制成功,牺牲性能换取强一致性,但慎用)。
5、优缺点分析
优点: 读写分离、数据冗余、提高读吞吐量。
缺点: 主从复制本身不提供自动故障转移 (Failover),主节点故障需要手动切换(或借助哨兵);写操作仍然集中在主节点;复制是异步的,存在数据不一致窗口期。
扩展:
-
Redis Sentinel (哨兵): 在主从复制基础上,增加了监控、通知、自动故障转移和配置提供者功能,实现了高可用 (HA)。
-
Redis Cluster (集群): 在提供分片(Sharding)功能的同时,每个分片(Shard)内部也使用主从复制机制来实现高可用。