# Redis 主从复制的实现原理是什么?
10 min read
Table of Contents
Redis 主从复制的实现原理是什么?
Redis 主从复制实现原理
【核心定义】
Redis 主从复制是通过命令传播机制,将主节点的数据变更操作实时同步到从节点,实现数据冗余和高可用的核心机制。
【关键要点】
- 全量同步(RDB快照):从节点首次连接或复制偏移量不匹配时,主节点生成RDB快照发送给从节点,完成基础数据同步
- 部分同步(命令传播):全量同步后,主节点将每个写命令通过复制积压缓冲区传播给从节点,实现增量更新
- 心跳检测:从节点每秒向主节点发送
REPLCONF ACK <offset>,维持连接活性并报告复制进度 - 无盘复制:Redis 2.8.18+支持,主节点直接将RDB数据通过网络发送给从节点,避免磁盘IO瓶颈
- 级联复制:从节点可以作为其他从节点的主节点,形成树状复制拓扑
【深度推导/细节】
复制建立过程(分步拆解)
Step 1 - 连接建立
从节点执行:SLAVEOF <master_ip> <master_port>1. 从节点保存主节点信息,清空自身数据2. 建立与主节点的socket连接3. 发送PING命令检测连接状态Step 2 - 身份验证
1. 如果主节点配置了requirepass,从节点发送AUTH命令2. 验证失败则复制终止,成功则继续下一步Step 3 - 端口监听
从节点发送:REPLCONF listening-port <port>告知主节点自己的监听端口,用于后续主节点向从节点推送数据Step 4 - 同步协商
1. 从节点发送:PSYNC <runid> <offset> - runid:主节点运行ID(40字符随机字符串) - offset:从节点当前复制偏移量(首次为-1)
2. 主节点响应: - +FULLRESYNC <runid> <offset>:需要全量同步 - +CONTINUE:可以部分同步Step 5 - 数据同步
情况A:全量同步(从节点offset=-1或不在复制积压缓冲区范围内)1. 主节点执行bgsave生成RDB快照2. 将RDB文件发送给从节点3. 从节点清空旧数据,加载RDB4. 主节点将生成RDB期间的写命令存入复制缓冲区5. RDB加载完成后,主节点发送缓冲区中的命令
情况B:部分同步(从节点offset在复制积压缓冲区中)1. 主节点从复制积压缓冲区找到offset之后的所有命令2. 直接发送这些命令给从节点复制积压缓冲区设计
# 复制积压缓冲区是主节点维护的固定大小环形队列class ReplicationBacklog: def __init__(self, size=1MB): # 默认1MB,可配置 self.buffer = bytearray(size) self.offset = 0 # 当前写入位置 self.size = size
def write(self, command): # 写入命令并更新offset # 如果缓冲区满,覆盖最旧的数据缓冲区大小计算:
建议大小 = 网络延迟(秒) × 主节点每秒写命令数 × 平均命令大小 × 2例如:延迟0.1s × 10000命令/秒 × 100字节 × 2 = 200KB实际配置通常为32MB-256MB【关联/对比】
Redis复制 vs MySQL复制
| 维度 | Redis主从复制 | MySQL主从复制 |
|---|---|---|
| 同步方式 | 异步(默认)/ 半同步(Redis 6.0+) | 异步/半同步/全同步 |
| 数据格式 | RDB快照 + Redis协议命令 | binlog事件 |
| 复制粒度 | 命令级复制 | 行级/语句级复制 |
| 延迟处理 | 复制积压缓冲区 | relay log |
| 故障恢复 | PSYNC 2.0支持部分重同步 | 基于GTID或binlog位置 |
Redis复制 vs Kafka副本
- 数据模型:Redis是内存KV,Kafka是持久化日志
- 一致性:Redis默认异步弱一致,Kafka支持ISR强一致
- 选举机制:Redis哨兵/集群选举,Kafka Controller选举
- 用途差异:Redis复制侧重高可用,Kafka复制侧重数据持久化
【版本差异】
Redis 2.8 之前
- 只有全量复制,网络闪断需要重新全量同步
- 复制中断后恢复效率极低
Redis 2.8(PSYNC 1.0)
- 引入部分重同步机制
- 新增复制积压缓冲区
- 支持断线重连后增量同步
Redis 4.0
- PSYNC 2.0:优化复制协议,解决重启后全量同步问题
- 混合持久化:RDB+AOF,加速重启恢复
Redis 6.0
- 无盘复制优化:支持socket直接传输RDB
- 副本读取:从节点可处理只读请求
- 多线程I/O:提升复制网络吞吐
Redis 7.0
- 多AOF文件:更精细的持久化控制
- 复制性能优化:减少主节点内存占用
『面试官追问』
Q1:主从复制延迟过大怎么办?
A:可以从四个层面优化:
- 网络层:主从同机房部署,使用万兆网络
- 配置层:
Terminal window # 增大复制积压缓冲区repl-backlog-size 256mb# 调整客户端输出缓冲区限制client-output-buffer-limit slave 512mb 256mb 60 - 架构层:
- 使用级联复制分散主节点压力
- 业务侧读写分离,对延迟不敏感查询走从节点
- 监控层:监控
master_repl_offset和slave_repl_offset差值
Q2:为什么Redis默认使用异步复制?
A:设计权衡的结果:
- 性能优先:异步复制不阻塞主节点,吞吐量高(10万+ QPS)
- 可用性:即使从节点故障,主节点仍可服务
- 一致性妥协:可能丢失最后几毫秒数据,但Redis定位是缓存
- 可配置性:Redis 6.0+支持WAIT命令实现同步复制
Q3:复制风暴问题如何解决?
A:复制风暴指大量从节点同时全量同步导致主节点负载过高:
- 树状复制:设置中间层从节点,分摊主节点压力
主节点 → 从节点A → 从节点B↓从节点C → 从节点D
- 错峰同步:分批重启从节点,避免同时全量同步
- 无盘复制:减少主节点磁盘IO压力
- 适当调大
repl-backlog-ttl:延长缓冲区保留时间
Q4:PSYNC 2.0解决了什么问题?
A:主要解决两个痛点:
-
主节点重启后全量同步:
- PSYNC 1.0:主节点重启后runid变化,触发全量同步
- PSYNC 2.0:引入
replid和replid2,重启后仍能识别旧复制关系
-
故障切换后的同步优化:
# 故障切换场景旧主:M1 (replid: R1, offset: 1000)新主:S1 (原从节点,继承R1为replid2)其他从节点:S2 (offset: 800)# PSYNC 2.0下,S2可以向S1发送:PSYNC R1 800 # 可以部分同步# 而PSYNC 1.0需要全量同步
Q5:如何保证复制数据的一致性?
A:多级保障机制:
- 偏移量校验:通过
master_repl_offset和slave_repl_offset比对 - 心跳检测:从节点每秒上报自身偏移量
- 数据校验:RDB文件传输时使用CRC64校验和
- 命令重放:从节点严格按顺序执行主节点命令
- 手动校验:使用
INFO replication和redis-cli --slave监控
Q6:复制超时相关参数有哪些?
A:关键参数及默认值:
repl-timeout 60 # 复制超时时间(秒)repl-ping-slave-period 10 # 主节点ping从节点间隔repl-disable-tcp-nodelay no # 是否启用Nagle算法设计考量:
repl-timeout=60:平衡网络延迟和故障检测灵敏度repl-ping-slave-period=10:足够频繁以快速发现故障,又不至于产生过多流量
总结要点:Redis主从复制的核心是PSYNC协议,通过复制积压缓冲区实现断线重连后的增量同步,设计上在性能和数据一致性间取得平衡,不同版本持续优化复制效率和可靠性。