Skip to content

Redis 主从、哨兵与 Cluster ​

Redis 高可用和扩容最容易学混:主从、哨兵、Cluster 都和“多台 Redis”有关,但它们解决的问题完全不同。

一句话先分清:

主从复制解决“有副本和读扩展”;哨兵解决“主节点挂了自动切换”;Cluster 解决“单机容量和写入能力不够时做分片扩容”。

如果只背“主从、哨兵、集群”,面试追问“哨兵和 Cluster 区别”“为什么主从会丢数据”“MOVED 和 ASK 是什么”“为什么 Cluster 解决不了热 Key”时,就会答不深。

学习目标 ​

学完这一页你要能做到:

  1. 解释主从复制的全量同步和增量同步。
  2. 解释主从为什么是异步复制,为什么可能丢数据。
  3. 解释 Sentinel 主观下线、客观下线和故障转移流程。
  4. 解释 Cluster 的 16384 个 slot、MOVED、ASK、hash tag。
  5. 说清哨兵和 Cluster 的区别、适用场景和不适用场景。
  6. 能给出 Spring Boot / Redis 客户端选型上的注意点。
  7. 能排查主从延迟、故障切换、Cluster 热点和跨 slot 问题。

三种模式先对比 ​

模式核心目标数据是否分片是否自动故障转移典型适用
主从复制副本、读扩展否,主从保存同一份数据否读多写少、做备份副本
哨兵 Sentinel主从自动切换否,仍然是一份完整数据是单主容量够,但要高可用
Redis Cluster分片扩容 + 分片高可用是,按 slot 分散到多个 Master是单机内存或写入能力不够
mermaid
flowchart TD
    A["Redis 多节点方案"] --> B["主从复制"]
    A --> C["哨兵 Sentinel"]
    A --> D["Redis Cluster"]
    B --> E["Master 写<br/>Replica 复制和读"]
    C --> F["监控 Master<br/>自动选新主"]
    D --> G["多个 Master<br/>按 slot 分片"]

主从复制解决什么 ​

单机 Redis 有三个问题:

  1. 主机宕机后服务不可用。
  2. 所有读写都压在一台机器上。
  3. 数据只有一份,恢复风险高。

主从复制让一个 Master 把数据同步给一个或多个 Replica。

mermaid
flowchart TD
    A["客户端写请求"] --> B["Master"]
    B --> C["Replica 1"]
    B --> D["Replica 2"]
    E["客户端读请求"] --> C
    E --> D

注意:主从不是多主。一般情况下写请求进入 Master,Replica 负责复制和读扩展。

主从复制全过程 ​

从节点连接主节点后,会尝试使用 PSYNC 同步。

mermaid
sequenceDiagram
    participant R as Replica
    participant M as Master
    R->>M: 建立连接
    R->>M: REPLCONF 上报能力
    R->>M: PSYNC replid offset
    M->>M: 判断全量还是增量
    alt 需要全量同步
        M->>M: fork 子进程生成 RDB
        M-->>R: 发送 RDB
        M-->>R: 发送 RDB 期间积累的写命令
    else 可以增量同步
        M-->>R: 从复制积压缓冲区发送缺失命令
    end
    R->>R: 加载数据并持续重放命令

全量复制 ​

全量复制通常发生在:

  1. Replica 第一次连接 Master。
  2. Replica 断线太久,缺失的 offset 已不在复制积压缓冲区。
  3. Master 复制 ID 变化,无法继续增量。

流程:

mermaid
flowchart TD
    A["Replica 请求同步"] --> B["Master fork 子进程"]
    B --> C["生成 RDB 快照"]
    C --> D["发送 RDB 给 Replica"]
    D --> E["Replica 清空旧数据并加载 RDB"]
    B --> F["Master 持续接收写命令"]
    F --> G["写命令进入复制缓冲"]
    E --> H["Replica 重放缓冲命令"]
    H --> I["进入持续复制"]

