跳转至

Redis 主从同步原理

一、为什么需要主从

  • 读写分离:主写从读,分担压力。
  • 高可用:主挂了,从可以晋升为主(Sentinel / Cluster)。
  • 数据冗余:多副本,不怕单节点故障。

二、全量同步(第一次连接)

从库第一次连接主库,主库不能直接发当前数据,因为从库要边收边追。流程:

  1. 从库发送 PSYNC ? -1(第一次不知道主库 runid)。
  2. 主库返回 +FULLRESYNC <runid> <offset>,表示要全量同步。
  3. 主库执行 BGSAVE 生成 RDB 快照(fork 子进程)。
  4. RDB 生成期间,新写命令写入 replication buffer(复制缓冲区)。
  5. RDB 发给从库,从库加载。
  6. 主库把 buffer 期间的写命令发给从库,从库重放。

完成后,进入增量同步阶段。

三、增量同步(断线重连)

网络抖动导致主从中断,重连后:

  1. 从库发送 PSYNC <runid> <offset>,告诉主库"我同步到这个偏移量了"。
  2. 主库判断:
  3. runid 匹配,且 offset 在复制积压缓冲区(repl_backlog)内:只发缺失部分。
  4. 不在缓冲区:只能做全量同步。

repl_backlog_size 默认 1MB,网络抖动久了就可能被覆盖,被迫全量。

四、命令传播(持续同步)

全量完成后,主库每执行一个写命令,就异步把命令发给所有从库。

从库默认只读replica-read-only yes)。

五、心跳与超时

  • 从库每秒发送 REPLCONF ACK <offset>,汇报同步进度。
  • 主库 repl-ping-replica-period 检查从库是否存活。
  • repl-timeout 超时则断开重连。

六、主从延迟

原因:

  • 主库写、从库重放是异步的。
  • 从库机器性能差、网络抖动。
  • 大 key 同步阻塞从库。

解决:

  • 监控 master_repl_offsetslave_repl_offset 差。
  • 关键读走主库(或强制读主逻辑)。
  • 避免大 key。

七、Sentinel 与 Cluster

Sentinel(哨兵)

  • 监控主从节点。
  • 主挂了自动选一个从晋升为主。
  • 客户端通过 Sentinel 发现主节点地址。

Cluster

  • 数据按 16384 个槽分布在多个主节点。
  • 每个主节点有从节点。
  • 去中心化,Gossip 协议通信。

高频追问

  • Redis 为什么不用 Paxos / Raft?主从复制是异步的,所以不能强一致;Sentinel 选主用 Raft 思想。
  • 复制积压缓冲区(repl_backlog)是环形缓冲区,主库所有从库共享,不是每个从库一份。