Redis集群
搭建

主从复制模式
架构:1 个 Master + N 个 Slave,Master 负责读写,Slave 只读并异步复制 Master 数据
核心原理
全量同步:Slave 首次连接或主从断连过久,Master 执行
BGSAVE生成 ==RDB== 发给 Slave,再补发复制积压缓冲区写命令复制积压缓冲区:如果是主节点写的时候还会把命令写到这个缓冲区里,用于快照RDB之后的数据同步
增量同步(PSYNC):正常连接后,Master 将写命令异步发送给 Slave(使用复制积压缓冲区)。
复制是异步的,Slave 数据存在延迟,有短暂不一致。
优缺点
- ✅ 数据冗余(备份)、可读写分离减轻 Master 读压力。
- ❌ Master 宕机需手动切换(人工
SLAVEOF NO ONE),恢复时间长。 - ❌ 写能力和容量仍受限于单机 Master。
哨兵模式(Sentinel)
架构:在主从复制基础上,部署 Sentinel 集群(通常 ≥3 个奇数节点),专门负责监控、选主、通知客户端。
1 | ┌─ Sentinel1 |
Sentinel 三大功能
- 监控(Monitoring):Sentinel 定期向 Master/Slave 发送 PING,判断是否下线。
- 自动故障转移(Automatic Failover):
- Master 被判定 主观下线(SDOWN) → 多数 Sentinel 确认 客观下线(ODOWN)。
- Sentinel 选举 Leader(Raft-like 算法),由 Leader 从 Slave 中选新 Master(优先级→复制偏移量→runid)。
- 通知其余 Slave 与新 Master 同步,并更新自身配置。
- 配置提供者(Configuration Provider):客户端连接 Sentinel,询问当前 Master 地址,实现服务发现。
关键参数
quorum:认定 ODOWN 所需 Sentinel 同意数(通常设为节点数//2 + 1,如 3 节点设 2)。down-after-milliseconds:多久无响应判主观下线(通常 5000~30000ms)。
优缺点
- ✅ 自动故障转移,高可用,秒级恢复(通常 10~30 秒)。
- ✅ 兼容旧客户端(通过 Sentinel 获取 Master 地址)。
- ❌ 仍无数据分片,写/存储容量受限于单 Master 内存。
数据丢失情况
两种数据丢失的场景,主从和哨兵都一样:
异步复制丢失(Master 宕机),未同步数据随 Master 内存消失
没办法避免
脑裂双主写入覆盖丢失
当 Master 连接的 healthy Slave 数不足时,Master 停止接受写请求
为什么是哨兵?
为什么单独弄个哨兵来竞选,不用slave?
Sentinel 模式不让 Slave 自竞选,主要是因为 Slave 没有全局视角来判断 Master 是真宕还是网络分区,也没有多数派投票机制防止多 Slave 同时自封 Master 造成脑裂。此外客户端需要通过 Sentinel 获取新 Master 地址,Slave 无法承担这个配置中心角色。
分片集群模式
架构:去中心化的分布式架构,通常由 N 个 Master(N≥3)+ 各自的 Slave 组成,数据通过哈希槽(Hash Slot)分片存储。
1 | Client |
核心机制
- 16384 个哈希槽:
slot = CRC16(key) % 16384,每个 Master 负责一部分槽位。 - 客户端智能路由:客户端缓存槽位→节点映射;请求发到 wrong node 时返回
-MOVED(重定向)或-ASK(迁移中)。 - 内置高可用:每个分片是主从结构,主节点 fail 后经集群的所有Master节点投票,其 Slave 自动晋升为新主(==无需 Sentinel==)
- 动态扩缩容:通过
redis-cli --cluster reshard迁移槽位(在线迁移,有短暂 ASK 重定向)。
分片下的使用问题
为什么批量命令(MGET/MSET)失效?
协议限制:Redis 的命令执行是在单个节点内完成的。
MGET要求一次性返回所有值,如果数据不在一块,无法保证原子性和一致性Pipeline,如果发现这些 Key 属于不同的 Slot/Node,客户端会自动拆分这个 Pipeline:属于 Node A 的命令打包发一次,属于 Node B 的命令打包发一次
为什么 Lua 脚本会失效?
Lua 脚本是服务器端原子执行的。当你执行
EVAL script 2 k1 k2时,这个脚本会被发送到k1所在的节点执行可以使用HashTag来保证在同一个key:
{batch_001}:order:success:1001==路由视角:当这个 Key 被发送到 Cluster 时,Redis 会解析这个字符串,发现里面有
{},于是提取batch_001来计算 Slot。但是,计算完 Slot 后,这个 Key 的名字不会改变,依然带着{}存进去==
流程
第一步:主观下线(PFAIL)
当一个 Master 节点 A 发现另一个 Master 节点 B 在 cluster-node-timeout时间内无法连通时,A 会将 B 标记为 PFAIL(Possible Fail)。
第二步:通过 Gossip 传播
节点 A 会在 Gossip 协议中把这个 PFAIL消息广播给其他节点。
第三步:客观下线(FAIL)
如果一个节点收集到集群中超过半数(Majority)的 Master 节点都认为 B 是 PFAIL,那么这些节点会将 B 标记为 FAIL(客观下线)。
例如,集群有 5 个 Master,那么至少需要 3 个 Master 认为 B 挂了,B 才算 FAIL。
第四步:投票选举新 Master(Failover)
B 被标记为 FAIL 后,B 的 Slave 们会发起竞选:
- 延时竞选:Slave 会根据复制偏移量(谁的数据最新)和 Rank 计算出一个随机延时,数据越新、Rank 越小,延时越短,越先发起选举。
- 拉票:Slave 向集群中所有 Master 发送
FAILOVER_AUTH_REQUEST。 - 投票:Master 收到请求后,如果还没有投过票(每个 Epoch 周期内只能投一票),且确认 B 确实是 FAIL,就会回复
FAILOVER_AUTH_ACK。 - 当选:Slave 如果收到超过半数 Master 的 ACK,它就正式晋升为新的 Master。
- 广播:新 Master 广播
PONG消息,告知集群自己接管了哪些 Slot。
优缺点
- ✅ 水平扩展:突破单机内存/写瓶颈,多 Master 并行写入。
- ✅ 内置高可用,无单点(去中心化)。
- ❌ 客户端必须支持 Cluster 协议(Jedis / Lettuce 均支持)。
- ❌ 运维复杂,扩缩容需注意大 Key 迁移阻塞。
问题
==脑裂:==
主节点与从节点网络断开,客户端与主节点正常通信,从节点选取新的主节点,网络恢复就出现了两个主节点;==网络恢复后旧 Master 变 Slave 被新的做全量同步,分区期间写入旧 Master 的数据就丢失了==
解决:
- 哨兵:当 Master 连接的 healthy Slave 数不足时,Master 停止接受写请求【此时“写不可用,读仍可用”,不是宕机,而是主动降级为只读模式】,避免旧 Master 继续写入被覆盖
- Redis Cluster :通过多数派投票选主降低了脑裂概率,但因是异步复制,极端情况下仍可能丢失少量未同步数据