为什么生成 RDB 期间还要记录写命令:因为 Master 不会停写。生成和传输 RDB 的时间窗口里产生的新写入,如果不补给 Replica,Replica 加载完快照后就会缺数据。

增量复制 ​

Redis 维护:

机制作用
replication id标识当前 Master 的复制历史
offset写命令流偏移量
replication backlog复制积压缓冲区,保存最近一段写命令

Replica 短暂断线后重新连接,如果它缺失的 offset 仍在 backlog 中,Master 只发缺失命令,不用重新发完整 RDB。

mermaid
flowchart TD
    A["Replica 断线"] --> B["记录已复制 offset"]
    B --> C["重新连接 Master"]
    C --> D{"backlog 是否还有缺失命令"}
    D -- "有" --> E["增量复制"]
    D -- "没有" --> F["全量复制"]

增量复制的意义是降低网络、CPU、磁盘和加载成本。

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

Redis 主从复制默认是异步复制。Master 写成功返回给客户端时,命令可能还没复制到 Replica。

mermaid
sequenceDiagram
    participant C as Client
    participant M as Master
    participant R as Replica
    C->>M: SET order:1001 paid
    M-->>C: 返回成功
    M-->>R: 复制还没完成
    M--xM: Master 宕机
    R->>R: 晋升为新 Master

如果刚才那条写命令没有复制过去,新 Master 就没有这条数据。

降低风险的方式:

  1. 核心事实数据落 MySQL,不只放 Redis。
  2. 使用 AOF/RDB 减少重启丢失窗口,但仍不是强一致。
  3. 关键写入可使用 WAIT 等待副本确认,但会增加延迟,也不能绝对保证所有故障场景不丢。
  4. 业务层做幂等、状态机和补偿。

主从复制配置 Demo ​

主节点一般不需要特殊配置。从节点配置:

conf
replicaof 127.0.0.1 6379

命令方式:

bash
redis-cli -p 6380 replicaof 127.0.0.1 6379

查看复制状态:

bash
redis-cli -p 6379 info replication
redis-cli -p 6380 info replication

重点字段:

字段含义
role当前节点是 master 还是 slave/replica
connected_slavesMaster 连接的从节点数量
master_link_statusReplica 到 Master 的连接状态
master_repl_offsetMaster 当前复制偏移量
slave_repl_offsetReplica 已复制偏移量
master_last_io_seconds_agoReplica 多久没收到 Master 数据

哨兵解决什么 ​

主从复制本身不会自动把 Replica 提升为 Master。Master 宕机后,如果没有哨兵,需要人工执行:

bash
replicaof no one

哨兵 Sentinel 的职责是自动完成这件事。

Sentinel 负责:

  1. 监控 Master、Replica、其他 Sentinel。
  2. 判断 Master 是否下线。
  3. 多个 Sentinel 达成客观下线。
  4. 选举一个 Sentinel Leader。
  5. 选择一个 Replica 晋升为新 Master。
  6. 让其他 Replica 复制新 Master。
  7. 通知客户端当前 Master 地址变化。

主观下线和客观下线 ​

概念含义
SDOWN 主观下线某一个 Sentinel 认为 Master 不可用
ODOWN 客观下线达到 quorum 数量的 Sentinel 都认为 Master 不可用
mermaid
flowchart TD
    A["Sentinel ping Master 超时"] --> B["标记 SDOWN"]
    B --> C["询问其他 Sentinel"]
    C --> D{"达到 quorum"}
    D -- "否" --> E["继续观察"]
    D -- "是" --> F["标记 ODOWN"]
    F --> G["开始故障转移"]

为什么要有客观下线:单个 Sentinel 可能因为网络抖动、自己所在机器故障、短暂 GC 而误判。多个 Sentinel 达成一致,误判概率更低。

哨兵故障转移全过程 ​

