Appearance
Redis 主从复制
本文介绍Redis主从复制相关原理、配置及问题。
1. 概念
Redis的主从复制是指将主节点(master)的数据同步到从节点(replica),从而实现读写分离、高可用、容灾备份等功能。
Redis的主从复制不依赖主节点的RDB或AOF配置,即主节点的RDB或AOF持久化可以关闭。
2. 工作原理
2.1 概念解释
Redis的主从复制分为两种方式:
- 全量复制:主节点生成一个 RDB 文件(快照)并发送给从节点,从节点接收到RDB文件后,先清空自身的数据库,然后加载RDB文件;
- 增量同步:当全量复制开始时,主节点会将写命令缓存到一个缓冲区(repl-backlog),同步完成后将这些增量命令发送给从节点,从节点通过 repl-backlog(复制缓冲区)接收主节点的写命令流,异步执行这些命令以保持数据一致性;
Redis如何实现全量复制和增量同步?通过Replication ID 和 Offset。
- Replication ID :是一个唯一标识符,用于标识主节点的复制流(replication stream),或者说主节点数据集的版本号。它是一个 40 字节的随机字符串,通常由主节点在启动或成为主节点时生成。
- Offset:偏移量,是一个递增的数值,表示主节点或从节点在复制流中的当前位置。它记录了主节点当前缓冲区中的写命令字节数,或者从节点已接收并应用的字节数。
我们可以使用 INFO REPLICATION 命令可以查看主节点和从节点的 Replication ID 和 Offset。

在上面的结果中,我们主要关注三个值:
master_replid:即Replication ID,表示该节点数据集版本;repl_backlog_first_byte_offset:该节点缓冲区repl_backlog中存储有效命令的起始位置;master_repl_offset:该节点缓冲区repl_backlog中存储有效命令的结束位置;
可以通过以下图理解repl_backlog_first_byte_offset和master_repl_offset:

2.2 工作流程
首先主节点启动,生成
Replication ID;然后开始接收来自客户端的写命令,并将其存入repl backlog,并更新master_repl_offset;
当repl backlog写满后,开始覆盖旧命令,并更新
repl_backlog_first_byte_offset和master_repl_offset,可以理解为repl backlog buffer在写指令序列上往后移动,总是保留最新的写指令;然后从节点启动,连接主节点;
当从节点连接主节点后,发送
PSYNC命令,包含从节点的Replication ID和Offset,如果是第一次,则Replication ID值为?,Offset值为-1:txtPSYNC ? -1主节点接收到从节点发送过来的
Replication ID和Offset:- 首先对比从节点和主节点的
Replication ID,如果不同,则执行全量复制流程; - 如果相同,则对比从节点的
Offset和主节点的repl_backlog_first_byte_offset:- 如果从节点的
Offset< 主节点的repl_backlog_first_byte_offset,表示从节点落后太多,主节点的repl backlog缓冲区中没有从节点缺失的命令,需要执行全量复制流程; - 如果从节点的
Offset>= 主节点的repl_backlog_first_byte_offset,则执行增量同步流程;
- 如果从节点的
- 首先对比从节点和主节点的
主节点返回:
全量复制,返回内容以
+FULLRESYNC打头,格式为:txt+FULLRESYNC <replication_id> <offset> $<length> 后面是 RDB 数据流增量同步,返回内容以
+CONTINUE打头,格式为:txt+CONTINUE RESP格式写命令
当进行增量同步流程时,由主节点将写命令发送给从节点,并且主节点会定时
ping从节点;
2.3 演示
下面我们用telnet手动发送 PSYNC命令,来演示主从复制。
如果在MacOS系统下没有telnet,可以使用homebrew安装:
brew install telnet
首先启动一个Redis实例,然后依次执行以下命令:
txt
INFO replication
set k6 v6
INFO replication可以看到master_repl_offset持续增长,说明repl backlog buffer中存储的命令不断增多:

然后,在命令行中使用telnet连接Redis:
bash
telnet 127.0.0.1 6379第一次发送PSYNC ? -1命令,表示首次连接到主节点,会执行全量复制:

可以看到返回了全量复制。
之后,我们在另一个Redis客户端执行写操作命令:
txt
set k7 v7可以看到,命令行界面会输出这条写命令,说明全量复制后,增量同步自动开始:

接下来我们演示增量同步:


3. 配置与命令
本小节介绍如何使用配置或命令开启主从复制。
3.1 配置
配置分为主节点配置和从节点配置。
主节点配置如下:
daemonize yes:设置Redis 服务器在启动时以“守护进程”(daemon)的方式在后台运行;bind * -::*:设置任何IPv4或IPv6地址可访问Redis服务;protected-mode no:关闭保护模式保护模式(protected mode)是 Redis 为防止误操作和安全风险而设计的一种机制。当保护模式开启(
protected-mode yes,默认值)时,如果 Redis 没有设置密码,并且监听的是非本地地址(如 0.0.0.0 或*),Redis 只允许本地连接,拒绝外部主机的访问。这可以防止 Redis 实例被意外暴露在公网时被未授权用户访问和利用。port 6379:指定端口;dir /data/:指定工作目录;logfile "":指定日志文件路径;requirepass 123456:指定访问Redis的密码;开启RDB相关配置;
开启AOF相关配置;
从节点配置如下:
masterauth <master-password>:配置从节点访问主节点所需要的密码,即主节点Redis密码;replicaof <masterip> <masterport>:配置主节点Redis地址;
3.1 命令
关于主从复制的命令有如下两条:
REPLICAOF <host port>:在运行时设置主节点的地址,从而使从节点可以改变跟随的主节点;REPLICAOF <NO ONE>:取消该从节点的从属关系,使之成为主节点;CONFIG SET parameter value [parameter value ...]:如果主节点需要密码访问,可以动态使用CONFIG命令更改配置项,配置主节点密码:txtCONFIG SET masterauth 123456INFO replication:查看主从复制信息;
4. 测试案例
以下测试案例基于Docker配置。
4.1 配置:一主一从
在Docker 中,Redis主节点正常启动,监听在6379端口上,映射到宿主机6379端口。
查看Redis主节点所在主机IP地址:

配置从节点:
txt
replicaof 172.17.0.2 6379
masterauth 123456启动Redis从节点,同样监听在6379端口,映射到宿主机6380端口。

可以看到复制成功,并且不能在从节点上执行写操作。
在从节点上查看主从复制信息:

在主节点上查看主从复制信息:

4.2 命令:二主一从
我们先启动两个Redis主节点,然后让一个从节点先使用配置文件跟随一个主节点,再在运行时使用命令跟随另一个主节点。
启动另一个主节点,同样监听在6379端口,映射到宿主机6389端口上,并且需要密码abcdef才能访问。
启动成功后,先设置一些数据:

在从节点(端口6380)上使用命令replicaof no one,使从节点成为主节点:

这是从节点可以正常执行写操作:

然后使用replicaof host port改变主节点:

可以看到,从节点改变主节点,会先清空自己的数据。
4.3 测试主节点下线
主节点下线后,从节点仍然保持从节点地位不变:

5. 问题
在Redis的主从复制场景中,需要注意以下问题:
全量同步的性能开销:全量同步需要主节点生成 RDB 快照(或通过无磁盘复制传输数据流),并通过网络发送给从节点,这会消耗大量 CPU、内存和网络带宽。在数据量大或网络较慢的情况下,全量同步可能导致主节点性能下降或从节点同步时间过长,从而性能低或数据一致性问题。
复制缓冲区(repl-backlog)溢出:repl-backlog 是一个固定大小的环形缓冲区(默认 1MB),用于存储主节点的写命令以支持部分同步。在高写负载或从节点长时间断连的情况下,缓冲区可能被新命令覆盖,导致从节点的 slave_repl_offset 小于缓冲区的起始 Offset,触发全量同步。可根据负载调整配置:
txtrepl-backlog-size 10mb可用性低:如果主节点意外下线,会导致整个主从复制拓扑结构失效,从节点无法上位成为主节点;
参考资料
[1] https://redis.io/docs/latest/operate/oss_and_stack/management/replication/