Redis 主从复制与哨兵机制详解:从原理到高可用实战

Redis 主从复制与哨兵机制详解:从原理到高可用实战

1. 引言

Redis 作为高性能的键值存储系统,在生产环境中常面临两大挑战:单点故障 (一个节点宕机导致服务不可用)和读写压力 (单节点无法承载高并发读请求)。为了解决这些问题,Redis 提供了主从复制 (Master-Slave Replication)来实现数据冗余和读写分离,并进一步通过哨兵(Sentinel)实现自动故障转移,构建高可用的 Redis 服务体系。

本文将深入剖析主从复制的全量和部分同步原理、复制积压缓冲区的作用,以及哨兵如何通过监控、选主、故障转移来保障集群的持续可用。通过流程图和对比表格,帮助你彻底理解这些核心机制。


2. 主从复制基础

2.1 角色与特性

在 Redis 主从复制架构中:

  • 主节点(Master):负责处理写请求,同时将数据变更异步复制到一个或多个从节点。
  • 从节点(Slave):复制主节点的数据,可以处理读请求(实现读写分离),并在主节点故障时作为备选。

核心规则

  • 一个 Master 可以有多个 Slave
  • 一个 Slave 只能有一个 Master(树状结构也是通过中间节点作为 Master 实现,但本质上每个 Slave 只有一个直接上游)
  • 数据流向是单向的:只能从 Master 流向 Slave(写操作仅在 Master 执行,然后同步到 Slave)

2.2 解决的问题

目标 主从复制如何解决
高并发读 读写分离:Master 处理写,多个 Slave 处理读,提升整体吞吐量。
数据冗余 多个 Slave 持有数据副本,避免单点数据丢失。
高可用基础 Master 宕机后,Slave 可被提升为新的 Master(需哨兵配合)。

3. 主从复制原理

主从复制分为全量复制部分复制 两个阶段。Redis 2.8 版本引入 PSYNC 命令,替代了旧版的 SYNC,支持断线续传(部分复制),大幅提高了复制效率。

3.1 全量复制(Full Synchronization)

全量复制发生在以下场景:

  • Slave 第一次连接 Master
  • Slave 与 Master 断开时间过长,导致复制偏移量(offset)不在 Master 的复制积压缓冲区中
流程图

Master Slave Master Slave 启动或重连 执行 BGSAVE 生成 RDB 清空旧数据,加载 RDB 执行这些写命令,追上 Master 之后持续增量同步 PSYNC ? -1 (首次请求全量) +FULLRESYNC <replid> <offset> 发送 RDB 文件 发送复制积压缓冲区中的写命令

详细步骤
  1. 建立连接:Slave 根据配置的 Master IP 和端口,与 Master 建立 TCP 长连接。
  2. 发送 PSYNC :Slave 发送 PSYNC <replid> <offset>。若第一次连接,replid 为 ?,offset 为 -1,表示请求全量复制。
  3. Master 响应 :如果 Master 决定全量复制,返回 +FULLRESYNC <replid> <offset>,其中 replid 是该 Master 实例的复制 ID,offset 是当前的复制偏移量。
  4. 生成 RDB :Master 执行 BGSAVE 命令,生成当前数据快照的 RDB 文件。在此期间,所有新的写命令都会被记录到复制积压缓冲区(replication backlog buffer)中。
  5. 发送 RDB:Master 将 RDB 文件传输给 Slave。
  6. 清空并加载:Slave 清空自身旧数据,然后加载 RDB 文件,恢复数据状态。
  7. 发送缓冲区的命令:Master 将生成 RDB 期间缓存的写命令发送给 Slave。
  8. 执行命令:Slave 执行这些命令,使数据与 Master 最终一致。
  9. 持续同步:此后 Master 将新产生的写命令实时发送给 Slave,保持数据实时同步。

3.2 部分复制(Partial Synchronization)

