📚 高级篇 13. 分布式缓存 - 分片集群架构与搭建实战
一、 核心痛点:为什么哨兵集群还不够?
主从集群 + 哨兵机制,完美解决了**“高并发读”和“高可用(防宕机)”**的问题。但是,它依然面临两座无法逾越的大山:
- 海量数据存储的物理极限: 无论你有多少个从节点,它们都只是主节点的“复读机”。如果你的总商品数据量高达 1TB,而单台服务器内存只有 64GB,系统直接崩溃。
- 高并发写的性能瓶颈: 整个集群依然只有一个 Master 在辛勤地处理写请求。如果双十一瞬间涌入 50 万的并发下单操作,单台 Master 的 CPU 和网络带宽会被瞬间打爆。
破局终极方案:分片集群 (Sharding Cluster)
既然一台 Master 扛不住写,存不下 1TB,那我们就搞 多台 Master!把 1TB 的数据切成好几块(分片),每台 Master 只存自己那一块,大家一起分摊写并发。
二、 分片集群的核心特征
真正的 Redis 分片集群(Redis Cluster,Redis 3.0 之后官方推出的方案)具有以下极其强悍的特征:
- 多主多从: 集群中包含多个 Master,每个 Master 保存不同分片的数据。每个 Master 还可以拥有自己的 Slave。
- 无中心架构(去中心化): 不需要再额外额署哨兵了! Master 节点之间会互相通过 PING 机制监控彼此的健康状态。如果某个 Master 挂了,集群内部会自动将其下属的 Slave 提拔为新 Master。
- 海量吞吐: 读请求和写请求被均匀地分发到了不同的 Master 上,真正实现了存储空间和并发读写能力的无限横向扩展。
三、 面试绝对核心:哈希槽 (Hash Slot) 机制
如果有 3 台 Master,当 Java 代码发来一个 set key value 命令时,Redis 怎么知道要把这个数据存到哪台机器上?又怎么保证下次 get key 的时候能去正确的机器上取出来?
这就是分片集群的灵魂所在——哈希槽 (Hash Slot) 。
🌟 运作原理详细推演:
-
固定槽位: Redis Cluster 会在整个集群中划分出 16384 个虚拟的哈希槽(编号从 0 到 16383)。
-
瓜分地盘: 这些槽位会被均匀地分配给现有的 Master 节点。
- 假设有 3 台 Master:
- Master 1 负责保管槽位:
0 ~ 5460 - Master 2 负责保管槽位:
5461 ~ 10922 - Master 3 负责保管槽位:
10923 ~ 16383
-
精准路由(CRC16 算法): * 当你执行
set name jack时,Redis 会拿这把钥匙(key = name)去进行一段极其快速的计算:利用 CRC16 算法算出一个 16 位的数字,然后再对 16384 取模。- 公式:
hash_slot = CRC16(key) % 16384 - 假设算出来的结果是
8888。系统一看,8888在 Master 2 的管辖范围内,于是这条数据就被精准投递到了 Master 2 上。
- 公式:
💡 面试降维打击: “在分片集群中,数据并不是直接绑定在某台物理节点上的,而是绑定在哈希槽上的。这种设计的绝妙之处在于极度灵活的扩容与缩容。如果公司业务猛增,我需要加一台新的 Master 4,我根本不需要停机,只需要从前 3 台机器上各自匀出一点槽位分给 Master 4 即可,数据会跟着槽位自动无缝迁移!”
四、 极速实操:在 Docker 中搭建 6 节点分片集群
为了让你能亲手感受哈希槽的魅力,我们继续使用 Docker 搭建一个经典的 “三主三从” (3 Master + 3 Slave) 的分片集群环境。
第 1 步:创建集群专属网络
Bash
docker network create redis-cluster-net
第 2 步:启动 6 个完全独立的 Redis 节点
这里为了演示方便,我们将开启 6 个容器(端口 8001 到 8006)。关键参数是必须开启 --cluster-enabled yes 宣告它们准备好加入分片集群。
(你可以将这 6 条命令依次在 PowerShell 中执行:)
Bash
docker run -d --name redis-node-1 --net redis-cluster-net -p 8001:6379 redis:latest redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
docker run -d --name redis-node-2 --net redis-cluster-net -p 8002:6379 redis:latest redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
docker run -d --name redis-node-3 --net redis-cluster-net -p 8003:6379 redis:latest redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
docker run -d --name redis-node-4 --net redis-cluster-net -p 8004:6379 redis:latest redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
docker run -d --name redis-node-5 --net redis-cluster-net -p 8005:6379 redis:latest redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
docker run -d --name redis-node-6 --net redis-cluster-net -p 8006:6379 redis:latest redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
第 3 步:一键分配槽位,创建集群!
此时 6 个节点都起来了,但它们还是一盘散沙。我们需要进入其中任意一个节点,执行一条命令,让 Redis 自动为我们分配主从关系并瓜分 16384 个哈希槽。
Bash
# 1. 进入 node-1 的内部终端
docker exec -it redis-node-1 bash
# 2. 告诉 Redis CLI 把这 6 个 IP 捏合成一个集群,并且每个 Master 配 1 个 Slave (--cluster-replicas 1)
redis-cli --cluster create \
172.18.0.2:6379 172.18.0.3:6379 172.18.0.4:6379 \
172.18.0.5:6379 172.18.0.6:6379 172.18.0.7:6379 \
--cluster-replicas 1
(注意:上面的 IP 地址 172.18.0.x 是 Docker 容器的内网 IP,你需要通过 docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis-node-1 这种方式先查出这 6 个容器的实际内网 IP 再进行替换。如果觉得麻烦,理解这个一键分配的核心思想即可!)
当你看到终端输出 [OK] All 16384 slots covered. 时,恭喜你,一个支撑百万并发的工业级分片集群宣告诞生!
学习总结
这节课的内容极其硬核,你已经彻底打通了 Redis 高并发架构的终极形态。
从今天起,遇到任何关于缓存容量瓶颈、写并发瓶颈的问题,你都可以自信地甩出**“分片集群 + 哈希槽”**这个王炸方案。这正是你在信息安全专业底蕴之上,所构建的极其坚实的工程实践能力。
虽然底层的哈希槽算法很完美,但是当我们回到 Spring Boot 项目中时,Java 客户端(Lettuce)该怎么向这个包含了多个 Master 的集群发起读写请求呢?如果它不小心把请求发错了机器,Redis 又会怎么处理?