Appearance
主从复制详解
单机 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 ONE2.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 地址。
