Skip to content

主从复制详解

  单机 Redis 有风险:宕机就全挂。主从复制是 Redis 高可用的基础,将数据从主节点复制到从节点,实现读写分离和数据冗余。

一、为什么需要主从复制?

单机 Redis 的问题:
  ❌ 单点故障:宕机全挂
  ❌ 读压力:单机 QPS 有上限
  ❌ 数据安全:磁盘坏了数据全丢

主从复制后:
  ┌──────────────┐
  │   Master      │  ← 写操作
  │  (主节点)     │
  └───┬────┬─────┘
      │    │
      ▼    ▼
  ┌──────┐ ┌──────┐
  │Slave1│ │Slave2│  ← 读操作
  └──────┘ └──────┘

  ✅ 读写分离:主写从读,分担压力
  ✅ 数据冗余:多个副本,防止丢失
  ✅ 高可用基础:哨兵/集群依赖主从

二、主从复制搭建

2.1 配置

bash
# 主节点(redis.conf)
# 无需特殊配置,默认就是主节点

# 从节点(redis.conf)
replicaof 192.168.1.100 6379     # 指定主节点 IP 和端口
masterauth 123456                # 主节点密码(如果有)
replica-read-only yes            # 从节点只读

2.2 命令行方式

bash
# 运行时动态指定主节点
redis-cli -p 6380
> REPLICAOF 192.168.1.100 6379

# 取消复制(变成独立主节点)
> REPLICAOF NO ONE

2.3 查看状态

bash
# 主节点
> INFO replication
# role:master
# connected_slaves:2
# slave0:ip=192.168.1.101,port=6379,state=online
# slave1:ip=192.168.1.102,port=6379,state=online

# 从节点
> INFO replication
# role:slave
# master_host:192.168.1.100
# master_port:6379
# master_link_status:up

三、主从复制原理

3.1 全量复制(首次同步)

全量复制流程:

  Slave                              Master
    │                                   │
    │  1. PSYNC ? -1(请求同步)         │
    │──────────────────────────────────→│
    │                                   │
    │  2. FULLRESYNC runid offset       │
    │←──────────────────────────────────│
    │                                   │
    │  3. Master 执行 BGSAVE 生成 RDB    │
    │                                   │
    │  4. 传输 RDB 文件                  │
    │←──────────────────────────────────│
    │                                   │
    │  5. Slave 清空旧数据,加载 RDB     │
    │                                   │
    │  6. 传输 RDB 期间的新命令(缓冲区)  │
    │←──────────────────────────────────│
    │                                   │
    │  7. Slave 执行缓冲区命令,完成同步  │

注意:

  • 全量复制期间,Slave 会清空已有数据
  • Master 使用复制缓冲区保存 RDB 生成期间的新命令
  • 复制缓冲区大小配置:repl-backlog-size 1mb

3.2 增量复制(断线重连后)

增量复制流程:

  Slave                              Master
    │                                   │
    │  PSYNC runid offset               │
    │──────────────────────────────────→│
    │                                   │
    │  CONTINUE(offset 在 backlog 中)  │
    │←──────────────────────────────────│
    │                                   │
    │  发送 offset 之后的命令            │
    │←──────────────────────────────────│
    │                                   │
    │  执行增量命令,追上主节点          │

  条件:
  ✅ Slave 的 runid 与 Master 一致
  ✅ Slave 的 offset 在 Master 的 backlog 中

3.3 复制偏移量(Replication Offset)

Master 和 Slave 各维护一个 offset:

  Master offset = 10000

    ├── Slave 1 offset = 10000  ← 完全同步
    ├── Slave 2 offset = 9980   ← 延迟 20 个命令
    └── Slave 3 offset = 9500   ← 延迟 500 个命令

  通过 offset 判断主从延迟程度

3.4 复制积压缓冲区(Replication Backlog)

Master 维护一个环形缓冲区:

  ┌────────────────────────────────────────────────────┐
  │ Backlog Buffer(环形,默认 1MB)                     │
  │                                                    │
  │ [...][offset=9990][offset=9991]...[offset=10000]   │
  │                                                    │
  │  Master 每执行一条写命令,就写入 Backlog              │
  │  Slave 断开重连后,如果 offset 还在 Backlog 中,     │
  │  则可以增量同步;否则需要全量同步                     │
  └────────────────────────────────────────────────────┘

四、常见拓扑结构

4.1 一主一从

┌──────────┐
│  Master   │
└────┬─────┘


┌──────────┐
│  Slave    │
└──────────┘

最简单,只有数据冗余,不支持读写分离

4.2 一主多从

          ┌──────────┐
          │  Master   │
          └──┬───┬───┘
             │   │
      ┌──────┘   └──────┐
      ▼                 ▼
┌──────────┐       ┌──────────┐
│  Slave 1 │       │  Slave 2 │
└──────────┘       └──────────┘

读写分离:Master 写,Slave 读
缺点:Master 压力大(向多个 Slave 传输数据)

4.3 树状(级联)

          ┌──────────┐
          │  Master   │
          └────┬─────┘


          ┌──────────┐
          │  Slave 1  │  ← 同时是 Slave 2 的 Master
          └────┬─────┘


          ┌──────────┐
          │  Slave 2  │
          └──────────┘

减轻 Master 压力,Slave 接力复制
缺点:延迟增加,链路更长

五、主从复制问题

5.1 数据不一致

问题:Master 已写入,Slave 还没同步,客户端读到旧数据

原因:
  - 主从网络延迟
  - Slave 处理不过来

解决:
  - 监控主从 offset 差值
  - 对于一致性要求高的场景,从 Master 读取

5.2 复制超时

conf
repl-timeout 60              # 复制超时(秒)

5.3 主从切换

Master 宕机后:
  1. 手动将一个 Slave 提升为 Master
     > REPLICAOF NO ONE

  2. 其他 Slave 指向新 Master
     > REPLICAOF 新Master IP 新Master端口

  3. 恢复旧 Master 作为 Slave 重新加入
     > REPLICAOF 新Master IP 新Master端口

  问题:手动操作,恢复慢,容易出错
  解决:使用 Sentinel 哨兵自动故障转移

六、面试要点

Q1:主从复制的原理是什么?

  首次连接全量复制(Master 生成 RDB → 传输 → Slave 加载 → 同步增量命令),后续通过 offset + backlog 增量复制。Master 所有写命令异步同步到 Slave。

Q2:全量复制和增量复制的区别?

  全量复制:首次连接或 offset 不在 backlog 中时,传输完整 RDB 文件。增量复制:断线重连后,只传输断开期间的命令,需要 offset 在 Master 的 backlog 中。

Q3:主从延迟怎么监控?

  通过 INFO replication 查看 Master 和 Slave 的 offset 差值。差值越大,延迟越严重。可配置监控告警,差值超过阈值时报警。

Q4:主从切换后,客户端怎么知道新 Master?

  纯主从模式需要手动修改客户端配置。生产环境使用 Sentinel 哨兵自动故障转移,客户端通过 Sentinel 获取当前 Master 地址。