
🎬 博主简介:

前言:
前面聊完哨兵机制,我们解决了主节点的自动故障转移,实现了主从架构的高可用。但哨兵模式有个本质的天花板:每个节点都要存储全量数据,数据总量始终受限于单台机器的内存上限。当业务数据量突破单节点内存的时候,就需要真正的分布式集群方案了。Redis Cluster(Redis 集群)就是官方给出的分布式解决方案,核心思路是数据分片:把全量数据拆成多份,分散到不同的节点上,每个节点只负责一部分数据,从而实现存储容量的水平扩展。同时每个分片自带主从复制,也保证了高可用。很多开发者用集群只会搭环境、发命令,对底层的分片算法、槽的设计、故障转移逻辑、扩容的代价一知半解,遇到跨槽报错、扩容抖动、节点故障就无从下手。本文从基本概念讲起,完整拆解三种分片算法的演进、哈希槽的设计细节、集群搭建与使用、故障处理与扩容运维,结合源码视角讲清设计思路,帮你把 Redis 集群从「会用」吃透到「懂原理」。
一. 集群的基本概念
1.1 广义与狭义的集群
「集群」这个词有两层含义:
- 广义集群:只要多台机器构成分布式系统,都可以叫集群。前面讲的主从结构、哨兵模式,都属于广义的集群。
- 狭义集群:特指 Redis 官方提供的 Cluster 模式,核心目标是解决存储空间不足的问题,也就是水平扩展存储容量。
哨兵模式虽然提升了可用性,但本质上每个节点仍然存储完整的数据全集,数据量上限始终卡在上限最高的那台机器上。而集群模式把数据拆分到多个分片,每个分片只存一部分,机器加得越多,能存的数据就越多,理论上可以无限扩展。
1.2 架构与能力
Redis Cluster 采用多主多从的架构:
- 整个数据集拆分为多个分片,每个分片有一个主节点和若干从节点;
- 主节点负责对应分片的读写和数据维护,从节点备份数据、分担读流量;
- 写请求可以分散到不同分片的主节点上,写性能也能横向扩展,这是哨兵模式做不到的。
二. 数据分片算法
分片是集群的核心,怎么把 key 均匀分配到不同节点、扩容时怎么迁移代价最小,是分片算法要解决的核心问题。行业内主流有三种思路,Redis 最终选择了哈希槽方案。
2.1 哈希求余
最朴素的分片思路,借鉴哈希表的寻址逻辑:对 key 做哈希运算(比如 MD5)得到整数,再对分片总数 N 取余,结果就是目标分片的编号。
优点:逻辑简单,实现容易,正常情况下数据分布均匀。 致命缺点:扩容成本极高。一旦分片数 N 变化,几乎所有 key 的分片结果都会改变,需要全量迁移数据。比如 3 分片扩成 4 分片,约 75% 的数据都要挪动位置,亿级数据量下基本无法在线上直接操作。
这种方案只适合分片数固定、基本不扩容的场景,生产环境很少直接使用。
2.2 一致性哈希算法
为了解决扩容迁移量大的问题,一致性哈希把哈希空间组织成一个环形,每个分片节点在环上分配一个固定位置。key 计算哈希后,顺时针查找第一个遇到的节点,就是目标存储节点。
扩容时只需要在环上插入新节点,只需要迁移它顺时针相邻节点的一部分数据即可,整体迁移量比哈希求余小很多。 缺点:节点数量少时很容易出现数据倾斜,个别节点承担大部分数据。如果一次扩容多个节点可以缓解,但机器成本也会相应上升。
2.3 哈希槽分区算法
这是 Redis 真正采用的方案,相当于融合了前两种的优势,用「哈希槽」作为中间层,解耦了 key 和节点的映射。
核心逻辑
不直接把 key 映射到节点,而是先映射到哈希槽(slot),再把槽分配给节点。 计算公式:
slot = CRC16(key) % 16384
整个集群固定有 16384 个槽,编号从 0 到 16383,全部分配给所有主节点。比如 3 个分片的话,每个大概负责 5461 个槽。
两个经典面试题
这两个是面试高频考点,很多人都理解得不对。
问题一:Redis 集群最多有 16384 个分片吗? 不是。槽和分片是完全不同的概念,16384 是槽的总数,不是分片的数量。 如果一个分片只对应一个槽,根本没法保证数据均匀 —— 有的槽堆满 key,有的槽是空的。 官方建议集群分片数不要超过 1000 个。一方面分片太多管理复杂度飙升,可用性下降;另一方面 16384 个槽分给 1000 个分片,每个也有十几个槽,足够保证数据分布均匀。
问题二:为什么正好是 16384 个槽? 这个问题作者本人在 GitHub 上专门回复过,核心是心跳带宽与分片粒度的权衡。 节点之间的心跳包需要携带自身持有哪些槽的信息,用位图(bitmap)存储。16384 个 bit 刚好是 2KB,体积非常小。 如果换成 65536 个槽,位图就要 8KB。看起来不多,但心跳是高频周期性通信,每个节点都要给其他节点发送,集群规模大了之后带宽开销会非常可观。 再结合分片数不超 1000 的建议,16384 个槽的粒度已经足够,再密收益也不大。综合下来这是一个非常均衡的取值。
槽分配的灵活性
槽的分配非常灵活,不一定是连续区间。每个节点用位图记录自己持有的槽,每一位对应一个槽,0 表示未持有,1 表示持有。 扩容的时候,可以从每个旧分片各拿出一部分槽,凑给新分片。比如 3 分片扩 4 分片,从每个旧分片各挪 1/4 的槽给新节点,整体数据迁移量只有总量的 1/4,而且扩容后数据仍然均匀。 只有被移动的槽对应的数据需要迁移,不动的槽完全不受影响,迁移成本可控。
三. 集群环境搭建
生产环境集群至少需要 3 个主节点,每个主节点带至少 1 个从节点,总共至少 6 个节点。学习环境可以用 Docker 模拟,利用容器隔离避免端口、配置、数据文件冲突。
3.1 节点核心配置
每个集群节点都要开启集群模式,核心配置项:
# 开启集群模式
cluster-enabled yes
# 集群节点状态文件,自动生成维护,禁止手动修改
cluster-config-file nodes.conf
# 节点超时时间,超过则判定节点故障
cluster-node-timeout 5000
# 节点对外宣告的IP与端口,跨机房部署必须配置
cluster-announce-ip 172.30.0.101
cluster-announce-port 6379
cluster-announce-bus-port 16379
注意每个节点必须有独立的配置和独立的数据目录,不能共用持久化文件,否则会出现权限冲突和数据覆盖。
3.2 创建集群
所有节点启动完成后,用 redis-cli 集群命令创建集群,自动分配槽位和从节点:
redis-cli --cluster create \
172.30.0.101:6379 172.30.0.102:6379 172.30.0.103:6379 \
--cluster-replicas 2
--cluster-replicas 2 表示每个主节点配 2 个从节点。执行后会输出槽位分配计划,确认所有 16384 个槽都被覆盖,输入 yes 即可完成创建。
四. 集群的使用与常见问题
4.1 客户端重定向
直接连接任意一个节点,操作不在这个节点上的 key 时,会返回 MOVED 错误,告知 key 实际所在的节点地址:
127.0.0.1:6379> set k1 123
(error) MOVED 12706 172.30.0.103:6379
redis-cli 加上 -c 参数就可以开启自动重定向,客户端会自动跳转到对应节点执行命令。 生产环境的主流客户端库(C++ 的 redis-plus-plus、Java 的 Jedis 等)都原生支持集群模式,内部自动处理重定向,业务代码无需感知。
4.2 跨槽命令问题
不是所有原生命令都能在集群里正常使用。涉及多个 key 的命令,如果 key 不在同一个槽里,就会报 CROSSSLOT 错误:
127.0.0.1:6379> mget k1 k2
(error) CROSSSLOT Keys in request don't hash to the same slot
解决方案是 hash tag:用 {} 包裹 key 的一部分,哈希计算时只取大括号内的字符串。这样就能让不同的业务 key 强制落到同一个槽里。 比如 user:{1001}:name 和 user:{1001}:age,都用 1001 计算哈希,必然在同一个槽,就可以批量操作了。 代价是会一定程度影响数据分布的均匀性,需要根据业务场景权衡。
4.3 从节点的写操作
尝试在从节点上执行写命令,会自动重定向到对应分片的主节点,和主从模式行为一致。从节点默认只提供读服务。
五.故障处理与高可用
集群自带故障转移能力,不需要额外部署哨兵,每个节点都参与监控和选举。
5.1 故障判定
和哨兵机制类似,也是基于心跳检测。每个节点和其他所有节点保持心跳通信,超过 cluster-node-timeout 时间没有响应,就标记为疑似下线。 当超过半数的主节点都认为某个节点下线,就达成共识,判定为客观下线,开始故障转移流程。
5.2 故障转移
- 从节点故障:基本无影响,读流量自动切到同分片的其他从节点,主节点不受干扰。
- 主节点故障:该分片的所有从节点会发起选举,基于 Raft 一致性算法选出新的主节点,接管该分片所有槽,继续提供服务。
和哨兵不同,集群的选举是分片内的从节点选新主,不是选管理节点。Raft 通过随机休眠机制避免平票,谁先唤醒谁更容易当选 —— 核心是尽快选出一个就行,选谁差别不大。
5.3 集群整体不可用的三种情况
不是任意节点挂了集群都能正常工作,三种场景会导致集群整体不可用:
- 某个分片的主节点和所有从节点全部挂掉,这部分槽无人负责;
- 某个分片只有主节点没有从节点,主节点一挂就直接失效;
- 超过半数的主节点都挂了,集群无法达成共识。
所以生产环境每个主节点至少配一个从节点,且节点尽量部署在不同机房、不同机架,避免同时故障。
六. 集群扩容与缩容
集群扩容是生产环境的高风险运维操作,必须谨慎执行。
6.1 扩容完整步骤
以 3 分片扩 4 分片为例:
- 新节点加入集群:启动新的主节点,通过
CLUSTER MEET命令加入集群。此时新节点不持有任何槽,不处理业务数据。 - 重新分片(reshard):使用
redis-cli --cluster reshard命令,指定要迁移的槽数量、接收节点、源节点。可以选all从所有旧节点平均抽取槽,也可以手动指定源节点。 - 数据迁移:确认迁移计划后,开始逐个迁移槽和对应的数据。迁移过程中,未迁移的 key 正常访问,正在迁移的 key 可能短暂不可用。
- 添加从节点:给新的主节点配置从节点,保证高可用。
6.2 扩容注意事项
- 迁移过程对业务有一定影响,建议在业务低峰期操作;
- 一次不要迁移太多槽,分批执行降低影响;
- 对可用性要求极高的场景,可以搭建新集群全量迁移后切流量,成本更高但业务影响最小。
6.3 缩容
就是扩容的反向操作:把待下线节点的槽全部迁移到其他节点,再将节点踢出集群。生产环境很少做缩容,一般都是只扩不缩。
源码视角:集群的设计智慧
站在 C/C++ 系统编程的角度看,集群的很多设计都非常经典,值得借鉴。
1. 位图的高效应用
每个节点持有的槽用位图表示,16384 位刚好 2KB,在 C 里就是一个 char[2048] 数组。按位操作检查、设置、清除都是 O (1),效率极高。 心跳包里直接携带这个位图,数据量极小,即使高频心跳也不会占用太多带宽。这是非常典型的用位运算换空间的思路,在网络通信场景中非常常见。
2. 中间层解耦思想
哈希槽是非常经典的中间层设计。如果直接 key 映射节点,扩容就要重新计算所有 key 的归属;加入槽这一层之后,key 和槽的映射是固定的,扩容只需要调整槽和节点的映射关系,只移动对应槽的数据就行。 加一层抽象解决问题,是系统设计最常用的手段之一。Redis 用一个非常简单的中间层,就把扩容代价降了一个数量级。
3. 去中心化的取舍
和哨兵模式的中心化监控不同,集群是完全去中心化的。每个节点都监控其他所有节点,没有特殊的管理节点。 好处是没有单点故障,坏处是心跳通信复杂度是 O (n²),节点太多心跳本身就会占满带宽。所以官方才建议分片不超过 1000 个,再大的话运维收益就抵不上开销了。
核心考点总结
- 基本定位:狭义集群解决存储容量水平扩展,同时实现多主高可用;每个分片存储部分数据,支持读写性能横向扩展。
- 分片算法对比
- 哈希求余:逻辑简单但扩容迁移成本极高,生产少用;
- 一致性哈希:环形映射,扩容迁移量小,节点少时易数据倾斜;
- 哈希槽:Redis 采用方案,key→槽→节点两层映射,16384 个固定槽,扩容灵活、迁移可控。
- 哈希槽细节
- 总数 16384,通过 CRC16 (key) 取模计算;
- 用位图存储,心跳传输开销小,是带宽与粒度的权衡;
- 槽数 ≠ 分片数,官方建议分片不超 1000 个。
- 集群使用
- 客户端加
-c支持自动重定向,主流 SDK 都内置集群支持; - 多 key 命令需同槽,否则报 CROSSSLOT,用 hash tag 解决;
- 从节点写操作自动重定向到主节点。
- 客户端加
- 故障处理
- 节点超时判定下线,多数主节点达成共识;
- 主节点故障自动选举新主,基于 Raft 算法;
- 三种集群不可用场景:分片全挂、无从节点主挂、半数以上主挂。
- 集群扩容
- 步骤:新节点加入 → 重新分片迁移槽 → 添加从节点;
- 迁移过程中数据部分可用,建议低峰期操作;
- 属于高风险运维操作,需谨慎执行。
结尾:
🍓 我是草莓熊 Lotso!若这篇技术干货帮你打通了学习中的卡点:
👀 【关注】跟我一起深耕技术领域,从基础到进阶,见证每一次成长
❤️ 【点赞】让优质内容被更多人看见,让知识传递更有力量
⭐ 【收藏】把核心知识点、实战技巧存好,需要时直接查、随时用
💬 【评论】分享你的经验或疑问(比如曾踩过的技术坑?),一起交流避坑
🗳️ 【投票】用你的选择助力社区内容方向,告诉大家哪个技术点最该重点拆解
技术之路难免有困惑,但同行的人会让前进更有方向~愿我们都能在自己专注的领域里,一步步靠近心中的技术目标!
结语:Redis Cluster 是 Redis 从单节点、主从、哨兵一路走来,最终的分布式形态。它用哈希槽的精巧设计,解决了数据分片的扩容难题;用去中心化的故障转移,实现了多主节点的高可用。当然集群也不是银弹:跨槽操作限制、扩容的复杂度、运维的门槛,都比主从哨兵模式高不少。但面对海量数据的场景,它是目前官方最成熟的分布式方案。 理解了哈希槽的本质和集群的运行逻辑,再去做生产环境的运维和排障,就会得心应手很多。
✨把这些内容吃透超牛的!放松下吧✨ ʕ˘ᴥ˘ʔ づきらど
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/2503_91389547/article/details/166140414





