跳转到内容

Redis 哨兵与集群


单节点 ──▶ 主从复制 ──▶ 哨兵模式 ──▶ 集群模式
简单 读写分离 自动故障转移 水平扩展
无HA 无自动HA 单Master HA 多Master HA
模式高可用水平扩展复杂度适用场景
单节点开发/测试
主从复制❌(需人工切换)读扩展 ✅读多写少,可接受人工运维
哨兵模式✅ 自动故障转移读扩展 ✅写少、单 Master 能承载
集群模式✅ 自动故障转移读写均可扩展 ✅大数据量、高并发写

哨兵模式在主从复制基础上,增加若干 Sentinel(哨兵)节点监控集群健康状态,Master 宕机时自动选举新 Master:

Client
Sentinel 集群(奇数个,通常 3 个)
┌───────────┬───────────┬───────────┐
│Sentinel 1 │Sentinel 2 │Sentinel 3 │
└─────┬─────┴─────┬─────┴─────┬─────┘
│监控 │ │
┌─────▼─────┐ ┌──▼──────┐ ┌──▼──────┐
│ Master │─▶│ Slave 1 │ │ Slave 2 │
└───────────┘ └─────────┘ └─────────┘

哨兵的三大职责:

职责说明
监控(Monitoring)每秒向 Master/Slave/其他 Sentinel 发送 PING,检测节点存活
通知(Notification)节点异常时通过 API 通知运维人员或其他系统
自动故障转移(Failover)Master 宕机后,自动选举新 Master,更新从节点配置
主观下线(SDOWN):
单个 Sentinel 在 down-after-milliseconds 内未收到 Master 响应
──▶ 标记为"主观下线"(可能是网络抖动,单票不算数)
客观下线(ODOWN):
超过 quorum 个 Sentinel 都认为 Master 主观下线
──▶ 标记为"客观下线"(确认宕机,触发故障转移)
Sentinel Leader 选举:
Sentinel 间投票选出 Leader
──▶ Leader 负责执行故障转移
故障转移:
1. 从 Slave 中选出新 Master(按优先级、复制偏移量等)
2. 将其他 Slave 指向新 Master
3. 将客户端连接切换到新 Master
4. 原 Master 恢复后作为新的 Slave 加入
version: '3'
services:
redis-master:
image: redis:7.0
container_name: redis-master
ports:
- "6379:6379"
command: redis-server --requirepass 123456
redis-slave1:
image: redis:7.0
container_name: redis-slave1
ports:
- "6380:6379"
command: redis-server --requirepass 123456 --masterauth 123456 --replicaof redis-master 6379
redis-slave2:
image: redis:7.0
container_name: redis-slave2
ports:
- "6381:6379"
command: redis-server --requirepass 123456 --masterauth 123456 --replicaof redis-master 6379
sentinel1:
image: redis:7.0
container_name: sentinel1
ports:
- "26379:26379"
command: >
redis-sentinel /etc/redis/sentinel.conf
volumes:
- ./sentinel.conf:/etc/redis/sentinel.conf
sentinel.conf
port 26379
sentinel monitor mymaster redis-master 6379 2 # quorum = 2
sentinel auth-pass mymaster 123456
sentinel down-after-milliseconds mymaster 5000 # 5 秒无响应判主观下线
sentinel failover-timeout mymaster 10000 # 故障转移超时
sentinel parallel-syncs mymaster 1 # 同时重新配置的 Slave 数量
spring:
data:
redis:
sentinel:
master: mymaster # sentinel.conf 中配置的 master 名称
nodes:
- 192.168.1.10:26379
- 192.168.1.11:26379
- 192.168.1.12:26379
password: 123456
lettuce:
pool:
max-active: 8

客户端连接哨兵后,会自动感知 Master 切换,无需手动更改连接地址。


Redis Cluster 将数据分散到多个 Master 节点,每个 Master 负责一部分数据,所有节点共同对外提供服务:

Redis Cluster(3 Master + 3 Slave):
Master1 ──▶ Slave1 Master2 ──▶ Slave2 Master3 ──▶ Slave3
槽 0~5460 槽 5461~10922 槽 10923~16383

哈希槽(Hash Slot): Redis Cluster 将数据空间划分为 16384 个槽,每个 key 通过 CRC16(key) % 16384 计算所属槽,再路由到对应 Master:

SET user:1001 "Alice"
CRC16("user:1001") % 16384 = 7638
槽 7638 属于 Master2
数据写入 Master2

客户端请求到错误节点时,节点返回重定向指令:

客户端 ──▶ Master1(发送 SET user:1001)
└── 该 key 属于槽 7638,在 Master2
──▶ 返回 MOVED 7638 Master2:6379
客户端 ──▶ Master2(重新发送 SET user:1001)✅
version: '3'
services:
redis-node1:
image: redis:7.0
container_name: redis-node1
ports:
- "7001:7001"
- "17001:17001" # 集群总线端口(= 数据端口 + 10000)
command: >
redis-server
--port 7001
--cluster-enabled yes
--cluster-config-file nodes-7001.conf
--cluster-node-timeout 5000
--requirepass 123456
--masterauth 123456
redis-node2:
image: redis:7.0
container_name: redis-node2
ports:
- "7002:7002"
- "17002:17002"
command: >
redis-server
--port 7002
--cluster-enabled yes
--cluster-config-file nodes-7002.conf
--cluster-node-timeout 5000
--requirepass 123456
--masterauth 123456
# ... node3~node6 类似配置

初始化集群(6 节点:3 主 3 从):

Terminal window
redis-cli -a 123456 --cluster create \
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 127.0.0.1:7006 \
--cluster-replicas 1 # 每个 Master 配 1 个 Slave
spring:
data:
redis:
cluster:
nodes:
- 192.168.1.10:7001
- 192.168.1.10:7002
- 192.168.1.10:7003
- 192.168.1.11:7001
- 192.168.1.11:7002
- 192.168.1.11:7003
max-redirects: 3 # 最大重定向次数
password: 123456
lettuce:
cluster:
refresh:
adaptive: true # 自适应刷新集群拓扑(节点变化时自动更新)
period: 2000ms # 定期刷新间隔

// ❌ 跨槽的 MGET 会报错(key 不在同一槽)
redisTemplate.opsForValue().multiGet(List.of("user:1", "order:1"));
// ✅ 使用 Hash Tag 强制同槽({} 内的内容决定槽位)
// "user:{1001}:info" 和 "order:{1001}:latest" 都路由到槽 {1001} 所在的节点
redisTemplate.opsForValue().multiGet(List.of("user:{1001}:info", "order:{1001}:latest"));

事务(MULTI/EXEC)和 Lua 脚本只能操作同一节点上的 key,使用 Hash Tag 保证相关 key 在同一节点。

数据量 < 20GB 且单 Master 写入能够承载
└──▶ 哨兵模式(运维简单)
数据量大 或 写入 QPS 超过单节点上限(约 8~10 万)
└──▶ 集群模式(水平扩展)

对比项哨兵模式集群模式
Master 宕机恢复时间秒级(约 10~30 秒)秒级
数据分片❌ 单 Master 存全量数据✅ 数据分散到多 Master
最大存储容量单机内存上限理论无上限(加节点扩展)
跨节点操作无限制受哈希槽限制
运维复杂度中等较高
最少节点数1 Master + 1 Slave + 3 Sentinel6 个(3 主 3 从)