Redis Cluster(Redis 集群模式) 从入门到精通:架构解析、机制详解与运维排查
文章目录
- [Redis Cluster(Redis 集群模式) 从入门到精通:架构解析、机制详解与运维排查](#Redis Cluster(Redis 集群模式) 从入门到精通:架构解析、机制详解与运维排查)
-
-
- [一、Redis Cluster 核心定位与架构](#一、Redis Cluster 核心定位与架构)
- [二、核心工作原理:哈希槽(Hash Slot)分布式数据存储的核心规则](#二、核心工作原理:哈希槽(Hash Slot)分布式数据存储的核心规则)
- 三、关键机制详解
-
- [1. 主从复制与故障转移:集群高可用的保障](#1. 主从复制与故障转移:集群高可用的保障)
- [2.Gossip 协议与集群通信:无中心架构的节点协同规则](#2.Gossip 协议与集群通信:无中心架构的节点协同规则)
- 3.客户端路由:无代理层的高性能请求处理
- [4. 其他:槽位迁移(扩缩容核心)](#4. 其他:槽位迁移(扩缩容核心))
- 5.各个机制的协同逻辑
- 四、使用限制与注意事项
- [五、简单部署示例(redis-cli 方式)](#五、简单部署示例(redis-cli 方式))
- [六、Redis 集群模式(Cluster)、主从复制、哨兵模式三者的联系](#六、Redis 集群模式(Cluster)、主从复制、哨兵模式三者的联系)
-
- 1、三者的核心关联逻辑(从底层到上层)
-
- [(1) 主从复制是三者的 "共同底层基石"](#(1) 主从复制是三者的 “共同底层基石”)
- [(2) 哨兵模式是 "纯主从架构的高可用补丁"](#(2) 哨兵模式是 “纯主从架构的高可用补丁”)
- [(3) 集群模式是 "分片 + 高可用" 的一体化方案(替代哨兵 + 主从)](#(3) 集群模式是 “分片 + 高可用” 的一体化方案(替代哨兵 + 主从))
- 2、三者的核心联系与区别(表格对比)
- 3、关键关联细节(新手易混淆)
-
- [(1) 集群模式为何不需要哨兵?](#(1) 集群模式为何不需要哨兵?)
- [(2) 三者的演进路径(符合实际生产场景)](#(2) 三者的演进路径(符合实际生产场景))
- [(3) 能否混合使用?](#(3) 能否混合使用?)
- [七、Redis Cluster 常见问题排查(核心故障 + 原因 + 解决方案)](#七、Redis Cluster 常见问题排查(核心故障 + 原因 + 解决方案))
-
- 通用排查前置准备(所有问题先做这几步)
- [1、核心问题 1:集群无法启动 / 节点加入失败(最常见)](#1、核心问题 1:集群无法启动 / 节点加入失败(最常见))
-
- 现象
- 核心原因(按排查优先级)
- [排查 & 解决步骤](#排查 & 解决步骤)
- [2、核心问题 2:槽位分配异常 / 数据法写入](#2、核心问题 2:槽位分配异常 / 数据法写入)
- [3、核心问题 3:主节点宕机,故障转移失败(高可用核心故障)](#3、核心问题 3:主节点宕机,故障转移失败(高可用核心故障))
-
- 现象
- 核心原因(按排查优先级)
- [排查 & 解决步骤](#排查 & 解决步骤)
- [4、核心问题 4:客户端路由异常(MOVED/ASK 重定向频繁)](#4、核心问题 4:客户端路由异常(MOVED/ASK 重定向频繁))
- [5、核心问题 5:集群节点失联 / 网络分区(脑裂)](#5、核心问题 5:集群节点失联 / 网络分区(脑裂))
- 6、其他高频小问题
-
- [问题 1:集群中某个主节点无法删除 / 替换](#问题 1:集群中某个主节点无法删除 / 替换)
- [问题 2:集群内存使用率不均(某节点内存满,其他节点空闲)](#问题 2:集群内存使用率不均(某节点内存满,其他节点空闲))
- [问题 3:集群重启后槽位丢失](#问题 3:集群重启后槽位丢失)
- [7、Redis Cluster 生产环境避坑指南](#7、Redis Cluster 生产环境避坑指南)
- [附:Redis Cluster 核心排查命令速查](#附:Redis Cluster 核心排查命令速查)
- 总结
- 总结
-
一、Redis Cluster 核心定位与架构
Redis Cluster(Redis 集群模式),这是 Redis 官方主推的分布式解决方案,核心是通过哈希槽分片实现水平扩展,结合主从复制和自动故障转移保障高可用,非常适合海量数据、高并发的生产场景。Redis Cluster 是 Redis 3.0 及以上版本推出的分布式集群方案,解决了主从复制、哨兵模式无法突破的单节点内存 / 性能瓶颈问题,核心目标是:
- 水平扩展:将数据分片存储在多个主节点上,支持动态扩缩容。
- 高可用:每个主节点搭配从节点,主节点故障时自动切换,无单点故障。
- 去中心化:集群内所有节点地位平等,无中心节点,节点间通过 gossip 协议同步状态。
基础架构要求
- 最小部署单元:3 个主节点 + 3 个从节点(每个主节点至少 1 个从节点,保障故障转移)。
- 节点通信:所有节点监听两个端口(如 6379 用于客户端通信,16379 用于节点间 gossip 通信)。
二、核心工作原理:哈希槽(Hash Slot)分布式数据存储的核心规则
Redis Cluster 不直接对键(Key)进行哈希分片,而是引入了哈希槽这个中间层,这是理解 Cluster 模式的核心:
-
槽位总数:固定 16384 个哈希槽(0~16383),这个数值兼顾了性能(节点间通信开销)和扩展性。
-
槽位分配:每个主节点会被分配一部分槽位(可手动 / 自动分配),集群的所有槽位必须全部分配给主节点,集群才处于 "可用" 状态。
-
键定位槽位:
对键执行 CRC16(key) % 16384计算,得到该键所属的槽位,再根据槽位找到对应的主节点。
示例:键 user:100的 CRC16 结果是 5888,5888%16384=5888,若槽 5888 分配给主节点 A,则该键存储在 A 上。
-
节点与槽位绑定:集群中只有主节点负责持有槽位,每个主节点会被分配一段连续的槽位区间(无重叠、全覆盖),所有主节点的槽位共同组成完整的 16384 个槽。例如 3 主集群,槽位会均匀分配为 0-5460、5461-10922、10923-16383(官方默认均匀分配,也可手动调整)。
-
客户端重定向:
客户端连接任意节点发起请求,若该节点不持有目标槽位,会返回
MOVED指令(如MOVED 5888 192.168.1.10:6379),告知客户端正确的节点地址。客户端会缓存槽位与节点的映射关系,后续请求直接命中目标节点,减少重定向。
-
优势 :节点增删、扩容缩容时,仅需迁移对应槽位及槽内的数据,无需对全量数据重新计算哈希,迁移粒度可控、效率高,且不影响集群整体对外提供服务。
为了方便理解与记忆什么是哈希槽,简单举个例子:
首先,先给出一个直白的定义:哈希槽是 Redis 集群用来分配和管理数据的 "地址编号",Redis 集群预定义了 16384 个哈希槽(编号从 0 到 16383),集群中的每个节点会负责一部分槽位,所有的键值对都会根据键名计算出对应的哈希槽,然后被映射到负责该槽的节点上。
比喻成一个快递分拣中心
我们可以把 Redis 集群比作一个大型的快递分拣配送中心:
1.16384 个哈希槽 = 16384 个 "快递分拣口"
整个配送中心有且仅有 16384 个固定编号的分拣口(0 号到 16383 号),每个分拣口对应唯一的配送区域,这是预先设定好的,不会新增或减少。
2.Redis 集群节点 = 不同的配送站点
比如集群中有 3 个节点,就像配送中心有 A、B、C 三个配送站点。管理员会把 16384 个分拣口分配给这些站点:
- A 站点负责 0-5460 号分拣口
- B 站点负责 5461-10922 号分拣口
- C 站点负责 10923-16383 号分拣口
3.Redis 的键值对 = 包裹
你存入 Redis 的每一个键(比如user:1001、product:500)就像一个包裹,包裹上只有 "收件人姓名(键名)",没有直接写 "该去哪个站点"。
4.哈希计算 = 分拣规则
分拣员(Redis 集群)会按照固定规则计算包裹该去哪个分拣口:对键名做 CRC16 哈希运算,再对 16384 取余,得到一个 0-16383 之间的数字,这个数字就是该包裹对应的 "分拣口号(哈希槽)"。
比如:
- 键
user:1001计算后得到哈希槽编号 2000 → 归 A 站点负责 - 键
product:500计算后得到哈希槽编号 8000 → 归 B 站点负责
5.数据存储 / 读取 = 包裹配送 / 取件
- 存数据时:集群先算键的哈希槽,再把数据发到对应槽的节点上;
- 读数据时:集群先算键的哈希槽,再去对应节点取数据;
- 节点扩容 / 缩容时:只需要把部分 "分拣口(哈希槽)" 从一个节点迁移到另一个节点,不用移动所有数据,就像把某个分拣口的配送任务转给另一个站点。
补:Redis Cluster 整体架构与哈希槽分片(静态架构)
集群通信层
集群节点层
客户端层
从节点组(只读/备份)
主节点组(持有哈希槽)
1.拉取路由表 2.直连主节点
1.拉取路由表 2.直连主节点
1.拉取路由表 2.直连主节点
异步复制数据
异步复制数据
异步复制数据
Gossip协议
Gossip协议
Gossip协议
Gossip协议
Gossip协议
Gossip协议
客户端 Client
-
本地路由表
-
CRC16计算槽位
-
MOVED/ASK重定向
主节点A
槽位:0-5460
处理读写请求
主节点B
槽位:5461-10922
处理读写请求
主节点C
槽位:10923-16383
处理读写请求
从节点A1
同步主节点A
只读
从节点B1
同步主节点B
只读
从节点C1
同步主节点C
只读
Gossip协议
-
集群总线(端口+10000)
-
PING/PONG状态同步
-
故障检测
三、关键机制详解
Redis Cluster 基于一主多从的主从复制架构,结合自动故障转移机制,解决了单节点宕机导致的服务不可用与数据丢失问题,是集群稳定运行的关键。
1. 主从复制与故障转移:集群高可用的保障
主从角色与职责:
- 主节点(Master):唯一可写节点,持有分配的哈希槽,处理客户端的读写请求,是数据存储的核心;
- 从节点(Replica):每个主节点可配置 1 个或多个从节点,从主节点异步复制全量 + 增量数据 ,默认只读,不持有槽位,仅作为主节点的 "备份节点"。
主从绑定:每个主节点可配置 1 个或多个从节点,从节点会全量复制主节点的所有槽位数据。
故障检测 :节点间通过 PING/PONG 消息(gossip 协议)检测健康状态,若一个节点超过 node-timeout 未响应,会被标记为 "疑似下线(PFAIL)";当集群中多数主节点都标记该节点为 PFAIL 时,会升级为 "确认为下线(FAIL)"。
自动故障转移:
- 主节点下线后,其从节点会发起 "竞选",集群内其他主节点投票,获得半数以上选票的从节点晋升为新主节点(通常是数据复制最完整、存活时间最长的)。
- 新主节点接管原主节点的所有槽位,集群更新槽位映射关系,客户端后续请求自动路由到新主节点,原宕机主节点恢复后,会作为新主节点的从节点重新加入集群。
- 补:实现故障转移的前提:集群中超过半数的主节点处于在线状态,且宕机主节点存在可用的从节点(数据复制正常、未宕机),否则集群会进入不可写状态,保障数据一致性。
补:Redis Cluster 核心运行流程(正常读写 + 故障转移)
有效
无效
否
是
否
是
正常运行
服务恢复
客户端发起请求
如 SET key1 val1
本地计算槽位
CRC16(key1) % 16384
查询本地路由表
匹配槽位对应主节点
路由表是否有效?
直连目标主节点
发起读写请求
收到MOVED/ASK重定向
更新本地路由表
主节点处理请求
写请求异步同步到从节点
节点间Gossip协议
持续同步集群状态
主节点宕机
无法响应PING
超时未回复
标记为疑似宕机
半数主节点确认宕机?
继续检测
确认主节点宕机
宕机主节点有可用从节点?
集群进入不可写状态
从节点内部选举
选出最优节点
从节点晋升为主节点
接管原哈希槽
Gossip同步新状态
所有节点更新路由表
客户端重定向后
直连新主节点
2.Gossip 协议与集群通信:无中心架构的节点协同规则
Redis Cluster 是无中心架构 ,没有专门的主节点管理集群,所有节点地位平等,节点间通过Gossip 协议 和集群总线实现状态同步、故障检测与路由信息维护,保障集群整体状态的一致性。
(1) 集群总线:节点间的专用通信通道,默认使用 "Redis 服务端口 + 10000"(如 Redis 服务端口 6379,集群总线端口为 16379),独立于客户端请求的通信端口,避免业务请求与集群通信相互干扰。
(2) Gossip 协议核心作用 :集群中所有节点通过 Gossip 协议持续、异步地交换集群状态信息,交换的信息包括:节点 ID、节点状态(在线 / 宕机)、节点角色(主 / 从)、节点持有的哈希槽、主从映射关系等。
(3) 核心通信行为:PING-PONG
- 每个节点会随机选择集群中的部分节点,定期发送PING 消息(包含自身状态 + 部分集群状态);
- 被 PING 的节点收到后,回复PONG 消息(包含自身状态 + 最新的集群状态);
- 节点通过持续的 PING-PONG,逐步同步出全量的集群路由表,每个节点都持有整个集群的节点与槽位映射信息。
(4) 故障检测逻辑 :当一个节点向另一个节点发送 PING 消息后,超过集群配置的超时阈值(cluster-node-timeout) 未收到 PONG 回复,会将该节点标记为 "疑似宕机";当集群中超过半数的主节点都将该节点标记为疑似宕机时,才会正式确认其宕机,并触发后续的故障转移。
3.客户端路由:无代理层的高性能请求处理
Redis Cluster 采用客户端直连节点的模式,无中间代理层(如 Proxy),客户端通过 "本地路由表 + 重定向" 实现请求的正确路由,最大限度降低性能损耗,保障集群的读写性能。
(1) 客户端路由核心流程
- 初始化:客户端首次连接集群中任意一个节点 ,从该节点获取全量的集群槽位 - 节点映射表,并缓存到本地(本地路由表);
- 本地路由:客户端发起请求时,本地计算键的哈希槽位,通过本地路由表找到对应主节点,直接向该节点发送请求;
- 重定向更新:若本地路由表过期(如节点增删、故障转移导致槽位映射变化),目标节点会返回MOVED/ASK 重定向指令,包含正确的目标节点地址;客户端根据指令向正确节点发起请求,并更新本地路由表,后续请求直接使用新的路由信息。
(2) 两种重定向指令区别
- MOVED:永久重定向,表示该槽位已永久迁移到新节点,客户端需更新本地路由表,后续该槽位的所有请求均指向新节点;
- ASK:临时重定向,表示该槽位正在迁移中,客户端仅需临时向目标节点发起当前请求,无需更新本地路由表,适用于集群扩缩容的槽位迁移过程。
(3) 多键操作限制 :由于每个键的槽位由自身哈希决定,多键操作(如 mget、mset、sinter)要求所有键必须映射到同一个哈希槽 ,否则集群会直接报错。若需强制多键同槽,可使用哈希标签 {hash-tag} ,Redis 计算哈希时,仅会对{}内的内容计算 CRC16,例如{user:100}name、{user:100}age,会因{}内的user:100相同,映射到同一个槽位。
4. 其他:槽位迁移(扩缩容核心)
Redis Cluster 支持在线动态扩缩容,核心是槽位的迁移(数据随槽位迁移):
扩容:新增主节点 → 从现有主节点迁移部分槽位(及对应数据)到新节点 → 集群同步槽位映射。
缩容:将待下线主节点的所有槽位迁移到其他主节点 → 槽位迁移完成后,下线该节点。
迁移过程:集群会先将槽位标记为 "迁移中",此时对该槽位的读写请求会正常处理,迁移完成后更新映射,全程不中断服务。
5.各个机制的协同逻辑
客户端通过哈希槽算法 定位槽位→通过客户端路由 直连对应主节点→主节点处理请求并同步数据到从节点→节点间通过Gossip 协议 维护集群状态→主节点宕机时,通过主从故障转移实现槽位接管与服务恢复,四大机制相互配合,构成 Redis Cluster 完整的分布式能力体系。
从节点组(只读/数据备份)
主节点组(持有哈希槽)
客户端 Client
(发起读写请求/维护本地路由表) 1. 首次连接集群任意节点,拉取「槽位-节点」全量映射,生成本地路由表 集群所有节点(主+从)
节点间通过「集群总线(端口+10000)」基于Gossip协议持续PING-PONG 主节点A
槽位:0-5460 主节点B
槽位:5461-10922 主节点C
槽位:10923-16383 (各主节点分配连续哈希槽,全覆盖16384个)
从节点A1
(只读) 从节点B1
(只读) 从节点C1
(只读) (一主一从/多从,异步复制主节点全量+增量数据)
四、使用限制与注意事项
- 多键操作限制 :跨槽的多键命令(如
MGET key1 key2,若 key1 和 key2 不在同一槽位)、事务、Lua 脚本会报错,需通过哈希标签规避。 - 不支持数据库切换 :Cluster 模式下只能使用 db0,
SELECT命令无效。 - 持久化建议:所有节点建议开启 RDB(必选)+ AOF(可选),防止故障转移后数据丢失。
- 客户端要求:需使用支持 Cluster 协议的客户端(如 Java 的 JedisCluster、Lettuce,Python 的 redis-py-cluster),普通单机客户端无法正常工作。
五、简单部署示例(redis-cli 方式)
以下是 3 主 3 从 Cluster 集群的快速部署步骤(以 Linux 为例):
bash
# 1. 创建6个节点的配置文件(端口 7000~7005,7000/7001/7002 为主,7003/7004/7005 为从)
for port in {7000..7005}; do
mkdir -p /redis/cluster/$port
cat > /redis/cluster/$port/redis.conf << EOF
port $port
cluster-enabled yes # 开启集群模式
cluster-config-file nodes-$port.conf # 集群配置文件(自动生成)
cluster-node-timeout 15000 # 节点超时时间(ms)
daemonize yes
pidfile /var/run/redis-$port.pid
dir /redis/cluster/$port
appendonly yes
EOF
done
# 2. 启动6个节点
for port in {7000..7005}; do
redis-server /redis/cluster/$port/redis.conf
done
# 3. 创建集群(redis 5.0+ 用 --cluster,5.0 前用 create-cluster 脚本)
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \
127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
--cluster-replicas 1 # 每个主节点对应1个从节点
执行后,redis-cli 会自动分配槽位、绑定主从关系,输入 yes 确认即可完成集群创建。
六、Redis 集群模式(Cluster)、主从复制、哨兵模式三者的联系
主从复制是基础底层机制,哨兵模式是主从架构的高可用增强方案,集群模式是融合主从复制 + 分片的分布式高可用方案------ 三者并非互斥,而是层层递进、底层复用的关系。
1、三者的核心关联逻辑(从底层到上层)
用一张图先理清整体关系:
替代方案
主从复制
(数据同步底层机制)
纯主从架构
(数据备份+读写分离)
哨兵模式
(主从架构+自动故障转移)
Redis Cluster
(无需哨兵,自带高可用)
(1) 主从复制是三者的 "共同底层基石"
无论是哨兵模式,还是集群模式,都完全依赖主从复制实现数据同步:
- 对哨兵模式:主节点写数据,从节点通过主从复制同步数据,这是哨兵能 "故障转移" 的前提(从节点有完整数据才能晋升为主节点);
- 对集群模式:Cluster 中每个主节点都配有从节点,主从之间同样通过主从复制同步数据,这是 Cluster 自动故障转移的核心基础(和哨兵模式的底层逻辑一致)。
简单说:没有主从复制,哨兵模式和集群模式的高可用都无从谈起------ 两者都是在主从复制的基础上,解决 "故障自动恢复" 和 "数据分片" 问题。
(2) 哨兵模式是 "纯主从架构的高可用补丁"
纯主从架构的痛点是 "主节点宕机需人工切换",哨兵模式的核心价值就是给纯主从架构加了一层 "自动故障转移" 能力:
- 哨兵不改变主从复制的任何逻辑,只是在外部增加了 "监控 + 决策 + 执行" 的哨兵进程;
- 哨兵模式的核心场景是:数据量小(全量数据可放在单节点)、只需解决高可用,无需分片的场景。
(3) 集群模式是 "分片 + 高可用" 的一体化方案(替代哨兵 + 主从)
Redis Cluster(集群模式)是官方为解决 "海量数据 + 高并发 + 高可用" 设计的分布式方案,它内置了主从复制 + 类哨兵的故障转移能力,无需再单独部署哨兵:
- 分片层面:用 16384 个哈希槽将数据拆分到多个主节点,解决单节点容量 / 性能瓶颈;
- 高可用层面:每个主节点配从节点(复用主从复制),同时 Cluster 内置了 "故障检测 + 自动故障转移" 逻辑(替代哨兵的核心功能);
- 架构层面:Cluster 无需外部哨兵进程,故障转移逻辑由集群节点自身通过 Gossip 协议完成,是更一体化的分布式方案。
2、三者的核心联系与区别(表格对比)
| 维度 | 主从复制 | 哨兵模式 | 集群模式(Cluster) |
|---|---|---|---|
| 底层依赖 | 无(自身就是底层机制) | 完全依赖主从复制 | 完全依赖主从复制 |
| 核心解决的问题 | 数据备份、读写分离 | 纯主从架构的 "主节点宕机自动切换" | 数据分片(水平扩展)+ 分布式高可用 |
| 故障转移能力 | 无(需人工切换) | 有(外部哨兵进程实现) | 有(集群节点内置,替代哨兵) |
| 数据存储方式 | 所有节点存储全量数据 | 所有节点存储全量数据 | 哈希槽分片,每个主节点存部分数据 |
| 写性能扩展 | 无(仅单主节点) | 无(仅单主节点) | 有(多主节点并行写) |
| 高可用实现逻辑 | - | 哨兵集群投票判定故障,选举领头哨兵执行转移 | 节点间 Gossip 协议判定故障,从节点内部选举晋升 |
| 适用场景 | 测试 / 小规模场景,仅需数据备份 | 中小规模场景(GB 级数据),需高可用但无需分片 | 大规模场景(TB 级数据),需分片 + 高可用 + 高并发 |
| 三者关系 | 后两者的底层基础 | 主从架构的高可用增强版 | 融合主从 + 分片的分布式方案,可替代哨兵 + 主从 |
3、关键关联细节(新手易混淆)
(1) 集群模式为何不需要哨兵?
Cluster 内置了哨兵的核心能力,只是实现方式不同:
- 故障检测:哨兵靠 "哨兵集群投票" 判定主节点下线,Cluster 靠节点间 Gossip 协议(PING-PONG)+ 半数主节点确认判定下线;
- 故障转移:哨兵靠 "领头哨兵" 执行转移,Cluster 靠宕机主节点的从节点内部选举晋升;
- 本质:Cluster 把 "哨兵的高可用逻辑" 内置到集群节点中,无需额外部署哨兵进程。
(2) 三者的演进路径(符合实际生产场景)
plaintext
纯主从架构(手动切换) → 哨兵模式(自动切换,单主) → 集群模式(分片+自动切换,多主)
- 初期小流量:用纯主从,人工维护,成本低;
- 中期中流量:加哨兵,实现自动故障转移,保障可用性;
- 后期大流量:升级为集群模式,解决分片和写扩展问题。
(3) 能否混合使用?
- 不推荐!Cluster 本身内置高可用,再部署哨兵会导致逻辑冲突(比如 Cluster 和哨兵同时尝试故障转移);
- 唯一例外:极特殊场景下,对 Cluster 集群做 "外部监控"(仅监控,不执行故障转移),但无实际意义。
七、Redis Cluster 常见问题排查(核心故障 + 原因 + 解决方案)
Redis Cluster(集群模式)的故障主要集中在集群无法启动 / 节点加入失败 、槽位分配异常 / 数据无法写入 、故障转移失败 、客户端路由异常(MOVED/ASK) 、集群节点失联 / 网络分区五类,是 Redis 分布式运维的高频痛点。
通用排查前置准备(所有问题先做这几步)
排查 Redis Cluster 的核心是先验集群状态、再查日志、最后核配置 / 网络,以下命令是基础:
1.查看集群整体状态(核心)
bash
# 连接任意节点,查看集群状态(cluster_state:ok 为正常)
redis-cli -c -h 节点IP -p 端口 CLUSTER INFO
# 查看所有节点信息(ID、角色、槽位、从节点、连接状态)
redis-cli -c -h 节点IP -p 端口 CLUSTER NODES
2.查看节点日志(最关键)
执行 redis-cli CONFIG GET logfile 获取日志路径,日志会明确打印:
- 槽位分配失败原因(如节点未握手);
- 故障转移失败原因(如从节点不可用);
- 网络分区 / 节点失联的具体报错。
3.验证集群网络连通性
- Redis Cluster 需要两个端口:业务端口(如 6379)+ 集群总线端口(业务端口 + 10000,如 16379);
- 节点间必须互通这两个端口:
telnet 目标节点IP 6379+telnet 目标节点IP 16379; - 云服务器需检查安全组,物理机需检查防火墙(
firewall-cmd --list-ports)。
4.核对核心配置
- 所有节点必须开启
cluster-enabled yes; - 所有节点的
cluster-config-file(集群配置文件)路径需可写; - 所有节点的
cluster-node-timeout(节点超时时间)配置一致(默认 15000ms)。
1、核心问题 1:集群无法启动 / 节点加入失败(最常见)
现象
执行 redis-cli --cluster create 创建集群时提示 ERR Slot not covered/Node XXX is not empty;
执行 CLUSTER MEET 加入节点时提示 ERR Error MEETing node XXX;
CLUSTER INFO 显示 cluster_state:fail。
核心原因(按排查优先级)
- 节点间集群总线端口(+10000)未开放,导致节点无法握手;
- 部分节点未开启
cluster-enabled yes,或配置未生效; - 待加入节点已有数据(非空),集群要求加入的节点必须是空节点;
- 节点
cluster-node-timeout配置不一致,导致心跳检测失败; - 节点 IP 配置错误(如使用内网 IP 但配置了公网 IP,或反之)。
排查 & 解决步骤
1.优先检查集群总线端口(80% 故障原因)
集群总线端口是节点间 Gossip 协议通信的核心,未开放则节点无法握手;
解决方案:
bash
# 临时开放端口(生产环境需持久化)
firewall-cmd --add-port=6379/tcp --permanent
firewall-cmd --add-port=16379/tcp --permanent
firewall-cmd --reload
云服务器在安全组中放行「6379-16380」端口段。
2.确保待加入节点为空
若节点已有数据,清空后重启:
bash
redis-cli FLUSHALL # 清空数据
redis-cli CONFIG SET cluster-enabled yes # 开启集群模式
redis-cli SHUTDOWN # 重启节点
redis-server redis.conf # 重新启动
3.统一所有节点的集群配置
所有节点的 redis.conf 必须包含:
conf
cluster-enabled yes
cluster-config-file nodes-6379.conf # 自动生成,需可写
cluster-node-timeout 15000 # 所有节点保持一致
protected-mode no # 关闭保护模式(或配置bind)
bind 0.0.0.0 # 允许所有IP访问(生产环境指定节点IP)
修改配置后必须重启节点,否则 cluster-enabled yes 不生效。
4.修正节点 IP 配置(避免内外网 IP 混淆)
若节点部署在不同网段,需确保 CLUSTER MEET 使用的 IP 是节点能互通的 IP;
执行 CLUSTER NODES 查看节点的「advertised IP」,若与实际 IP 不符,在 redis.conf 配置:
conf
cluster-announce-ip 节点实际IP # 声明节点对外的IP
cluster-announce-port 6379 # 业务端口
cluster-announce-bus-port 16379 # 集群总线端口
2、核心问题 2:槽位分配异常 / 数据法写入
现象
客户端写入数据时提示 MOVED 12345 XXX:6379,但目标节点未持有该槽位;
CLUSTER NODES 显示部分槽位未分配(0-5460 未出现在任何主节点);
CLUSTER INFO 显示 cluster_slots_assigned 小于 16384(正常应为 16384)。
核心原因
- 集群创建时未完成全量槽位分配(如
redis-cli --cluster create未指定--cluster-replicas); - 手动迁移槽位时中断,导致槽位处于「迁移中」状态;
- 主节点宕机后,故障转移未完成,槽位未被从节点接管;
- 客户端未使用「集群模式」连接(如普通
redis-cli而非redis-cli -c)。
排查 & 解决步骤
1.检查槽位分配完整性
执行 redis-cli -c CLUSTER NODES,统计所有主节点的槽位范围,需覆盖 0-16383;
若槽位缺失,重新分配:
bash
# 进入集群管理模式,重新分配槽位(替换为实际节点IP:端口)
redis-cli --cluster reshard 主节点IP:端口
# 按提示输入:需要分配的槽位数(如缺失的5460)→ 目标主节点ID → 源节点ID(all)→ yes确认
2.修复「迁移中」的槽位
若槽位处于 migrating / importing 状态(日志中打印 Slot XXX is migrating ),执行:
bash
# 连接目标节点,取消槽位迁移
redis-cli -c CLUSTER SETSLOT 槽位号 STABLE
3.确保客户端使用集群模式连接
普通连接(非 -c)无法自动处理 MOVED 重定向,导致写入失败;
客户端配置需指定「集群模式」:
- Java(Jedis):
JedisCluster而非Jedis; - Python(redis-py):
RedisCluster而非Redis。
3、核心问题 3:主节点宕机,故障转移失败(高可用核心故障)
现象
主节点进程挂掉 / 网络中断,但从节点未晋升为主节点;
日志中打印 FAILOVER auth denied/NO GOOD SLAVE AVAILABLE;
CLUSTER NODES 显示主节点状态为 fail,但槽位仍未迁移。
核心原因(按排查优先级)
- 主节点的从节点数量为 0,或从节点状态为
fail(不可用); - 从节点
replica-priority(优先级)被设为 0(永不晋升); - 从节点与主节点同步延迟过高,超过
cluster-node-timeout; - 集群中半数以上主节点失联(网络分区),无法投票确认故障;
- 从节点的
cluster-enabled yes未开启(集群模式下从节点也需开启集群)。
排查 & 解决步骤
1.检查从节点可用性
- 执行
CLUSTER NODES,确认宕机主节点有状态为online的从节点; - 若从节点状态为
fail,重启从节点并检查主从复制(参考「主从复制排查」);
2.检查从节点优先级
从节点优先级默认 100,0 表示永不晋升:
bash
redis-cli -c CONFIG GET replica-priority
# 若为0,修改为100并持久化
redis-cli -c CONFIG SET replica-priority 100
redis-cli -c CONFIG REWRITE
3.检查从节点同步延迟
从节点执行 INFO replication ,查看 master_lag (同步延迟):
- 若延迟 >
cluster-node-timeout(15000ms),从节点会被判定为不可用; - 解决方案:扩大主节点复制积压缓冲区(
repl-backlog-size 1GB),优化主从网络(同机房部署);
4.解决网络分区问题
若集群被拆分为两个分区,半数以上主节点所在的分区才能触发故障转移;
排查:CLUSTER NODES 查看节点间的「连接状态」(connected/disconnected);
解决方案:修复网络中断,重启失联节点,等待 Gossip 协议同步状态(约 30 秒)。
4、核心问题 4:客户端路由异常(MOVED/ASK 重定向频繁)
现象
客户端写入 / 读取数据时频繁收到 MOVED 12345 XXX:6379 或 ASK 12345 XXX:6379;
业务报错 RedisClusterException: MOVED,性能大幅下降。
核心原因
MOVED重定向:客户端本地路由表过期,目标槽位已迁移到其他节点;ASK重定向:槽位正在迁移中,临时重定向到目标节点;- 客户端未开启「自动重定向」(如
redis-cli未加-c参数); - 集群频繁进行槽位迁移(如手动迁移未完成,或故障转移反复触发)。
排查 & 解决步骤
1.确保客户端开启自动重定向
命令行:redis-cli -c(-c 表示集群模式,自动处理 MOVED/ASK);
业务客户端:
- Jedis:
JedisCluster默认开启自动重定向; - Spring Data Redis:配置
spring.redis.cluster.max-redirects=3(最大重定向次数);
2.更新客户端本地路由表
客户端路由表默认缓存,过期后会自动拉取,也可手动触发:
bash
# 客户端执行(强制刷新路由表)
CLUSTER SLOTS
3.排查槽位频繁迁移的原因
若 ASK 重定向频繁,说明槽位迁移未完成:
bash
# 查看槽位迁移状态(替换为异常槽位号)
redis-cli -c CLUSTER GETKEYSINSLOT 槽位号 10 # 查看槽位中的key
redis-cli -c CLUSTER SETSLOT 槽位号 NODE 目标主节点ID # 强制完成迁移
若 MOVED 重定向频繁,说明故障转移反复触发(主节点频繁宕机),需排查主节点宕机原因(内存不足、CPU 满、网络抖动)。
5、核心问题 5:集群节点失联 / 网络分区(脑裂)
现象
CLUSTER NODES 显示部分节点状态为 disconnected;
集群被拆分为两个独立分区,各自认为自己是「有效集群」;
数据写入出现「丢失」(写入到小分区,故障恢复后被覆盖)。
核心原因
- 节点间网络中断(集群总线端口 / 业务端口被防火墙拦截);
cluster-node-timeout配置过小,轻微网络抖动就判定节点下线;- 节点内存不足被 OOM 杀死,重启后与集群失联;
- 集群节点数为偶数,导致脑裂时无法判定「半数主节点」。
排查 & 解决步骤
1.修复网络连通性
检查节点间的 6379 和 16379 端口是否互通,关闭防火墙 / 安全组拦截规则;
执行 CLUSTER MEET 失联节点IP 失联节点端口,手动让集群重新发现节点;
2.调整集群超时时间
生产环境建议将 cluster-node-timeout 调至 30000ms(30 秒),避免轻微抖动导致节点下线:
bash
redis-cli -c CONFIG SET cluster-node-timeout 30000
redis-cli -c CONFIG REWRITE
3.避免集群脑裂
集群主节点数必须为奇数(如 3、5),脑裂时半数以上主节点所在的分区才有效;
配置 cluster-require-full-coverage no(允许部分槽位不可用,避免集群整体不可用);
4.恢复失联节点数据
失联节点重启后,若数据与集群不一致,执行:
bash
redis-cli FLUSHALL # 清空本地数据
redis-cli CLUSTER RESET # 重置节点状态
redis-cli CLUSTER MEET 集群任意节点IP 端口 # 重新加入集群
6、其他高频小问题
问题 1:集群中某个主节点无法删除 / 替换
现象:执行 CLUSTER FORGET 节点ID 后,节点又重新出现在集群中;
原因:Gossip 协议会同步节点信息,需先移除该节点的所有从节点,再迁移其槽位,最后执行 FORGET;
解决方案:
bash
# 1. 迁移该主节点的所有槽位到其他主节点
redis-cli --cluster reshard 该节点IP:端口
# 2. 移除该节点的从节点(CLUSTER RESET 从节点)
# 3. 所有节点执行 CLUSTER FORGET 该节点ID
问题 2:集群内存使用率不均(某节点内存满,其他节点空闲)
现象:主节点间内存占用差异大,部分节点触发 maxmemory 淘汰;
原因:哈希槽分配不均,或单个槽位中存在大 key(如百万元素的 Hash);
解决方案:
- 重新均衡槽位:
redis-cli --cluster rebalance 集群任意节点IP:端口; - 拆分大 key:避免单个 key 占用过多内存,导致槽位数据倾斜。
问题 3:集群重启后槽位丢失
现象:集群重启后 CLUSTER NODES 显示槽位未分配;
原因:cluster-config-file(如 nodes-6379.conf)被删除 / 权限不足,节点重启后丢失集群状态;
解决方案:
- 恢复
cluster-config-file文件,或重新分配槽位; - 确保 Redis 用户对该文件有读写权限(
chown redis:redis nodes-6379.conf)。
7、Redis Cluster 生产环境避坑指南
(1) 部署规范
主节点数为奇数(3/5),每个主节点至少 1 个从节点;
所有节点部署在同一机房 / 网段,避免跨公网部署(网络延迟 / 丢包不可控);
节点的 maxmemory 配置一致,且预留 20% 内存(避免 OOM)。
(2) 配置规范
所有节点开启 cluster-enabled yes,cluster-node-timeout 统一设为 30000ms;
配置 cluster-announce-ip 声明节点的实际 IP(避免内外网 IP 混淆);
禁用 FLUSHALL/FLUSHDB 等危险命令(rename-command FLUSHALL "")。
(3) 监控规范
监控 cluster_state(必须为 ok)、cluster_slots_assigned(必须为 16384);
监控主节点的 used_memory、从节点的 master_lag(同步延迟);
监控节点的连接状态(connected_clients)、集群总线端口连通性。
(4) 操作规范
手动迁移槽位 / 替换节点时,先备份数据;
避免在业务高峰期执行 reshard/rebalance(会产生迁移流量);
故障转移后,检查客户端路由表是否更新,避免读写异常。
附:Redis Cluster 核心排查命令速查
| 命令 | 作用 |
|---|---|
CLUSTER INFO |
查看集群整体状态(健康度、槽位、故障转移数) |
CLUSTER NODES |
查看所有节点的 ID、角色、槽位、连接状态 |
CLUSTER SLOTS |
查看所有槽位的分配情况(槽位→节点映射) |
CLUSTER GETKEYSINSLOT 槽位号 数量 |
查看指定槽位中的 key |
CLUSTER SETSLOT 槽位号 NODE 节点ID |
手动分配槽位到指定节点 |
redis-cli --cluster check 节点IP:端口 |
检查集群健康度(槽位分配、主从关系) |
redis-cli --cluster rebalance 节点IP:端口 |
均衡集群槽位分配 |
总结
-
Redis Cluster 核心是16384 个哈希槽,通过槽位分片实现数据分布式存储,支持水平扩展。
-
架构去中心化,主从复制 + 自动故障转移保障高可用,最小部署需 3 主 3 从。
-
核心限制是跨槽多键操作受限,需通过哈希标签
{}解决,客户端需支持集群协议。 -
底层复用 :哨兵模式和集群模式都基于主从复制实现数据同步,主从复制是三者的核心底层机制;
-
功能递进 :主从复制解决 "数据备份",哨兵模式解决 "主从的自动故障转移",集群模式解决 "分片 + 分布式高可用";
--: |
|
CLUSTER INFO| 查看集群整体状态(健康度、槽位、故障转移数) ||
CLUSTER NODES| 查看所有节点的 ID、角色、槽位、连接状态 ||
CLUSTER SLOTS| 查看所有槽位的分配情况(槽位→节点映射) ||
CLUSTER GETKEYSINSLOT 槽位号 数量| 查看指定槽位中的 key ||
CLUSTER SETSLOT 槽位号 NODE 节点ID| 手动分配槽位到指定节点 ||
redis-cli --cluster check 节点IP:端口| 检查集群健康度(槽位分配、主从关系) ||
redis-cli --cluster rebalance 节点IP:端口| 均衡集群槽位分配 |
总结
-
Redis Cluster 核心是16384 个哈希槽,通过槽位分片实现数据分布式存储,支持水平扩展。
-
架构去中心化,主从复制 + 自动故障转移保障高可用,最小部署需 3 主 3 从。
-
核心限制是跨槽多键操作受限,需通过哈希标签
{}解决,客户端需支持集群协议。 -
底层复用 :哨兵模式和集群模式都基于主从复制实现数据同步,主从复制是三者的核心底层机制;
-
功能递进:主从复制解决 "数据备份",哨兵模式解决 "主从的自动故障转移",集群模式解决 "分片 + 分布式高可用";
-
场景替代:集群模式可完全替代 "哨兵 + 主从",是大规模生产环境的首选;哨兵模式仅适用于无需分片的中小规模场景。