mermaid
flowchart TD
    A["Master 客观下线"] --> B["Sentinel 之间选举 Leader"]
    B --> C["Leader 选择合适 Replica"]
    C --> D["让该 Replica 执行 replicaof no one"]
    D --> E["新 Master 产生"]
    E --> F["其他 Replica 改为复制新 Master"]
    F --> G["Sentinel 发布新 Master 信息"]
    G --> H["客户端刷新连接"]

选择 Replica 时通常会考虑:

  1. 复制延迟是否小。
  2. Replica 优先级。
  3. 复制 offset 是否更靠前。
  4. 节点是否在线、健康。

哨兵故障转移期间可能出现短暂不可用和少量数据丢失窗口,所以业务仍要有重试、幂等和降级。

哨兵配置 Demo ​

sentinel.conf 示例:

conf
port 26379
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 monitor mymaster 127.0.0.1 6379 2监控名为 mymaster 的 Master,quorum 为 2
down-after-milliseconds多久无响应后主观下线
failover-timeout故障转移超时时间
parallel-syncs新主产生后,同时允许多少 Replica 重新同步

启动:

bash
redis-sentinel sentinel.conf

生产建议部署奇数个 Sentinel,例如 3 个或 5 个,放在不同机器或故障域里。

哨兵适合和不适合 ​

适合:

  1. 单个 Master 容量够。
  2. 写入压力单 Master 扛得住。
  3. 核心目标是自动故障转移。
  4. 希望架构比 Cluster 简单。

不适合:

  1. 单机 Redis 内存不够。
  2. 单 Master 写入能力不够。
  3. 需要多 Master 分摊写流量。
  4. 已经出现明显数据倾斜或容量瓶颈。

一句话:哨兵是高可用,不是水平扩容。

Cluster 解决什么 ​

Redis Cluster 把 key 空间拆成 16384 个 hash slot,每个 Master 负责一部分 slot。

mermaid
flowchart TD
    A["Key"] --> B["CRC16(key) % 16384"]
    B --> C["slot"]
    C --> D{"slot 属于哪个 Master"}
    D --> E["Master A"]
    D --> F["Master B"]
    D --> G["Master C"]

Cluster 解决两个问题:

  1. 多个 Master 保存不同数据,容量可以横向扩展。
  2. 多个 Master 分担写请求,吞吐可以横向扩展。

每个 Master 通常还有 Replica,用于分片级故障转移。

mermaid
flowchart TD
    A["Master A<br/>slot 0-5460"] --> B["Replica A1"]
    C["Master B<br/>slot 5461-10922"] --> D["Replica B1"]
    E["Master C<br/>slot 10923-16383"] --> F["Replica C1"]

为什么是 16384 个 slot ​

如果直接让 key 映射到节点,扩容时需要移动大量 key 的映射关系。slot 是中间层:key 映射到 slot,slot 再归属节点。扩容时迁移 slot,比维护海量 key 到节点映射更容易。

mermaid
flowchart TD
    A["key"] --> B["slot"]
    B --> C["node"]
    D["扩容"] --> E["把部分 slot 迁移给新节点"]

Cluster 写入流程 ​

mermaid
flowchart TD
    A["客户端 SET user:1"] --> B["客户端计算 slot"]
    B --> C["根据 slot 缓存找 Master"]
    C --> D["发送命令"]
    D --> E{"节点是否负责该 slot"}
    E -- "是" --> F["执行命令"]
    E -- "否" --> G["返回 MOVED 或 ASK"]

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

MOVED 和 ASK ​

重定向含义客户端动作
MOVEDslot 已经稳定归属到另一个节点更新 slot 缓存,重新请求正确节点
ASKslot 正在迁移,临时去目标节点执行只临时跳转一次,不永久更新映射

MOVED 示例:

text
MOVED 3999 192.168.1.10:6379

ASK 常见于 resharding 过程中,slot 正在从旧节点迁到新节点。

hash tag 和跨 slot ​

Cluster 下多 key 命令要求这些 key 在同一个 slot。

跨 slot 错误示例:

bash
MGET user:1:name user:1:cart

如果两个 key 落在不同 slot,可能报错。

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

