☰
Redis篇章-Redis 主从复制:从“为什么需要“到全量 / 部分 / 实时三种复制
2026/10/12 2:33:26 网站建设 项目流程

一文吃透 Redis 主从复制:从"为什么需要"到全量 / 部分 / 实时三种复制(含完整流程图)

前面我们聊过 Redis 持久化(RDB 快照与 AOF 日志),持久化解决的是单机断电数据不丢的问题。但如果这台机器本身宕机了呢?这就是本文要讲的:主从复制(Replication)——它是 Redis 高可用的基石,哨兵(Sentinel)和集群(Cluster)都是构建在复制的基础之上的。


一、为什么要主从复制?

1.1 单机 Redis 的两大痛点

一台单独的 Redis 服务器,存在典型的单点问题:

痛点说明
① 可用性不高只有一台机器,它一旦宕机,整个缓存服务就瘫痪了,业务直接受损
② 性能有限所有的读请求 + 写请求都压在一台机器上,CPU、内存、网络都有上限,扛不住高并发

1.2 主从复制的解决思路

Redis 提供了复制功能,实现相同数据的多个 Redis 副本(Replica):

  • 数据多副本 → 故障恢复:主节点挂了,从节点上还有一份完整数据,可以顶上提供服务(配合哨兵可以自动完成故障转移);
  • 读写分离 → 分摊压力:主节点负责写,从节点负责读,读压力被分摊到多台从节点上,降低主节点的访问压力。

1.3 主从复制的三个基本特点

  1. 参与复制的实例分为主节点(master)和从节点(slave);
  2. 每个从节点只能有一个主节点,而一个主节点可以同时有多个从节点;
  3. 复制的数据流是单向的——只能由主节点流向从节点,从节点上的修改主节点无法感知。

二、主从复制的详细操作

2.1 如何建立复制(三种配置方式)

主节点的配置不需要任何改动,只需要在从节点上指明"我的主节点是谁",三种方式任选:

# 方式 1:配置文件中加入(随 Redis 启动生效)slaveof{masterHost}{masterPort}# 方式 2:redis-server 启动命令时加入redis-server /etc/redis/redis-slave.conf--port6380--slaveof127.0.0.16379# 方式 3:运行时直接使用 redis 命令127.0.0.1:6380>slaveof127.0.0.16379

验证是否生效,在主从节点分别执行:

127.0.0.1:6379>info replication# 主节点看到 role:master, connected_slaves:N127.0.0.1:6380>info replication# 从节点看到 role:slave, master_link_status:up

补充两个相关操作:

  • 断开复制:从节点执行slaveof no one,断开后从节点晋升为主节点,原有数据不会丢弃,只是不再同步主节点的新变化;
  • 切主操作:执行slaveof {newMasterIp} {newMasterPort},流程为:断开旧主 → 连接新主 →删除自身全部数据→ 从新主重新复制。

2.2 建立复制的完整流程(六个步骤)

在从节点上执行slaveof之后,内部会依次经历六个步骤:

  1. 保存主节点信息:从节点记录主节点的 ip / port,此时master_link_status还是down;
  2. 主从建立网络连接:从节点内部每秒运行的定时任务发现新主节点后,尝试建立 TCP 连接;连不上会无限重试,直到成功或手动停止复制;
  3. 发送 ping 命令:确认主节点在应用层上工作正常;若 pong 超时,断开连接等下轮重连;
  4. 权限验证:主节点设置了requirepass时,从节点需要通过masterauth配置一致的密码,验证失败则复制停止;
  5. 同步数据集:把主节点当前持有的所有数据全部发给从节点,这是最耗时的一步,分为全量同步和部分同步两种情况(见第三节);
  6. 命令持续复制:数据同步完成后,主节点会把后续的每一条写命令持续发送给从节点,保证主从数据一致。

关键概念:runid(复制 id)+ offset(偏移量)共同标识了一份"数据集"——如果两个节点的 runid 和 offset 都相同,它们持有的数据就一定相同。这个概念是理解全量 / 部分复制的钥匙。


