4. 分布式缓存架构:Redis作为分布式缓存、Redis集群模式(主从/哨兵/Cluster)、缓存分片与一致性哈希
在单机缓存无法满足高并发与高可用场景时,分布式缓存成为必然选择。Redis 作为业界最主流的分布式缓存组件,提供了从主从复制到无中心化集群的完整演进路径。本节将深入剖析 Redis 的三种集群架构、缓存分片策略以及一致性哈希的核心原理,帮助你在 Spring Boot 项目中做出正确的架构选型。
4.1 Redis 作为分布式缓存的核心价值
Redis 之所以能成为分布式缓存的事实标准,主要得益于以下特性:
| 特性 | 说明 | 对缓存一致性的影响 |
|---|---|---|
| 纯内存操作 | 数据全部存储在内存中,读写延迟通常在微秒级 | 快速响应减少数据不一致窗口 |
| 丰富的数据结构 | 支持 String、Hash、List、Set、Sorted Set 等 | Hash 结构便于原子化更新部分字段 |
| 发布/订阅 | 支持消息通知机制 | 可用于缓存失效广播 |
| Lua 脚本 | 服务端原子执行多条命令 | 实现 CAS(Check-And-Set)操作 |
| 持久化 | RDB 快照 + AOF 日志 | 重启后快速恢复缓存数据 |
spring-boot-starter-data-redis 集成。选择哪种集群模式,直接决定了缓存一致性的实现复杂度与运维成本。
4.2 Redis 集群模式演进:主从 → 哨兵 → Cluster
Redis 的集群架构经历了三个重要阶段,每一阶段解决了上一阶段的痛点,同时也引入了新的权衡。
4.2.1 主从复制模式
主从模式是 Redis 高可用的基础。一个主节点(Master)负责写操作,多个从节点(Slave)负责读操作,数据通过异步复制同步到从节点。
主从模式的关键问题:
- 写瓶颈: 所有写操作集中在 Master,单点写入能力有限。
- 故障转移需手动: Master 宕机后,需要人工将从节点提升为主节点。
- 数据不一致: 异步复制导致从节点数据滞后,读取到过期数据。
4.2.2 哨兵模式
哨兵模式在主从基础上增加了自动故障转移能力。哨兵(Sentinel)是一个独立进程,负责监控 Master 和 Slave 的健康状态,并在 Master 宕机时自动选举新 Master。
| 哨兵功能 | 工作机制 | 对缓存一致性的影响 |
|---|---|---|
| 监控 | 每秒向所有节点发送 PING 命令 | 快速感知节点故障 |
| 自动故障转移 | 选举新 Master,更新客户端配置 | 切换期间缓存不可用,可能丢失未同步数据 |
| 配置提供 | 客户端通过哨兵获取当前 Master 地址 | 保证客户端始终连接可用节点 |
| 通知 | 通过发布/订阅通知客户端状态变化 | 支持客户端主动刷新连接 |
4.2.3 Cluster 集群模式
Redis Cluster 是官方提供的分布式解决方案,实现了数据自动分片(Sharding)和高可用。它去中心化,每个节点都保存集群元数据,客户端可以直连任意节点。
- 线性扩展: 增加节点即可线性提升吞吐量和存储容量。
- 自动故障转移: Master 宕机后,其 Slave 自动晋升为 Master。
- 无中心化: 每个节点都持有完整路由信息,不存在单点瓶颈。
4.3 缓存分片策略
缓存分片(Sharding)是将数据分散到多个 Redis 实例上的技术。分片策略直接决定了数据分布的均匀性、扩展的灵活性以及查询的效率。
4.3.1 三种主流分片策略对比
| 分片策略 | 实现方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 客户端分片 | 应用层通过哈希算法决定 key 写入哪个节点 | 实现简单,无额外组件 | 节点变更需修改客户端逻辑 | 中小规模、节点固定 |
| 代理分片 | 通过 Twemproxy、Codis 等代理层路由 | 客户端无感知,统一管理 | 代理层成为性能瓶颈和单点 | 需要统一运维管控 |
| Redis Cluster | 官方内置哈希槽分片 | 去中心化,自动重分片 | 客户端需支持 Cluster 协议 | 大规模、高可用要求高 |
4.3.2 哈希槽分片原理(Redis Cluster)
Redis Cluster 采用固定 16384 个哈希槽(Hash Slot)的分片方案。每个 key 通过 CRC16 算法计算哈希值,然后对 16384 取模,得到对应的槽位。每个 Master 节点负责一段连续的槽位区间。
// 哈希槽计算公式
slot = CRC16(key) % 16384
// 示例:3 个 Master 节点的槽位分配
// Node-1: 0 ~ 5460
// Node-2: 5461 ~ 10922
// Node-3: 10923 ~ 16383
4.4 一致性哈希:解决节点变更时的缓存雪崩
传统取模分片(hash(key) % N)在节点数量变化时,会导致大量 key 的映射关系改变,引发缓存雪崩——大量请求同时穿透到数据库。一致性哈希(Consistent Hashing)正是为解决这一问题而生。
4.4.1 一致性哈希核心原理
一致性哈希将整个哈希值空间组织成一个虚拟的圆环(Hash Ring),范围通常为 0 ~ 2^32-1。每个节点根据其 IP 或名称计算哈希值,放置在圆环上。每个 key 也计算哈希值,沿圆环顺时针找到第一个节点,即为该 key 的存储节点。
4.4.2 虚拟节点:解决数据倾斜
实际部署中,物理节点在哈希环上的分布可能不均匀,导致某些节点负载过高(数据倾斜)。虚拟节点(Virtual Node)技术为每个物理节点创建多个虚拟副本,均匀分布在环上,使数据分布更加均衡。
// 虚拟节点实现思路(伪代码)
public class ConsistentHash<T> {
private final HashFunction hashFunction;
private final int numberOfReplicas; // 每个物理节点的虚拟节点数
private final SortedMap<Integer, T> circle = new TreeMap<>();
public void addNode(T node) {
for (int i = 0; i < numberOfReplicas; i++) {
circle.put(hashFunction.hash(node.toString() + i), node);
}
}
public T getNode(Object key) {
if (circle.isEmpty()) return null;
int hash = hashFunction.hash(key);
// 找到第一个大于等于 hash 的虚拟节点
SortedMap<Integer, T> tailMap = circle.tailMap(hash);
Integer nodeHash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
return circle.get(nodeHash);
}
}
- 节点增加: 只有约 1/N 的 key 需要重新映射(N 为节点总数)。
- 节点减少: 只有该节点上的 key 需要迁移到其他节点。
- 对比传统取模: 节点从 3 台扩展到 4 台时,传统取模导致 75% 的 key 迁移;一致性哈希仅迁移约 25%。
4.5 架构选型决策矩阵
在 Spring Boot 项目中,选择哪种 Redis 集群模式需要综合考虑业务规模、一致性要求、运维能力等因素。以下决策矩阵可供参考:
| 评估维度 | 主从模式 | 哨兵模式 | Cluster 模式 |
|---|---|---|---|
| 数据量 | 单机内存上限(通常 < 64GB) | 单机内存上限 | 可扩展至 PB 级(通过增加节点) |
| QPS | 读:随从节点线性扩展;写:单点瓶颈 | 读:随从节点线性扩展;写:单点瓶颈 | 读写均随节点数线性扩展 |
| 高可用 | 需手动故障转移 | 自动故障转移(30s 内) | 自动故障转移(秒级) |
| 数据一致性 | 弱一致性(异步复制) | 弱一致性(故障转移可能丢数据) | 弱一致性(异步复制,支持 WAIT 命令) |
| 运维复杂度 | 低 | 中(需部署哨兵集群) | 高(需规划槽位、处理 resharding) |
| 客户端支持 | Lettuce/Jedis 原生支持 | Lettuce/Jedis 原生支持 | 需使用 Cluster 模式客户端 |
| Spring Boot 集成 | spring.redis.host |
spring.redis.sentinel.master |
spring.redis.cluster.nodes |
4.6 本章小结
分布式缓存架构的核心在于平衡性能、可用性与一致性。Redis 从主从复制到 Cluster 集群的演进,体现了分布式系统设计的经典权衡:
- 主从模式 适合读多写少、允许短暂不一致的小规模场景。
- 哨兵模式 在主从基础上实现了自动故障转移,适合对可用性有要求的中型业务。
- Cluster 模式 通过哈希槽分片和去中心化架构,支撑大规模、高并发的缓存需求。
- 一致性哈希 作为分片算法的基石,有效降低了节点变更时的缓存迁移成本。