bash
SET user:{1001}:name "Tom"
SET user:{1001}:cart "cart-json"
MGET user:{1001}:name user:{1001}:cart

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

不要滥用 hash tag。如果所有租户都写成 {global},就会把大量 key 强行打到一个 slot,造成热点。

Cluster 为什么解决不了单 Key 热点 ​

Cluster 能把不同 key 分散到不同 Master,但同一个 key 仍然只能落在一个 slot,一个 slot 只归一个 Master。

mermaid
flowchart TD
    A["hot:asset:A001"] --> B["slot 8888"]
    B --> C["Master B"]
    D["大量请求"] --> C
    E["其他 Master"] --> F["仍然空闲"]

所以:

  1. 单机容量不够,Cluster 有用。
  2. 大量不同 key 写入,Cluster 有用。
  3. 单个热 Key 被打爆,Cluster 不一定有用。

单 Key 热点要用本地缓存、多级缓存、逻辑过期、请求合并、限流、拆 Key 等方案。

Cluster 配置 Demo ​

节点配置:

conf
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 15000
appendonly yes

创建 3 主 3 从:

bash
redis-cli --cluster create \
  127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \
  127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
  --cluster-replicas 1

查看状态:

bash
redis-cli -c -p 7000 cluster nodes
redis-cli -c -p 7000 cluster info
redis-cli -c -p 7000 cluster slots

-c 表示使用 Cluster 模式客户端,能自动跟随重定向。

Spring Boot 客户端注意点 ​

Sentinel 模式关注的是“如何发现当前 Master”:

yaml
spring:
  data:
    redis:
      sentinel:
        master: mymaster
        nodes:
          - 127.0.0.1:26379
          - 127.0.0.1:26380
          - 127.0.0.1:26381

Cluster 模式关注的是“如何处理 slot 和重定向”:

yaml
spring:
  data:
    redis:
      cluster:
        nodes:
          - 127.0.0.1:7000
          - 127.0.0.1:7001
          - 127.0.0.1:7002

注意:

  1. 客户端必须支持 Cluster。
  2. 批量操作要考虑跨 slot。
  3. Lua 脚本涉及多个 key 时要保证同 slot。
  4. 连接池、超时、重试要和业务 SLA 匹配。

哨兵和 Cluster 怎么选 ​

mermaid
flowchart TD
    A["选择 Redis 架构"] --> B{"单机内存或写入能力够吗"}
    B -- "够" --> C{"是否需要自动故障转移"}
    C -- "是" --> D["主从 + 哨兵"]
    C -- "否" --> E["单机或主从,适合非关键缓存"]
    B -- "不够" --> F["Redis Cluster"]
    F --> G["关注 slot、跨 slot、热点和迁移"]
业务情况推荐
数据量小,只要故障自动切换主从 + 哨兵
读多写少,要读扩展主从 + 哨兵,读写分离
单机内存不够Cluster
单 Master 写 QPS 不够Cluster
依赖大量跨 key Lua 或事务优先哨兵,或用 hash tag 重构
单 Key 热点严重Cluster 不是根治,优先热点治理

生产排查 ​

主从延迟 ​

看:

bash
info replication

重点:

  1. Master 和 Replica offset 差距。
  2. master_link_status 是否 up。
  3. 网络是否抖动。
  4. 是否有大 Key 写入。
  5. 从库 CPU、磁盘、AOF 是否慢。

哨兵切换异常 ​

看:

  1. Sentinel 日志。
  2. quorum 是否合理。
  3. Sentinel 是否部署在不同故障域。
  4. 客户端是否正确通过 Sentinel 获取新 Master。
  5. 切换后旧 Master 是否被降级为 Replica。

Cluster 访问异常 ​

看:

  1. 客户端是否支持 Cluster。
  2. 是否频繁 MOVED / ASK。
  3. slot 是否迁移中。
  4. 是否跨 slot 多 key 操作。
  5. 是否有热点 slot 或大 Key。

Cluster 节点负载不均 ​