三、三种复制方式(重点)

Redis 使用psync命令完成主从数据同步,语法:

PSYNC replicationid offset
  • replid为?且offset为-1→ 尝试进行全量复制(第一次复制时从节点啥也不知道,只能这么发);
  • replid和offset为具体数值 → 尝试进行部分复制(从节点之前复制过,记得自己的"学习进度")。

三种复制方式:全量复制、部分复制、实时复制。下面逐一拆解。

3.1 全量复制 —— 首次复制必须经历

全量复制是主从第一次建立复制时必须经历的阶段:主节点把全部数据一次性以 RDB 的形式发给从节点。

流程详解(对应图中 ①-⑨):

  1. 从节点发送psync ? -1(第一次复制,没有主节点的 runid 和 offset);
  2. 主节点解析出要做全量复制,回复+FULLRESYNC {runid} {offset};
  3. 从节点接收并保存主节点的 runid 和 offset;
  4. 主节点执行bgsave,生成 RDB 文件;
  5. 主节点把 RDB 文件发送给从节点,从节点保存到本地硬盘;

    从 Redis 2.8.18 开始支持无盘复制(diskless):主节点生成 RDB 时不落磁盘,直接通过网络发给从节点,省去写硬盘 + 读硬盘的开销;

  6. 生成 RDB 期间主节点仍在响应写命令,这些新写命令暂存到缓冲区,等从节点保存完 RDB 后再补发过去(仍按 RDB 二进制格式追加写入),保证一致性;
  7. 从节点清空自身原有旧数据;
  8. 从节点加载 RDB,得到与主节点一致的数据;
  9. 如果从节点开启了 AOF,再执行bgrewriteaof,得到最近的 AOF 文件。

⚠️全量复制成本非常高:主节点 bgsave 的时间 + RDB 网络传输的时间 + 从节点清空旧数据的时间 + 加载 RDB 的时间。数据量越大代价越大,所以应尽量避免对已有大量数据集的 Redis 进行全量复制——这正是部分复制存在的意义。

3.2 部分复制 —— 网络闪断后的"断点续传"

部分复制是针对全量复制过高开销做出的优化措施:从节点复制期间如果出现网络闪断、命令丢失等异常,重新连上后只补发缺失的那一小段数据,开销极小。

流程详解(对应图中 ①-⑥):

  1. 主从之间网络中断,超过repl-timeout时间后,主节点认为从节点故障,断开复制连接;
  2. 中断期间主节点依然响应命令,但这些复制命令无法及时发给从节点,于是**暂时滞留在「复制积压缓冲区」**中;
  3. 网络恢复后,从节点重新连上主节点;
  4. 从节点把之前保存的replid + offset作为参数发送psync {replid} {offset},请求部分复制;
  5. 主节点校验后,根据 offset 去复制积压缓冲区查找数据,回复+CONTINUE;
  6. 主节点把缺失的那部分数据补发给从节点,主从重新一致。

核心:复制积压缓冲区(repl-backlog-buffer)

  • 保存在主节点上的一个固定长度队列,默认 1MB;主节点有从节点连接时创建;
  • 主节点响应写命令时,不但发给从节点,还会同时写入这个缓冲区;
  • 本质是先进先出的环形队列(相当于数组实现的环形缓冲区),只保存最近已复制的数据;
  • 可用偏移量范围 =[repl_backlog_first_byte_offset, first_byte_offset + repl_backlog_histlen](可用info replication查看)。

⚠️如果从节点需要的 offset 已经超出缓冲区范围(断线太久、被环形队列覆盖了),缓冲区里已经没有它要的数据 →无法部分复制,只能退化成全量复制。写量大的场景可以调大repl-backlog-size来降低这种退化概率。

3.3 实时复制 —— 长连接 + 心跳保活

