Skip to content

Redis 主从、哨兵、Cluster 全过程原理

Redis 高可用不能只背:

text
主从复制,哨兵故障转移,Cluster 分片。

要真正学会,需要知道:

  1. 主从复制第一次同步发生了什么。
  2. 增量复制怎么做。
  3. Master 宕机时哨兵每一步怎么判断和切换。
  4. Cluster 为什么有 16384 个 slot。
  5. MOVED 和 ASK 分别代表什么。
  6. 主从、哨兵、Cluster 分别解决什么,不能解决什么。

三种模式先分清

模式解决什么不解决什么
主从复制数据副本、读扩展自动故障转移
哨兵主从高可用、自动选主分片容量扩展
Cluster多 Master 分片、容量扩展、分片级故障转移单 key 热点、跨 slot 多 key 限制

主从复制总流程

mermaid
sequenceDiagram
    participant S as Slave
    participant M as Master
    S->>M: 建立复制连接
    S->>M: 发送 replconf / psync
    M->>M: 判断全量还是增量
    M->>S: 发送 RDB 快照或增量命令
    M->>S: 持续发送写命令流
    S->>S: 加载数据并重放命令

从库最终通过重放主库写命令,让数据逐步接近主库。

第一次全量同步

当 Slave 第一次跟 Master 建立复制关系,通常需要全量同步。

mermaid
flowchart TD
    A["Slave 请求同步"] --> B["Master 生成 RDB"]
    B --> C["Master 继续接收写命令"]
    C --> D["写命令进入复制缓冲区"]
    B --> E["RDB 发送给 Slave"]
    E --> F["Slave 清空旧数据并加载 RDB"]
    F --> G["Master 发送缓冲区增量命令"]
    G --> H["Slave 重放增量命令"]

为什么 Master 生成 RDB 时还要记录增量命令?

因为生成和传输 RDB 期间,Master 仍然可能处理写请求。如果不记录这段时间的写命令,Slave 加载 RDB 后会缺数据。

增量复制

Redis 会维护复制偏移量和复制积压缓冲区。

mermaid
flowchart TD
    A["Slave 断线"] --> B["记录自己复制到的 offset"]
    B --> C["重新连接 Master"]
    C --> D{"Master 积压缓冲区还有缺失数据吗"}
    D -- "有" --> E["增量发送缺失命令"]
    D -- "没有" --> F["重新全量同步"]

如果断线时间短,积压缓冲区还保留缺失命令,就能增量复制。否则只能全量同步。

主从复制为什么可能丢数据

Redis 主从复制默认是异步的。

mermaid
sequenceDiagram
    participant C as Client
    participant M as Master
    participant S as Slave
    C->>M: SET order:1 paid
    M-->>C: 返回成功
    M-->>S: 写命令还没复制过去
    M--xM: Master 宕机
    S->>S: 晋升为新 Master

这时新 Master 可能没有刚才那条写入。

所以 Redis 不适合作为强一致账本的唯一存储。

哨兵做什么

哨兵 Sentinel 负责:

  1. 监控 Master 和 Slave。
  2. 判断 Master 是否下线。
  3. 多个 Sentinel 达成故障判断。
  4. 选择一个 Slave 晋升为新 Master。
  5. 通知其他 Slave 复制新 Master。
  6. 通知客户端新的 Master 地址。

主观下线和客观下线

概念含义
主观下线 SDOWN一个 Sentinel 认为 Master 不可用
客观下线 ODOWN多个 Sentinel 达成一致,认为 Master 不可用
mermaid
flowchart TD
    A["Sentinel ping Master 失败"] --> B["标记主观下线"]
    B --> C["询问其他 Sentinel"]
    C --> D{"达到 quorum 吗"}
    D -- "是" --> E["客观下线"]
    D -- "否" --> F["继续监控"]

为什么不能单个 Sentinel 说了算?

单个 Sentinel 可能只是网络抖动或自己故障。多个 Sentinel 达成一致能降低误判。

哨兵故障转移过程

mermaid
flowchart TD
    A["Master 客观下线"] --> B["Sentinel 选举 Leader"]
    B --> C["Leader 选择一个 Slave"]
    C --> D["让该 Slave 执行 slaveof no one"]
    D --> E["新 Master 产生"]
    E --> F["其他 Slave 改为复制新 Master"]
    F --> G["通知客户端新地址"]

选择 Slave 时会考虑:

  1. Slave 是否在线。
  2. 复制偏移量是否较新。
  3. 优先级配置。
  4. 延迟和健康状态。

哨兵解决不了什么

哨兵不做分片。

如果单个 Master 内存不够、写 QPS 不够,哨兵帮不了。哨兵只是在主从架构下做高可用切换。

Cluster 为什么有 slot

Redis Cluster 把整个 key 空间分成 16384 个 hash slot。