当 Slave 与 Master 的网络断开后重连,如果 Master 的复制积压缓冲区中还保留了 Slave 断开期间丢失的写命令,则可以进行部分复制,避免全量 RDB 传输。

关键组件
  • 复制积压缓冲区:Master 维护的一个固定大小的环形队列(默认 1MB),用于缓存最近向所有 Slave 发送的写命令。每个命令都有对应的偏移量(offset)。
  • 复制偏移量(offset):Master 和每个 Slave 各自维护一个 offset,表示已复制的数据位置。
  • Master 运行 ID(replid):Master 实例的唯一标识。Slave 会保存自己正在复制的 Master 的 replid。如果重连后 Master 的 replid 发生了变化(例如主从切换),则只能全量复制。
流程图

Master Slave Master Slave 网络断开后重连 进入全量复制流程 alt [offset 在 backlog 范围内 && replid 匹配] [offset 太旧或 replid 不匹配] PSYNC <replid> <offset> +CONTINUE 发送从 offset 开始的缺失命令 +FULLRESYNC

过程说明
  1. Slave 重连后,向 Master 发送 PSYNC <replid> <offset>,携带自身记录的 Master replid 和当前的复制偏移量。
  2. Master 检查:如果 replid 与自身一致,并且 offset 仍然在复制积压缓冲区 的范围内(即 offset 大于缓冲区最旧数据的位置),则返回 +CONTINUE
  3. Master 将缓冲区中从 offset 开始的所有写命令发送给 Slave。
  4. Slave 接收并执行这些命令,完成数据追赶。
  5. 如果条件不满足,则进行全量复制

💡 PSYNC 的兼容性 :从 Redis 4.0 开始,支持 PSYNC2,进一步优化了故障转移后部分复制的场景。


4. 哨兵模式(Sentinel)

有了主从复制,当 Master 宕机时,虽然 Slave 可以继续提供读服务,但系统无法自动处理写请求,需要人工介入将某个 Slave 提升为 Master。哨兵(Sentinel)就是 Redis 提供的高可用解决方案:它可以监控主从节点的健康状态,并在 Master 故障时自动发起故障转移,选举新的 Master。

4.1 哨兵集群架构

哨兵本身也是一个分布式系统,通常部署多个实例(至少 3 个)组成集群,避免单点决策。
Redis 主从
哨兵集群
客户端
读写请求
感知地址变化
感知地址变化
感知地址变化
监控
监控
监控
监控
监控
监控
监控
监控
监控
投票选举
投票选举
投票选举
投票选举
投票选举
投票选举
投票选举
投票选举
投票选举
Client
Sentinel 1
Sentinel 2
Sentinel 3
Master
Slave 1
Slave 2

4.2 哨兵的核心工作流程

4.2.1 三个定时监控任务

每个哨兵实例会定时执行以下任务:

任务 命令 作用
每 10 秒 INFO 获取所有从节点信息,更新主从拓扑
每 2 秒 SENTINEL HELLO 频道 与其他哨兵交换信息,感知彼此存在
每 1 秒 PING 检查 Master、Slave、其他哨兵的存活状态
4.2.2 主观下线与客观下线
  • 主观下线(SDOWN) :当一个哨兵发现对 Master 的 PING 没有在规定时间内(down-after-milliseconds)得到有效回复,就认为该 Master 主观下线
  • 客观下线(ODOWN) :当足够数量quorum)的哨兵都认为该 Master 主观下线后,就会将其标记为客观下线,并触发故障转移流程。
4.2.3 领导者哨兵选举

一旦 Master 被标记为客观下线,哨兵集群需要选出一个领导者 来执行故障转移。选举基于 Raft 算法的简化版本:

  1. 每个客观下线后的哨兵都向其他哨兵发送 SENTINEL is-master-down-by-addr 命令,要求投票给自己。
  2. 哨兵遵循先到先得原则,为第一个请求投票。
  3. 获得超过半数 (且至少 quorum)票数的哨兵成为领导者。
  4. 如果在规定时间内未选出,则重试。