全量/部分复制完成后,主从进入命令实时复制阶段:

  • 主节点把自己收到的每一条修改操作,通过 TCP 长连接源源不断传给从节点;
  • 从节点执行相同命令,实时修改自身数据,与主节点保持一致。

这条长连接依靠应用层实现的心跳机制来维护(不是 TCP 自带的心跳):

角色心跳行为默认频率
主节点 → 从节点发送ping,判断从节点存活性和连接状态每10 秒
从节点 → 主节点发送replconf ack {offset},上报当前复制偏移量每1 秒

如果主节点发现从节点通信延迟超过repl-timeout(默认 60 秒),则判定从节点下线,断开复制连接;从节点恢复后,心跳机制继续进行。

3.4 三种方式的关系

一句话总结:先全量(第一次),后实时(日常),出故障再部分复制补齐。

维度全量复制部分复制实时复制
触发时机首次建立复制 / offset 超出缓冲区范围网络闪断恢复后,offset 仍在缓冲区内数据同步完成之后持续进行
psync 参数psync ? -1psync {replid} {offset}—
主节点响应+FULLRESYNC+CONTINUE持续推送写命令
传输内容完整 RDB 快照缓冲区中缺失的那段命令后续每一条写命令
开销极高(bgsave + 传输 + 清空 + 加载)很小(只补缺失部分)平稳(逐条增量)

四、主从复制的拓扑结构

复制的拓扑可以单层也可以多层,常见的有三种:

拓扑结构适用场景注意点
一主一从最简单,1 个主 + 1 个从主节点宕机时从节点提供故障转移支持可只在从节点开 AOF,避免持久化干扰主节点性能;主节点关闭持久化时,宕机后要避免自动重启
一主多从(星形)1 个主 + N 个从读并发量大:读命令负载均衡到多个从节点;耗时读命令可指定专用从节点写并发量大时,写命令要发给每个从节点,反而加重主节点负载
树形主从(分层)从节点还可以作为下层节点的主节点继续向下复制主节点需要挂载多个从节点时,避免性能干扰引入复制中间层,有效降低主节点负载和传送的数据量

五、其他实用配置

  • 安全性:主节点设置requirepass后,从节点必须配置相同的masterauth,否则无法通过权限验证发起复制;
  • 只读模式:从节点默认slave-read-only=yes。因为复制是单向的,从节点上的修改主节点感知不到,会造成主从数据不一致,线上不建议关闭;
  • 传输延迟:repl-disable-tcp-nodelay默认no(开启 TCP_NODELAY,命令小包及时发送,延迟小但占带宽,适合同机房);设为yes则合并小包节省带宽(约 40ms 间隔),延迟变大,适合跨机房。

六、总结与重点回顾

  1. 主从复制解决的是单点问题:单节点可用性不高、性能有限;通过数据多副本实现故障恢复,通过读写分离分摊压力;
  2. 配置很简单:主节点不动,从节点加slaveof {masterHost} {masterPort}即可;数据流永远单向(主 → 从);
  3. 建立复制六步走:保存主节点信息 → 建立连接 → ping → 权限验证 → 同步数据集 → 命令持续复制;
  4. 三种复制方式:
    • 全量复制(psync ? -1→+FULLRESYNC):首次复制必须经历,bgsave 生成 RDB 全量传输,成本极高;
    • 部分复制(psync {replid} {offset}→+CONTINUE):靠复制积压缓冲区(默认 1MB 环形队列)补发断线期间的数据,offset 超出缓冲区范围则退化为全量;
    • 实时复制:TCP 长连接持续推送写命令,主 10 秒 ping 一次、从 1 秒上报一次 offset 的心跳机制保活;
  5. 核心概念:replid + offset共同标识一份数据集,相当于主从之间对齐"学习进度";
  6. 哨兵和集群都是在主从复制的基础上构建的——理解了复制,后面学高可用架构就顺理成章了。

如果本文对你有帮助,欢迎点赞、收藏、评论交流!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询