Redis 主从复制与 Sentinel 原理

→ 返回 Redis

主从复制解决数据副本和读扩展,Sentinel 在主从之上增加监控、通知与自动故障转移。二者都不提供强同步提交:Redis 默认复制是异步的,主节点确认写入时从节点可能还没收到。

部署演进

形态容量高可用适用
单机受单机内存限制无开发、可丢缓存
主从读扩展手动切换读多写少
Sentinel读扩展自动 failover中小规模、不需水平分片
Cluster水平分片分片 + 副本见 Cluster

复制流中的 replid 与 offset

每个主节点维护复制历史标识 replid,复制流每产生一个字节都会推进 offset。二元组:

(replication ID, replication offset)

可以标识数据集复制历史中的一个位置。从节点记录自己处理到的 replid 和 offset,重连时通过:

PSYNC <replid> <offset>

请求续传。主节点维护固定大小的环形 replication backlog;即使暂时没有从节点,复制流也可以在 backlog 开启时保留一段历史。

主节点复制流 offset ───────────────────────────────►
                      [ replication backlog 环形窗口 ]
                                   ▲
                              replica offset

如果从节点所缺的数据仍在 backlog 中,且 replid 属于主节点认可的历史,主节点返回 CONTINUE 并只补发缺失字节;否则返回 FULLRESYNC,执行全量同步。

故障切换后,新主节点会保留上一段复制历史作为辅助 replid(可在 INFO replication 看到 master_replid2 等字段),让原主或其他从节点有机会部分同步,而不是全部重新传 RDB。


全量同步

Replica                         Primary
   │──── PSYNC replid offset ─────►│
   │◄──── FULLRESYNC new-id off ───│
   │                               ├─ fork / BGSAVE
   │                               ├─ 同时缓存新写命令
   │◄──────── RDB 快照 ────────────│
   ├─ 清空旧数据并加载 RDB          │
   │◄──── 快照期间的增量命令 ──────│
   │◄──── 后续实时命令流 ──────────│

步骤:

  1. 从节点建立连接,认证并交换能力、端口等信息;
  2. 从节点发送 PSYNC;无法部分同步时进入 FULLRESYNC;
  3. 主节点后台生成 RDB,同时把新写入保存在复制客户端缓冲区;
  4. 主节点发送 RDB,从节点接收并加载;
  5. 主节点发送生成快照期间积累的写命令,随后进入稳定的命令流复制。

主节点可采用磁盘式 RDB,也可配置 diskless replication 通过 socket 直接把快照流发送给从节点。无盘方式减少磁盘中转,但仍有 fork、网络和 COW 成本。

多个从节点同时请求全量同步时,主节点在条件允许时会复用一次后台快照;批量重启、网络抖动或 backlog 太小仍可能造成全量同步风暴。


部分同步为什么会失败

原因结果与处理
断线太久,缺失字节已被环形 backlog 覆盖全量同步;增大 repl-backlog-size
replid 不属于当前或可追溯的复制历史全量同步
主节点重启且复制历史无法衔接全量同步;重要节点启用合适持久化
从节点首次连接没有可续传位置,执行全量同步

backlog 大小应覆盖“峰值写入字节速率 × 期望容忍的断线时间”,并保留余量。例如写复制流 20 MB/s,希望容忍 60 秒断线,理论下限约 1.2 GB,而不是只按 key 数估算。


复制一致性与安全边界

Redis 默认异步复制:

客户端写入 → 主节点执行并返回 → 命令异步发往从节点

因此存在:

  • 主节点已返回成功、命令尚未到达从节点时宕机,故障切换后该写入丢失;
  • 从库读取可能落后,出现“刚写完却读不到”;
  • 网络分区中的旧主若仍对外服务,可能形成脑裂写入。

WAIT numreplicas timeout 可以等待指定数量副本确认到达当前 offset,缩小丢数据概率,但它不是分布式事务或严格线性一致提交;超时、故障窗口和持久化策略仍需考虑。

min-replicas-to-write 1
min-replicas-max-lag 10
replica-read-only yes

前两项可在可用副本不足时让主节点拒绝写,降低脑裂旧主持续接单的风险,代价是网络异常时牺牲可用性。


Sentinel 故障检测与切换

建议至少 3 个独立 Sentinel,并让它们跨故障域部署。Sentinel 持续监控主从节点和其他 Sentinel:

PING 超时
  ▼
SDOWN(某个 Sentinel 主观下线)
  ▼ 向其他 Sentinel 询问,达到 quorum
ODOWN(主节点客观下线)
  ▼
Sentinel 竞选本轮故障转移 Leader
  ▼
选择从节点并执行 SLAVEOF NO ONE
  ▼
其余从节点改为复制新主,客户端发现新主

quorum 是判定 ODOWN 所需的 Sentinel 同意数;真正授权故障转移还需要 Sentinel 多数派。两者不是同一个概念,所以“quorum 配 1”并不代表单 Sentinel 永远能完成切换。

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

新主选择考虑因素

Sentinel 会过滤已下线、长时间断联或配置为不参与提升的从节点,再综合 replica priority、复制进度和运行 ID 等因素选择。通常希望选择数据较新且优先级合适的副本,而不是简单随机选择。

客户端必须支持 Sentinel

客户端不能把旧主地址永久写死。Lettuce、Jedis 或 Redisson 的 Sentinel 模式会向 Sentinel 查询当前主节点,并在切换后重建连接。故障转移窗口内请求仍可能失败,业务端需要有限重试、幂等和熔断,避免无限重试风暴。


诊断与容量规划

INFO replication
ROLE
WAIT 1 1000

重点指标:

  • master_repl_offset 与从节点 offset 差值;
  • master_replid / master_replid2;
  • repl_backlog_size / repl_backlog_histlen;
  • master_link_status、master_last_io_seconds_ago;
  • 全量同步次数、网络吞吐、RDB fork/COW 和从节点加载耗时。

面试结论

Redis 通过 replid + offset 标识复制历史,从节点用 PSYNC 请求续传;所缺字节仍在 replication backlog 中就部分同步,否则主节点生成 RDB 做全量同步,再补发期间积累的命令。复制默认异步,Sentinel 负责检测、选举和主从切换,但不能消除复制窗口的数据丢失,需结合 min-replicas-*、WAIT、持久化、幂等与备份设计。


相关