📌 特殊情况 :即使哨兵集群只有一个节点,也能独立完成故障转移(因为单节点自然满足超过半数的条件),但这种部署存在单点风险,生产环境强烈建议至少 3 个哨兵实例

4.2.4 故障转移(选举新 Master)

领导者哨兵执行以下步骤:
发现客观下线
筛选健康的 Slave
按优先级选择新 Master
向其他 Slave 发送 SLAVEOF 新 Master
更新配置并通知客户端

选举新 Master 的规则(依次比较):

  1. 优先级slave-priority(replica-priority)值越小优先级越高,为 0 表示不参与选举。
  2. 复制偏移量:offset 越大,表示数据越新,优先级越高。
  3. 运行 ID:如果以上都相同,选择 runid 最小的。

后续操作

  • 领导者将选中的 Slave 提升为 Master(发送 SLAVEOF NO ONE)。
  • 向其他 Slave 发送命令,让它们复制新的 Master。
  • 更新哨兵配置,当原 Master 恢复后,它会作为新 Master 的 Slave 加入。

5. 总结与最佳实践

5.1 主从复制 + 哨兵 = 高可用 Redis 集群

组件 主要作用
主从复制 数据冗余、读写分离、为高可用提供基础
复制积压缓冲区 实现部分复制,减少断线重连的数据传输量
哨兵 监控、自动故障转移、配置中心

5.2 实践建议

  1. 主从数量:每个 Master 挂载 1~3 个 Slave 即可,过多会增加 Master 的复制压力。
  2. 复制积压缓冲区 :根据网络稳定性和写吞吐量调整 repl-backlog-size(默认 1MB,建议根据业务计算:每秒写入量 × 网络恢复预期秒数)。
  3. 哨兵部署
    • 至少 3 个实例,且应部署在不同物理机/容器上。
    • quorum 一般设置为 ceil(哨兵总数/2)
  4. 客户端感知 :应使用支持哨兵的客户端(如 Jedis、Lettuce 的 Sentinel 模式),以便自动切换 Master 地址。
  5. 禁用危险命令 :建议在 Master 上禁用 FLUSHALLFLUSHDB,避免误操作导致所有 Slave 被同步清空。

5.3 全量与部分复制对比

维度 全量复制 部分复制
触发条件 首次连接、offset 太旧、replid 变化 网络短暂中断,offset 仍在缓冲区
数据传输 RDB 文件 + 缓冲区命令 仅缓冲区中的增量命令
开销 高(磁盘 I/O、网络带宽)
优化方向 增大 backlog、改善网络稳定性 -

6. 思考题

  1. 如果 Master 设置了 requirepass 密码,Slave 应该怎么配置才能成功复制?
  2. 哨兵选举领导者时,为什么需要超过半数的投票?
  3. 复制积压缓冲区设置过小会有什么后果?
相关推荐
冰小忆1 小时前
类变量在继承场景下的初始化规则是怎样的?
java·前端·数据库
YL200404261 小时前
MySQL-运维篇-主从复制
运维·数据库·mysql
Wzx1980121 小时前
MySQL什么时候索引失效反而提升效率?
数据库·mysql
AC赳赳老秦2 小时前
OpenClaw碎片时间利用:设置轻量化自动化任务,高效利用职场碎片时间
java·大数据·运维·服务器·数据库·自动化·openclaw
5201-2 小时前
向量数据库在 NPU 上的加速
数据库·pytorch·python
arbitrary192 小时前
自动化业务通报系统实现
大数据·数据库·python·jupyter
米饭不加菜2 小时前
Mermaid 流程图语法参考二
数据库·流程图
LCG元3 小时前
深耕多智能体编排,解锁复杂Agent开发之路
前端·数据库·人工智能
arronKler3 小时前
MySQL命令行导出数据库
c语言·数据库·mysql