Skip to content

主从复制详解

一、主从复制的定义与核心作用

主从复制是Redis实现数据冗余读写分离高可用的基础机制:

  • 主节点(Master):负责处理写操作(如SETDEL),并将写操作同步给从节点。
  • 从节点(Slave/Replica):负责处理读操作(如GET),从主节点同步数据,默认只读slave-read-only yes)。

核心作用

  1. 数据冗余:从节点保存主节点的副本,防止单点故障导致数据丢失。
  2. 读写分离:主节点处理写请求,从节点处理读请求,提高系统吞吐量(适合读多写少场景)。
  3. 高可用基础:当主节点宕机时,从节点可通过哨兵(Sentinel)或集群(Cluster)晋升为新主节点,保证服务连续性。

二、主从复制的核心原理

主从复制的本质是主节点将写操作同步给从节点,分为初始化同步(全量复制)增量同步两个阶段。为了实现高效同步,Redis引入了复制偏移量运行ID积压缓冲区等关键组件。

1. 关键概念铺垫

在讲解同步流程前,需先理解以下核心概念:

  • 复制偏移量(Replication Offset)

    • 主节点(master_repl_offset)和从节点(slave_repl_offset)各自维护一个字节偏移量,记录已处理的命令字节数。
    • 主节点每发送1字节命令,偏移量+1;从节点每收到1字节命令,偏移量+1。
    • 作用:通过对比主从偏移量,判断从节点是否落后(如主偏移量1000,从偏移量800,说明从节点落后200字节)。
  • 运行ID(Run ID)

    • 每个Redis实例启动时生成的唯一标识符(如d4f4a1b2...)。
    • 作用:从节点重连时,通过运行ID判断是否为同一个主节点(若主节点重启,运行ID会变化,需重新全量复制)。
  • 积压缓冲区(Replication Backlog Buffer)

    • 主节点维护的环形缓冲区(默认1MB,可通过repl-backlog-size配置),保存最近的写命令
    • 作用:当从节点重连时,若其偏移量在缓冲区范围内,可通过缓冲区中的命令实现增量复制(避免全量复制)。
  • 复制缓冲区(Replication Buffer)

    • 主节点为每个从节点维护的临时缓冲区,保存即将发送给从节点的命令。
    • 作用:全量复制时,主节点生成RDB文件的同时,将写命令存入复制缓冲区,待RDB发送完成后,再将缓冲区中的命令发送给从节点(保证数据完整性)。

2. 初始化同步(全量复制)

当从节点首次连接主节点重连时无法进行增量复制(如运行ID变化、偏移量超出积压缓冲区范围),会触发全量复制,流程如下:

mermaid
sequenceDiagram
    participant 从节点(Slave)
    participant 主节点(Master)
    从节点->>主节点: 发送PING命令(确认连通性)
    主节点->>从节点: 返回PONG(连通)
    从节点->>主节点: 发送AUTH命令(若主节点有密码)
    主节点->>从节点: 返回OK(认证通过)
    从节点->>主节点: 发送PSYNC ? -1(请求同步,?表示未知运行ID,-1表示全量复制)
    主节点->>从节点: 返回FULLRESYNC <runid> <offset>(通知全量复制,携带主节点运行ID和当前偏移量)
    主节点->>主节点: 执行BGSAVE(后台生成RDB文件,不阻塞主进程)
    主节点->>主节点: 将BGSAVE期间的写命令存入**复制缓冲区**(避免数据丢失)
    主节点->>从节点: 发送RDB文件(从节点接收并保存)
    从节点->>从节点: 清空当前数据库(`FLUSHDB`/`FLUSHALL`)
    从节点->>从节点: 加载RDB文件(阻塞,直到加载完成)
    主节点->>从节点: 发送复制缓冲区中的命令(从节点执行,追上BGSAVE期间的写操作)
    从节点->>主节点: 进入增量同步阶段(后续写命令实时同步)

全量复制的开销

  • 主节点:BGSAVE需要CPU和内存(生成RDB),发送RDB需要网络带宽。
  • 从节点:加载RDB需要IO和CPU(阻塞服务)。
  • 优化:尽量避免频繁全量复制(如合理设置积压缓冲区大小)。

3. 增量同步(实时同步)

全量复制完成后,主节点会将所有写命令(如SETDEL)实时同步给从节点,保持主从数据一致,流程如下:

mermaid
sequenceDiagram
    participant 主节点(Master)
    participant 从节点(Slave)
    主节点->>主节点: 执行写命令(如`SET key value`)
    主节点->>主节点: 更新`master_repl_offset`(偏移量+命令字节数)
    主节点->>主节点: 将命令写入**复制缓冲区**(每个从节点一个)
    主节点->>主节点: 将命令写入**积压缓冲区**(公共环形缓冲区)
    主节点->>从节点: 发送命令(通过TCP连接)
    从节点->>从节点: 执行命令(如`SET key value`)
    从节点->>从节点: 更新`slave_repl_offset`(与主节点偏移量一致)

增量同步的关键逻辑

  • 主节点通过复制缓冲区向从节点发送命令(每个从节点独立,避免相互影响)。
  • 主节点通过积压缓冲区保存最近的命令(供从节点重连时使用)。

4. 重连时的增量复制(PSYNC命令)

当从节点因网络问题断开连接,重连时会发送PSYNC命令PSYNC <runid> <offset>),主节点根据以下逻辑判断是否进行增量复制:

