
目录
-
- [一、 为什么需要 Redis 分片集群? 🤔](#一、 为什么需要 Redis 分片集群? 🤔)
- [二、 Redis 分片集群是什么? 💡](#二、 Redis 分片集群是什么? 💡)
- [三、 散列插槽 (Slot) 是什么? (数据怎么分?) 📮](#三、 散列插槽 (Slot) 是什么? (数据怎么分?) 📮)
- [四、 如何搭建三主六从的 Redis 分片集群? 🐳🔧](#四、 如何搭建三主六从的 Redis 分片集群? 🐳🔧)
- [五、 分片集群的集群伸缩是什么? ➕➖](#五、 分片集群的集群伸缩是什么? ➕➖)
- [六、 如何使用 RedisTemplate 访问分片集群?💻](#六、 如何使用 RedisTemplate 访问分片集群?💻)
- [七、 分片集群的原理是什么? ⚙️🤝](#七、 分片集群的原理是什么? ⚙️🤝)
- [八、 分片集群的优缺点是什么?](#八、 分片集群的优缺点是什么?)
🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!
🌟了解 Redis 哨兵模式 请看 : Redis 哨兵模式:告别手动故障转移!
其他优质专栏: 【🎇SpringBoot】【🎉多线程】【🎨Redis】【✨设计模式专栏(已完结)】...等
如果喜欢作者的讲解方式,可以点赞收藏加关注,你的支持就是我的动力
✨更多文章请看个人主页: 码熔burning
好的,我们来详细地、用大白话聊聊 Redis 分片集群 (Redis Cluster),这次加上一些小表情增加点趣味性!😊
一、 为什么需要 Redis 分片集群? 🤔
想象一下,你开了一家生意爆火的小卖部 (单个 Redis 实例) 🏪。
- 问题一:地方不够大 (内存瓶颈) 😥:顾客越来越多,货架 (内存) 都堆满了,新商品放不下了。单个 Redis 服务器的内存是有限的,当数据量超过这台服务器的内存容量时,就存不下了。
- 问题二:老板忙不过来 (CPU/网络瓶颈) 🏃♂️💨:顾客排长队结账,老板一个人收钱、打包、找零,忙得团团转 (CPU 达到极限)。同时,店门口的路太窄 (网络带宽),进出的人太多,堵车了 🚗🚕🚙。单个 Redis 服务器的 CPU 处理能力和网络带宽也是有限的,当请求量非常大时,它会成为性能瓶颈,响应变慢。
- 问题三:老板病了就关门 (可用性问题) 🤒:万一老板生病了或者店里停电了 (服务器宕机),整个小卖部就得关门歇业,顾客买不到东西。单个 Redis 实例存在单点故障风险,一旦它挂了,整个服务就不可用了。
分片集群就是为了解决这些问题! 🎉
它的思路是:既然一个小卖部不够用,那就开连锁超市!🏢🏢🏢
- 解决内存瓶颈 👍:开多家分店 (多个 Redis 节点),把商品 (数据) 分散到不同的店里。这样总的存储空间就大大增加了。
- 解决 CPU/网络瓶颈 👍:顾客可以去不同的分店结账,每个店的老板 (CPU) 压力都小了,店门口的路 (网络) 也不会那么拥挤了。请求被分散到多个节点处理,提高了整体的吞吐量。
- 解决可用性问题 👍:每个分店都配个副店长 (主从复制) 👥。万一某个店长病了 (主节点宕机),副店长立刻顶上 (从节点自动切换为主节点),超市还能继续营业。提供了高可用性。
所以,Redis 分片集群的核心思想就是:
- 分片 (Sharding) 🔪:把数据"切"成很多片,分散存储在多个 Redis 实例(主节点)上。
- 复制 (Replication) 👯:给每个存储数据的实例(主节点)配备一个或多个备份实例(从节点),保证高可用。
二、 Redis 分片集群是什么? 💡
Redis Cluster 是 Redis 官方提供的分布式 解决方案。它不是像哨兵(Sentinel)那样只负责高可用切换,而是同时 解决了数据分片 和高可用两个问题。✨
它是一个去中心化 的架构,这意味着没有一个"中央调度员"或者"代理服务器"来指挥所有请求。集群中的每个节点都知道其他节点的存在,也知道哪些数据(通过后面会讲的 Slot)应该由哪个节点负责。客户端可以直接连接到集群中的任意一个节点发起请求,如果这个节点恰好负责处理这个请求的数据,就直接处理;如果不是,它会告诉客户端"喂,你应该去找 XXX 节点 👉",然后客户端再去连接正确的节点。
三、 散列插槽 (Slot) 是什么? (数据怎么分?) 📮
前面说到要把数据"切片"分散到不同的店(主节点)。那具体怎么切?怎么知道哪个数据该去哪个店呢? 这就是散列插槽 (Hash Slot) 的作用。
- 想象一个大邮局有 16384 个信箱 (Slot) 📬:Redis Cluster 预设了 16384 个 Slot (编号 0 到 16383)。这个数字是固定的。
- 每封信 (Key) 都有个目标信箱 ✉️:当你存一个键值对 (比如
set mykey myvalue
) 时,Redis Cluster 会对这个key
(也就是 "mykey") 做一个特殊的计算 (CRC16 算法),然后用计算结果对 16384 取模。HASH_SLOT = CRC16(key) % 16384
。这个结果就是一个 0 到 16383 之间的数字,决定了这个key
属于哪个 Slot。 - 每个邮递员 (Master Node) 负责一部分信箱 🧑✈️:在集群初始化的时候,这 16384 个 Slot 会被平均分配给所有的主节点。比如你有 3 个主节点,那么:
- 节点 A 可能负责 Slot 0 到 5460
- 节点 B 可能负责 Slot 5461 到 10922
- 节点 C 可能负责 Slot 10923 到 16383
- 找对邮递员 👍:当客户端要操作一个
key
时,它会先计算这个key
属于哪个 Slot,然后根据自己缓存的"Slot 分配表",找到负责这个 Slot 的主节点,再把请求发给那个主节点。
为什么是 16384? Redis 作者认为这个数字:
- 足够分散数据到最多 1000 个主节点(实践中很少有这么大规模的集群 💪)。
- 节点间传输 Slot 配置信息时,用 16384 个 Slot(即 16384 bit = 2KB)的位图 (bitmap) 来表示,这个大小比较合适,不会太大导致网络开销过高。👌
如何查看某个 Key 属于哪个 Slot?
可以使用命令:CLUSTER KEYSLOT {key}
,例如 CLUSTER KEYSLOT mykey
。
四、 如何搭建三主六从的 Redis 分片集群? 🐳🔧
这里我们用 Docker Compose 来模拟 9 个 Redis 实例,组成一个 3 主 6 从(每个主节点带 2 个从节点)的集群。
前提条件:
- 你的 Linux 系统安装了 Docker。
- 你的 Linux 系统安装了 Docker Compose。
步骤:
-
创建工作目录: 📂
bashmkdir redis-cluster-demo cd redis-cluster-demo
-
创建
docker-compose.yml
文件: 📝yamlservices: # 定义 9 个 Redis 节点服务 (这里只展示 node-1 和 node-4 作为例子, 其他类似) redis-node-1: # Master 1 Candidate image: redis:latest # 或者更新的版本 container_name: redis-node-1 # 注意:推荐将 nodes.conf 放在持久化数据目录中 command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0 ports: - "7001:6379" # 客户端端口映射 - "17001:16379" # 集群总线端口映射 volumes: - ./node-1/data:/data # 只映射数据目录 networks: - redis-cluster-net redis-node-2: # Master 2 Candidate image: redis:latest container_name: redis-node-2 command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0 ports: - "7002:6379" - "17002:16379" volumes: - ./node-2/data:/data networks: - redis-cluster-net redis-node-3: # Master 3 Candidate image: redis:latest container_name: redis-node-3 command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0 ports: - "7003:6379" - "17003:16379" volumes: - ./node-3/data:/data networks: - redis-cluster-net redis-node-4: # Slave Candidate 1 image: redis:latest container_name: redis-node-4 command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0 ports: - "7004:6379" - "17004:16379" volumes: - ./node-4/data:/data networks: - redis-cluster-net # ... (省略 redis-node-5 到 redis-node-9 的定义,与 node-4 类似,只需修改名称、端口映射和卷映射目录即可) ... # 例如 redis-node-5: ports: ["7005:6379", "17005:16379"], volumes: ["./node-5/data:/data"] # 例如 redis-node-9: ports: ["7009:6379", "17009:16379"], volumes: ["./node-9/data:/data"] redis-node-5: image: redis:latest container_name: redis-node-5 command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0 ports: - "7005:6379" - "17005:16379" volumes: - ./node-5/data:/data networks: - redis-cluster-net redis-node-6: image: redis:latest container_name: redis-node-6 command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0 ports: - "7006:6379" - "17006:16379" volumes: - ./node-6/data:/data networks: - redis-cluster-net redis-node-7: image: redis:latest container_name: redis-node-7 command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0 ports: - "7007:6379" - "17007:16379" volumes: - ./node-7/data:/data networks: - redis-cluster-net redis-node-8: image: redis:latest container_name: redis-node-8 command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0 ports: - "7008:6379" - "17008:16379" volumes: - ./node-8/data:/data networks: - redis-cluster-net redis-node-9: image: redis:latest container_name: redis-node-9 command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0 ports: - "7009:6379" - "17009:16379" volumes: - ./node-9/data:/data networks: - redis-cluster-net networks: redis-cluster-net: driver: bridge # 或者其他网络驱动
说明:
command
: 启动 Redis 并开启集群模式,指定配置文件在/data
目录下。推荐 这种方式,让 Redis 自己管理nodes.conf
。ports
: 映射客户端端口 (6379 -> 700x) 和集群总线端口 (16379 -> 1700x)。总线端口必须能互通! 🤝volumes
: 将数据目录挂载出来,保证持久化。networks
: 所有节点在一个共享网络里。
-
创建必要的目录: 🛠️
bashfor i in {1..9}; do mkdir -p ./node-$i/data; done
-
启动所有 Redis 容器: ▶️
bashdocker compose up -d
等待所有容器启动完成。可以用
docker ps
查看状态。 -
创建集群: ✨ 关键一步 ✨
这一步需要使用
redis-cli
工具来告诉这些独立的 Redis 节点:"嘿,你们现在组成一个大家庭了!"-
找到你的宿主机 IP 地址: 不能用
127.0.0.1
或localhost
。用ip addr
或ifconfig
查找。假设你的 IP 是172.29.0.10
(请替换成你自己的!)。可以使用docker inspect redis-node-1 | grep '"IPAddress":'
命令查看:
-
执行集群创建命令:
bash# 获取任一节点的 redis-cli (用 node-1 举例) docker exec -it redis-node-1 redis-cli --cluster create \ 172.28.120.43:7001 172.28.120.43:7002 172.28.120.43:7003 \ 172.28.120.43:7004 172.28.120.43:7005 172.28.120.43:7006 \ 172.28.120.43:7007 172.28.120.43:7008 172.28.120.43:7009 \ --cluster-replicas 2
解释:
docker exec -it redis-node-1 redis-cli
: 进入redis-node-1
容器执行命令。--cluster create
: 创建集群。- 后面是一长串
IP:PORT
列表 (用宿主机 IP 和映射的客户端端口)。 --cluster-replicas 2
: 核心参数!告诉工具,给每个主节点配 2 个从节点。它会自动算:9 个节点 / (1主 + 2从) = 3 个主节点。所以,它会把前 3 个 (7001, 7002, 7003) 当作主,后 6 个 (7004-7009) 当作从,并自动分配。 magically! ✨
-
确认创建:
redis-cli
会打印出计划的配置方案,问你Can I set the cluster configuration? (type 'yes' to accept):
。输入yes
并回车。
-
-
验证集群状态: ✅
连接到任意一个节点(使用映射的端口),查看集群信息。
bash# 连接到 7001 节点 (在容器内) docker exec -it redis-node-1 redis-cli -p 6379 cluster info # 或者从宿主机连接 (需要安装 redis-cli, -c 表示启用集群模式) # redis-cli -c -h 172.29.0.10 -p 7001 cluster info
你应该看到
cluster_state:ok
。查看节点信息:
bashdocker exec -it redis-node-1 redis-cli -p 6379 cluster nodes # 或者从宿主机连接 # redis-cli -c -h 172.29.0.10 -p 7001 cluster nodes
你会看到 9 个节点的信息,包括角色 (master/slave)、负责的 Slot 等。你会发现 3 个 master 和 6 个 slave,关系明确。
🎉 恭喜!你的 3 主 6 从 Redis 集群现在跑起来了!
五、 分片集群的集群伸缩是什么? ➕➖
集群搭好了,但业务发展太快 📈,3 家分店又不够用了,或者某个区域顾客少了 📉,想关掉一家店。这就是集群伸缩。
-
伸:扩容 (Scale Out) - 增加新的 Redis 节点。
-
开新店 (添加节点) 🆕:先按照上面的方法启动一个新的 Redis 实例(比如
redis-node-10
,映射端口7010
和17010
),让它也运行在集群模式下,但它刚开始是"孤单"的。 -
把它拉进连锁体系 (加入集群) 🤝:使用
redis-cli --cluster add-node
命令,告诉集群里的某个老节点,把这个新家伙拉进来。bash# 新节点 172.29.0.10:7010, 加入到现有集群 (通过 7001 节点操作) docker exec -it redis-node-1 redis-cli --cluster add-node 172.29.0.10:7010 172.29.0.10:7001
默认加进来是作为 主节点 ,但它还没分到活儿 (Slot)。如果要加从节点,用
--cluster-slave
和--cluster-master-id <主节点ID>
。 -
分配工作 (迁移 Slot) 🚚:新来的主节点不能闲着,需要从老主节点那里"匀"一些 Slot (和对应的数据) 过来。这叫 Resharding (重新分片) 。使用
redis-cli --cluster reshard
命令,它会像个向导一样问你:- 要搬多少个 Slot 呀?
- 搬给谁呢 (输入新节点的 Node ID)?
- 从哪里搬 (可以输入
all
让大家分摊,或者指定某些节点)?
bash# 连接到任一节点发起 reshard (例如 7001) docker exec -it redis-node-1 redis-cli --cluster reshard 172.29.0.10:7001 # ... 根据提示一步步操作 ...
这个过程 Redis 会在后台默默进行,服务基本不受影响 (可能有短暂抖动)。
-
-
缩:缩容 (Scale In) - 移除 Redis 节点。
-
交接工作 (迁移 Slot) ➡️:如果要移除的是一个 主节点 ,必须先把它的 Slot 全部迁走 ,交给其他主节点。还是用
redis-cli --cluster reshard
,这次把要移除节点的所有 Slot 作为"源",分配给别人。确保它手里的 Slot 清零! 如果移除的是 从节点,就不用操心 Slot 了,直接下一步。 -
办理离职手续 (移除节点) 👋:使用
redis-cli --cluster del-node
命令,告诉集群,把这个节点"开除"掉。bash# 假设要移除 7003 节点,其 Node ID 是 <node-3-id> (用 cluster nodes 查) # 通过 7001 节点操作 docker exec -it redis-node-1 redis-cli --cluster del-node 172.29.0.10:7001 <node-3-id>
-
关店 (关闭实例) :最后,把被移除节点的 Redis 进程或 Docker 容器停掉。
bashdocker-compose stop redis-node-3 # 如果用 docker-compose 管理 # 或者 docker stop redis-node-3
-
伸缩操作都需要时间让集群状态同步和数据迁移。耐心点哦!⏳
六、 如何使用 RedisTemplate 访问分片集群?💻
在 Java 应用中(特别是 Spring Boot / Spring Data Redis),访问 Redis Cluster 很方便。配置好后,用 RedisTemplate
就行,跟用单实例差不多。
-
添加依赖: (pom.xml / build.gradle)
确保有
spring-boot-starter-data-redis
。它通常默认使用 Lettuce 客户端,Lettuce 对 Cluster 支持很好。xml<!-- Maven 示例 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- 一般不需要额外添加 Lettuce 或 Jedis,除非你想强制用 Jedis -->
-
配置
application.properties
或application.yml
:告诉 Spring Data Redis 你的集群在哪儿。不需要写全所有节点 ,写几个就行,客户端会自动发现其他的。👍
application.properties
示例:properties# Redis Cluster 节点列表 (逗号分隔 host:port) spring.redis.cluster.nodes=172.29.0.10:7001,172.29.0.10:7002,172.29.0.10:7003 # 如果有密码 # spring.redis.password=yourpassword # 连接池配置 (可选, Lettuce) spring.redis.lettuce.pool.max-active=8 spring.redis.lettuce.pool.max-idle=8
application.yml
示例:yamlspring: redis: cluster: nodes: - 172.29.0.10:7001 - 172.29.0.10:7002 - 172.29.0.10:7003 # password: yourpassword # 可选 lettuce: # 可选连接池 pool: max-active: 8 max-idle: 8
-
在代码中使用
RedisTemplate
:注入
RedisTemplate
或StringRedisTemplate
,然后就像操作普通 Redis 一样用。javaimport org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; @Service public class MyRedisService { @Autowired private StringRedisTemplate stringRedisTemplate; // 或者 RedisTemplate<String, Object> public void setValue(String key, String value) { // 直接用!它会自动找到正确的节点去执行 set 命令 stringRedisTemplate.opsForValue().set(key, value); System.out.println("设置 Key: " + key + " 到集群! 😎"); } public String getValue(String key) { // 同样,自动路由到持有这个 key 的节点去 get String value = stringRedisTemplate.opsForValue().get(key); System.out.println("从集群获取 Key: " + key + ", Value: " + value + " 😊"); return value; } // 其他操作 hash, list, set, zset 都类似! }
关键点:
- 无感操作: 大部分单 Key 操作,你感觉不到集群的存在。😎
- 自动寻址: 客户端库内部维护 Slot -> 节点映射,自动把命令发给对的节点。
- 聪明纠错: 如果映射过时 (比如刚发生了故障转移),节点会返回
MOVED
或ASK
错误。客户端库收到后会自动 更新映射,然后重试命令,对你的程序来说几乎是透明的。🔄 - 多 Key 操作要注意! ⚠️:像
MSET
,MGET
, 事务 (MULTI/EXEC) 这类涉及多个 Key 的,默认必须保证所有 Key 都在同一个 Slot 里 。怎么保证?用 Hash Tags ! Key 里用{}
包起来的部分才参与 Slot 计算。例如user:{1000}:name
和user:{1000}:profile
就会落到同一个 Slot,因为都看{1000}
。 如果 Key 不在同个 Slot,执行这些命令会报错哦!💥
七、 分片集群的原理是什么? ⚙️🤝
Redis Cluster 的魔法主要靠这几招:
-
节点间八卦 (Gossip 协议):
深入了解Gossip协议请看:Gossip协议:分布式系统中的"八卦"传播艺术
- 每个节点心里都有本账(集群状态:谁活着,谁管哪些 Slot,主从关系等)。
- 节点之间通过 集群总线端口 (客户端端口+10000那个) 定期互相 PING/PONG,顺便交换自己知道的"八卦消息"(集群状态信息)。🗣️👥
- 这种方式没有中心老大 ,大家互相通气,最终信息会传遍整个集群,达成一致(虽然可能有点延迟,叫最终一致性)。
-
Slot 地盘划分与同步:
- 每个主节点"认领"自己负责的 Slot。
- 认领信息通过 Gossip 协议告诉所有人。
- 客户端连上任何一个节点,都能拿到最新的"地盘划分图"(Slot -> 节点映射)。🗺️
-
心跳检测与"怀疑人生"(PFAIL & FAIL):
- 节点间互相 PING,如果 A 在
cluster-node-timeout
内没收到 B 的 PONG 回复,A 就开始"怀疑" B 是不是挂了,标记为 PFAIL (Possible Fail - 可能挂了)。这只是 A 的个人看法。🤔 - A 会把这个"怀疑"通过 Gossip 告诉其他主节点。
- 如果超过一半 的主节点都觉得"嗯,我也联系不上 B 了",大家就达成共识:B 确实挂了 !状态升级为 FAIL。这个"噩耗"会广播给所有人。💀
- 节点间互相 PING,如果 A 在
-
小弟上位记 (自动故障转移 Failover):
- 一旦某个主节点 被确认 FAIL 了,它的从节点们就开始骚动了:"大哥倒了,机会来了!" 💪
- 谁能上位?得看:确认大哥真挂了,并且自己数据跟大哥差别不大(同步延迟小)。
- 选举流程:
- 想上位的从节点,先给自己"资历"加一分 (
currentEpoch
++), 然后广发英雄帖给所有主节点:"选我!选我!" 🗳️ - 还活着的主节点收到帖子,如果在这个"任期"(
epoch
) 内还没投过票,就给第一个发帖的从节点投一票。 - 哪个从节点最先拿到超过半数主节点的投票,就成功当选新大哥!👑
- 想上位的从节点,先给自己"资历"加一分 (
- 走马上任 :新大哥(原从节点)立马:
- 宣布自己是主节点了。
- 接管原来大哥的所有 Slot 地盘。
- 通过 Gossip 昭告天下:"从今天起,这些 Slot 归我管了!"📢
- 服务恢复 :整个过程是自动的,客户端在短暂的切换后就能找到新大哥继续工作。注意 ⚠️:如果某个主节点和它的所有从节点同时 挂掉,那它负责的 Slot 就真的服务不了了,需要人工介入。另外,如果超过半数 的主节点都挂了,为了防止数据错乱,整个集群会停止服务!🛑
-
客户端导航 (MOVED & ASK):
- MOVED (搬家了,去那边!) 👉:客户端可能拿着旧地图(过时的 Slot 映射)找错了节点。这个节点会说:"兄弟,这个 Slot 不归我管了,已经搬到
ip:port
那家去了,你去那边吧!" 并返回MOVED <slot> <correct_ip>:<correct_port>
。客户端收到后,会更新地图,然后乖乖去新地址重新请求。 - ASK (稍等,问问那边) ➡️:在 Slot 迁移过程 中,比如 Slot X 正从 A 往 B 搬。客户端还是找旧主 A 问 Slot X 里的某个 key:
- 如果 key 还在 A 这,A 就处理了。
- 如果 key 已经 搬到 B 那了,A 会说:"这个 key 可能在 B 那了,你去问问 B 试试?" 并返回
ASK <slot> <destination_ip>:<destination_port>
。 - 客户端收到
ASK
,不会 更新地图(因为搬家还没彻底完成)。它会先去 B 那边敲门说ASKING
(表明我是被 A 指过来的),然后再发真正的命令。B 收到ASKING
就知道怎么回事了,即使 Slot X 还没完全归它管,也会临时处理这条命令。ASK
只管用一次。
- MOVED (搬家了,去那边!) 👉:客户端可能拿着旧地图(过时的 Slot 映射)找错了节点。这个节点会说:"兄弟,这个 Slot 不归我管了,已经搬到
八、 分片集群的优缺点是什么?
优点:
- 能屈能伸 (Scalability) ✅:加机器就能加容量、加性能,理论上可以搞很大规模。就像开连锁店,想开多少开多少。
- 打不死的小强 (High Availability) ✅:主从热备 + 自动切换,挂掉一两个节点服务基本不受影响(只要不是主从一起挂,或挂掉太多主)。
- 跑得快 (Performance) ✅:请求分散到多个节点,大家分担压力,整体响应快。
- 亲儿子待遇 (Official Solution) ✅:Redis 官方出品,稳定性和兼容性有保障,社区活跃。
- 群龙无首也行 (Decentralized) ✅:没有中央控制节点,避免了单点瓶颈和故障。
缺点:
- 多 Key 操作有点瘸 (Multi-key Operations Limitation) ⚠️:像
MSET
、事务等,默认要求 Key 在同一个 Slot,否则报错。需要开发者注意,或者用 Hash Tags 绕一下。跨 Slot 的复杂操作比较麻烦。 - 有点复杂 (Complexity) ⚠️:配置、管理、排错比单机或哨兵模式复杂,需要懂 Slot、Gossip 这些概念。运维成本高点。
- 话痨费网 (Network Overhead) ⚠️:节点间需要不停地 Gossip 来同步状态,会消耗一些网络带宽和 CPU。
- 客户端要配套 (Client Compatibility) ⚠️:必须用支持 Redis Cluster 的客户端库(新版的 Lettuce、Jedis 都支持)。
- 可能偏心 (Data Skew) ⚠️:如果 Key 设计不好(比如 Hash Tag 用得太集中,或有超级热点 Key),可能导致数据和流量集中在少数节点,失去均衡效果。🤷♀️
- 批量活儿效率可能不高 (Batch Efficiency) ⚠️:如果要操作一大堆分布在不同 Slot 的 Key,客户端得跟多个节点打交道,可能不如单实例高效。
- 团结就是力量(但散了就...) (Cluster Integrity Requirement) ⚠️:集群的正常运行和故障转移依赖于"少数服从多数"原则。如果挂掉的主节点太多(超过半数),整个集群就"瘫痪"了,拒绝服务以保护数据。