mermaid
flowchart TD
    A["key"] --> B["CRC16(key)"]
    B --> C["对 16384 取模"]
    C --> D["得到 slot"]
    D --> E["slot 属于某个 Master"]

为什么不用直接 key -> 节点?

slot 是中间层。迁移和扩容时移动 slot 比直接管理海量 key 到节点映射更简单。

Cluster 写入过程

mermaid
flowchart TD
    A["客户端 SET user:1"] --> B["计算 slot"]
    B --> C["找到负责 slot 的 Master"]
    C --> D["发送命令"]
    D --> E["Master 写入"]
    E --> F["异步复制给自己的 Replica"]

成熟客户端会缓存 slot 到节点的映射,避免每次问集群。

MOVED 是什么

如果客户端访问错节点,节点会返回 MOVED:

text
MOVED 3999 192.168.1.10:6379

含义:

text
这个 slot 已经稳定归属到另一个节点,你应该更新 slot 映射。
mermaid
flowchart TD
    A["客户端访问错误节点"] --> B["节点返回 MOVED"]
    B --> C["客户端更新 slot 缓存"]
    C --> D["重新访问正确节点"]

ASK 是什么

ASK 出现在 slot 迁移过程中。

mermaid
flowchart TD
    A["slot 正在从 A 迁移到 B"] --> B["客户端访问 A"]
    B --> C["A 返回 ASK B"]
    C --> D["客户端临时去 B 执行"]
    D --> E["不立即永久更新 slot 映射"]

区别:

重定向含义
MOVEDslot 已经稳定迁移,更新缓存
ASKslot 正在迁移,临时访问一次

hash tag 是什么

Cluster 多 key 操作要求 key 在同一个 slot。

hash tag 可以指定参与计算 slot 的部分:

bash
user:{1001}:profile
user:{1001}:cart

{1001} 相同,这两个 key 会落到同一个 slot。

适合:

  1. 同一用户多个相关 key。
  2. 需要 Lua 或事务处理的一组 key。

不要滥用 hash tag,否则会把大量 key 打到同一个 slot,造成热点。

Cluster 故障转移

每个 Master 通常有 Replica。Master 故障后,Replica 可以被选为新 Master。

mermaid
flowchart TD
    A["Master A 故障"] --> B["集群节点检测故障"]
    B --> C["A 的 Replica 发起选举"]
    C --> D["获得多数 Master 投票"]
    D --> E["Replica 晋升为 Master"]
    E --> F["接管原 slot"]

Cluster 高可用仍然依赖复制。如果 Master 宕机前写入没同步给 Replica,也可能丢数据。

哨兵和 Cluster 怎么选

场景建议
数据量不大,只要高可用主从 + 哨兵
单机内存不够Cluster
写 QPS 单 Master 扛不住Cluster
需要跨 key 事务很多谨慎 Cluster,设计 hash tag 或避免跨 slot
强一致账本不适合只放 Redis

商业场景:缓存集群选型

医疗资产平台:

  1. 字典、资产详情、字段元数据缓存量不大:主从 + 哨兵足够。
  2. 如果资产详情 key 数量巨大,单机内存接近上限:考虑 Cluster。
  3. 如果某个机构资产特别热:Cluster 不一定解决单 key 热点,需要本地缓存和拆 key。
  4. 如果要同一资产多个 key 一起操作:用 hash tag 或避免跨 slot 事务。

常见坑

后果正确理解
以为主从不丢数据异步复制可能丢Redis 不做强一致账本
以为哨兵能扩容哨兵只做高可用容量扩展要 Cluster
以为 Cluster 解决热 Key单 key 仍落一个 slot热 Key 需本地缓存、拆 key
不处理 MOVED/ASK客户端访问失败或抖动使用支持 Cluster 的客户端
滥用 hash tagslot 热点只给必须同 slot 的 key 使用

面试标准回答

text
Redis 主从复制用于数据副本和读扩展,第一次同步通常由 Master 生成 RDB 发给 Slave,同时把期间的写命令放入复制缓冲区,Slave 加载 RDB 后再重放增量命令。断线后如果 Master 的复制积压缓冲区还保留缺失命令,可以增量复制,否则要全量同步。哨兵是在主从基础上做高可用,先主观下线,再多个 Sentinel 达成客观下线,选举 Sentinel Leader,选择合适 Slave 晋升为新 Master,并让其他 Slave 改为复制新 Master。Cluster 通过 16384 个 hash slot 分片,key 根据 CRC16 计算 slot,slot 归属某个 Master。MOVED 表示 slot 已稳定迁移,客户端要更新映射;ASK 表示迁移中临时重定向。主从、哨兵、Cluster 都不能保证 Redis 成为强一致账本,异步复制和故障切换仍可能丢数据。