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 限制和运维复杂度。