原因可能是:

  1. slot 分布不均。
  2. 大 Key 落在某节点。
  3. 热 Key 落在某节点。
  4. 某个业务租户 key 使用 hash tag 过度集中。

排查:

bash
redis-cli -c -p 7000 cluster slots
redis-cli -c -p 7000 cluster nodes
redis-cli --bigkeys
redis-cli --hotkeys

商业场景:医疗资产平台 ​

需求推荐模式
字典、配置、资产详情缓存,数据量不大主从 + 哨兵
资产详情缓存数量非常大,单机内存不够Cluster
某些资产或机构极热本地缓存、逻辑过期、热点治理
同一资产多个 key 要一起操作使用 hash tag 或避免跨 slot 事务
核心订单、支付、审计事实落 MySQL,Redis 只做缓存

常见误区 ​

误区正确理解
主从就是高可用主从只复制数据,自动切换要哨兵或 Cluster
加 Replica 能提升写能力写仍然进入 Master,Replica 主要读扩展和容灾
哨兵能解决容量问题哨兵不分片,容量仍受单 Master 限制
Cluster 能解决所有热点单 Key 热点仍在一个 slot
Cluster 可以随便多 key 操作跨 slot 多 key 受限,要 hash tag 或重构
Redis 多副本就强一致默认异步复制,故障切换仍可能丢数据

面试标准回答 ​

主从、哨兵、Cluster 区别 ​

text
主从复制解决数据副本和读扩展,Master 负责写,Replica 复制数据并可承担读请求,但主从本身不负责自动故障转移。哨兵建立在主从复制之上,负责监控 Master,经过主观下线、客观下线、Leader 选举后,把合适的 Replica 晋升为新 Master,所以哨兵解决的是高可用自动切换。Redis Cluster 通过 16384 个 hash slot 把 key 分散到多个 Master,每个 Master 可以有 Replica,解决的是单机容量和写入能力不足,同时具备分片级故障转移。哨兵不分片,Cluster 分片;哨兵客户端关注当前 Master,Cluster 客户端要处理 slot、MOVED、ASK 和跨 slot 限制。

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

text
Redis 主从复制默认是异步的。Master 写成功返回客户端时,命令可能还没有复制到 Replica。如果此时 Master 宕机,Replica 被哨兵或 Cluster 晋升为新 Master,尚未复制的数据就会丢失。可以通过 AOF、WAIT、副本延迟监控降低风险,但 Redis 不适合作为强一致账本唯一存储,核心事实数据仍要落数据库。

MOVED 和 ASK 区别 ​

text
MOVED 表示某个 slot 已经稳定归属到另一个节点,客户端应该更新本地 slot 缓存,并重新访问正确节点。ASK 表示 slot 正在迁移中,客户端临时去目标节点执行一次,不应立即永久更新 slot 映射。MOVED 是稳定重定向,ASK 是迁移期间的临时重定向。

Cluster 为什么解决不了单 Key 热点 ​

text
Cluster 是按 key 计算 hash slot 的,一个 key 只能落到一个 slot,一个 slot 只由一个 Master 负责。所以多个不同 key 可以分散到多个节点,但同一个热 Key 的流量仍然集中在一个 Master 上。单 Key 热点要靠本地缓存、多级缓存、逻辑过期、请求合并、拆 Key、限流等方式治理,而不是只加 Cluster 节点。

关联知识点 ​

知识点继续学习什么
主从哨兵 Cluster 全过程原理更细的同步、故障转移和 slot 过程
大 Key 与热 Key 治理Cluster 下热点和大 Key 风险
高并发缓存治理timeout、连接池、限流、生产排查
Redis 面试知识点标准回答和追问

本章小结 ​

主从复制是副本和读扩展,哨兵是主从自动故障转移,Cluster 是分片扩容和分片级高可用。选型时先看单机容量和写入能力是否够,再看是否需要自动切换,最后评估业务能否接受 Cluster 的跨 slot 限制和运维复杂度。