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 成为强一致账本,异步复制和故障切换仍可能丢数据。