高级篇 13. 分布式缓存 - 分片集群架构与搭建实战

6 阅读6分钟

📚 高级篇 13. 分布式缓存 - 分片集群架构与搭建实战

一、 核心痛点:为什么哨兵集群还不够?

主从集群 + 哨兵机制,完美解决了**“高并发读”“高可用(防宕机)”**的问题。但是,它依然面临两座无法逾越的大山:

  1. 海量数据存储的物理极限: 无论你有多少个从节点,它们都只是主节点的“复读机”。如果你的总商品数据量高达 1TB,而单台服务器内存只有 64GB,系统直接崩溃。
  2. 高并发写的性能瓶颈: 整个集群依然只有一个 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)

🌟 运作原理详细推演:

  1. 固定槽位: Redis Cluster 会在整个集群中划分出 16384 个虚拟的哈希槽(编号从 0 到 16383)。

  2. 瓜分地盘: 这些槽位会被均匀地分配给现有的 Master 节点。

    • 假设有 3 台 Master:
    • Master 1 负责保管槽位:0 ~ 5460
    • Master 2 负责保管槽位:5461 ~ 10922
    • Master 3 负责保管槽位:10923 ~ 16383
  3. 精准路由(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 又会怎么处理?