mermaid
flowchart TD
    A[从节点发送PSYNC <runid> <offset>] --> B{主节点runid是否匹配?}
    B -->|否| C[返回FULLRESYNC,全量复制]
    B -->|是| D{从节点偏移量是否在积压缓冲区范围内?}
    D -->|是| E[返回CONTINUE,增量复制(发送缓冲区中从<offset>到当前偏移量的命令)]
    D -->|否| C[返回FULLRESYNC,全量复制]

判断条件说明

  • runid匹配:确保重连的是同一个主节点(若主节点重启,runid变化,需全量复制)。
  • 偏移量在积压缓冲区范围内:积压缓冲区的起始偏移量≤从节点偏移量≤主节点当前偏移量(说明缓冲区保存了从节点缺失的命令,可增量复制)。

三、主从复制的关键机制与参数

1. 异步复制

Redis主从复制是异步的:主节点发送命令后,无需等待从节点确认,即可继续处理下一个请求。这种设计提高了主节点的吞吐量,但会导致从节点延迟(即从节点数据落后于主节点)。

延迟优化

  • 设置repl-disable-tcp-nodelay no(默认):主节点发送命令时,立即通过TCP发送(不合并),减少延迟(但增加网络包数量)。
  • 若网络带宽有限,可设置repl-disable-tcp-nodelay yes:合并多个命令一起发送(减少网络包),但增加延迟。

2. 只读从节点

从节点默认只读slave-read-only yes),防止从节点写入数据导致主从不一致。若需从节点写入(如特殊场景),可修改配置,但不推荐。

3. 积压缓冲区配置

  • repl-backlog-size:积压缓冲区大小(默认1MB)。建议设置为“主节点1分钟内的写命令字节数”(如主节点每分钟写10MB,设置为10MB),确保从节点重连时偏移量在缓冲区范围内。
  • repl-backlog-ttl:积压缓冲区的存活时间(默认3600秒)。当没有从节点连接时,主节点会在repl-backlog-ttl秒后清空缓冲区(释放内存)。

4. 从节点优先级

slave-priority(默认100):当主节点宕机时,哨兵会选择优先级最低的从节点晋升为新主节点(优先级越低,越优先)。若设置为0,该从节点不会被晋升为主节点。

四、主从复制的拓扑结构

Redis支持多种主从拓扑结构,选择需根据业务场景:

  1. 一主一从
  • 最简单的结构,主节点处理写请求,从节点处理读请求。
  • 适合小规模应用(如个人项目)。
  1. 一主多从
  • 主节点连接多个从节点(如1主5从),从节点分担读压力。
  • 缺点:主节点需向多个从节点发送命令,网络开销大(适合读极多写少的场景)。
  1. 链式复制(树状结构)
  • 主节点→从节点1→从节点2→…(从节点1作为从节点2的主节点)。
  • 优点:减轻主节点的网络压力(主节点只需向从节点1发送命令,从节点1再向其他从节点发送)。
  • 缺点:从节点2的延迟会比从节点1高(适合大规模集群)。

五、常见问题与优化

1. 全量复制频繁触发

原因

  • 从节点重连时,偏移量超出积压缓冲区范围(缓冲区太小)。
  • 主节点重启(运行ID变化)。
  • 从节点数量过多(主节点生成RDB的开销大)。

优化

  • 增大repl-backlog-size(如设置为10MB)。
  • 避免主节点频繁重启(如使用持久化机制,减少重启次数)。
  • 使用链式复制(减少主节点的从节点数量)。

2. 从节点延迟过高

原因

  • 主节点写请求过多(从节点无法及时同步)。
  • 网络带宽不足(主节点发送命令缓慢)。
  • 从节点性能差(如CPU、内存不足,无法及时执行命令)。

优化

  • 优化主节点写请求(如合并批量写操作)。
  • 提升网络带宽(如使用千兆网卡)。
  • 升级从节点硬件(如增加CPU核心、内存)。
  • 设置repl-disable-tcp-nodelay no(减少命令发送延迟)。

3. 主从数据不一致

原因

  • 异步复制:主节点宕机时,从节点未收到最新命令。
  • 从节点写入数据(slave-read-only no)。
  • 主节点持久化失败(如RDB生成失败,重启后数据丢失)。

优化

  • 使用哨兵或集群(实现高可用,当主节点宕机时,快速切换到从节点)。
  • 开启主节点持久化(appendonly yes,确保数据不丢失)。
  • 禁止从节点写入(slave-read-only yes)。

六、总结

Redis主从复制的核心原理是:

  • 全量复制:初始化从节点数据(通过RDB文件)。
  • 增量复制:实时同步主节点的写命令(通过复制缓冲区和积压缓冲区)。
  • 高效同步:通过复制偏移量(判断数据是否一致)、运行ID(判断是否为同一主节点)、积压缓冲区(避免全量复制)等机制,减少同步开销。

主从复制是Redis实现高可用和** scalability**的基础,结合哨兵(Sentinel)或集群(Cluster),可构建 robust 的分布式系统。

参考命令

  • 查看主从状态:info replication(主从节点都可执行)。
  • 设置从节点:slaveof <master-ip> <master-port>(从节点执行,Redis 5.0后改为replicaof)。
  • 取消从节点:slaveof no one(从节点执行,变为独立节点)。

参考配置

  • 主节点:bind 0.0.0.0(允许远程连接)、requirepass <password>(设置密码)。
  • 从节点:replicaof <master-ip> <master-port>(设置主节点地址)、masterauth <password>(主节点密码)、slave-read-only yes(只读)。