Redis Cluster (Redis 集群模式)从入门到精通:架构解析、机制详解与运维排查

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 模式的核心:

  1. 槽位总数:固定 16384 个哈希槽(0~16383),这个数值兼顾了性能(节点间通信开销)和扩展性。

  2. 槽位分配:每个主节点会被分配一部分槽位(可手动 / 自动分配),集群的所有槽位必须全部分配给主节点,集群才处于 "可用" 状态。

  3. 键定位槽位

    对键执行 CRC16(key) % 16384计算,得到该键所属的槽位,再根据槽位找到对应的主节点。

    示例:键 user:100的 CRC16 结果是 5888,5888%16384=5888,若槽 5888 分配给主节点 A,则该键存储在 A 上。

  4. 节点与槽位绑定:集群中只有主节点负责持有槽位,每个主节点会被分配一段连续的槽位区间(无重叠、全覆盖),所有主节点的槽位共同组成完整的 16384 个槽。例如 3 主集群,槽位会均匀分配为 0-5460、5461-10922、10923-16383(官方默认均匀分配,也可手动调整)。

  5. 客户端重定向

    客户端连接任意节点发起请求,若该节点不持有目标槽位,会返回 MOVED 指令(如 MOVED 5888 192.168.1.10:6379),告知客户端正确的节点地址。

    客户端会缓存槽位与节点的映射关系,后续请求直接命中目标节点,减少重定向。

  6. 优势 :节点增删、扩容缩容时,仅需迁移对应槽位及槽内的数据,无需对全量数据重新计算哈希,迁移粒度可控、效率高,且不影响集群整体对外提供服务。

为了方便理解与记忆什么是哈希槽,简单举个例子:

首先,先给出一个直白的定义:哈希槽是 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)"。

自动故障转移

  1. 主节点下线后,其从节点会发起 "竞选",集群内其他主节点投票,获得半数以上选票的从节点晋升为新主节点(通常是数据复制最完整、存活时间最长的)。
  2. 新主节点接管原主节点的所有槽位,集群更新槽位映射关系,客户端后续请求自动路由到新主节点,原宕机主节点恢复后,会作为新主节点的从节点重新加入集群。
  3. 补:实现故障转移的前提:集群中超过半数的主节点处于在线状态,且宕机主节点存在可用的从节点(数据复制正常、未宕机),否则集群会进入不可写状态,保障数据一致性。

补: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
(只读) (一主一从/多从,异步复制主节点全量+增量数据)

四、使用限制与注意事项

  1. 多键操作限制 :跨槽的多键命令(如 MGET key1 key2,若 key1 和 key2 不在同一槽位)、事务、Lua 脚本会报错,需通过哈希标签规避。
  2. 不支持数据库切换 :Cluster 模式下只能使用 db0,SELECT 命令无效。
  3. 持久化建议:所有节点建议开启 RDB(必选)+ AOF(可选),防止故障转移后数据丢失。
  4. 客户端要求:需使用支持 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

核心原因(按排查优先级)
  1. 节点间集群总线端口(+10000)未开放,导致节点无法握手;
  2. 部分节点未开启 cluster-enabled yes,或配置未生效;
  3. 待加入节点已有数据(非空),集群要求加入的节点必须是空节点;
  4. 节点 cluster-node-timeout 配置不一致,导致心跳检测失败;
  5. 节点 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)。

核心原因
  1. 集群创建时未完成全量槽位分配(如 redis-cli --cluster create 未指定 --cluster-replicas);
  2. 手动迁移槽位时中断,导致槽位处于「迁移中」状态;
  3. 主节点宕机后,故障转移未完成,槽位未被从节点接管;
  4. 客户端未使用「集群模式」连接(如普通 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,但槽位仍未迁移。

核心原因(按排查优先级)
  1. 主节点的从节点数量为 0,或从节点状态为 fail(不可用);
  2. 从节点 replica-priority(优先级)被设为 0(永不晋升);
  3. 从节点与主节点同步延迟过高,超过 cluster-node-timeout
  4. 集群中半数以上主节点失联(网络分区),无法投票确认故障;
  5. 从节点的 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:6379ASK 12345 XXX:6379

业务报错 RedisClusterException: MOVED,性能大幅下降。

核心原因
  1. MOVED 重定向:客户端本地路由表过期,目标槽位已迁移到其他节点;
  2. ASK 重定向:槽位正在迁移中,临时重定向到目标节点;
  3. 客户端未开启「自动重定向」(如 redis-cli 未加 -c 参数);
  4. 集群频繁进行槽位迁移(如手动迁移未完成,或故障转移反复触发)。
排查 & 解决步骤

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

集群被拆分为两个独立分区,各自认为自己是「有效集群」;

数据写入出现「丢失」(写入到小分区,故障恢复后被覆盖)。

核心原因
  1. 节点间网络中断(集群总线端口 / 业务端口被防火墙拦截);
  2. cluster-node-timeout 配置过小,轻微网络抖动就判定节点下线;
  3. 节点内存不足被 OOM 杀死,重启后与集群失联;
  4. 集群节点数为偶数,导致脑裂时无法判定「半数主节点」。
排查 & 解决步骤

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 yescluster-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:端口 均衡集群槽位分配

总结

  1. Redis Cluster 核心是16384 个哈希槽,通过槽位分片实现数据分布式存储,支持水平扩展。

  2. 架构去中心化,主从复制 + 自动故障转移保障高可用,最小部署需 3 主 3 从。

  3. 核心限制是跨槽多键操作受限,需通过哈希标签 {} 解决,客户端需支持集群协议。

  4. 底层复用 :哨兵模式和集群模式都基于主从复制实现数据同步,主从复制是三者的核心底层机制;

  5. 功能递进 :主从复制解决 "数据备份",哨兵模式解决 "主从的自动故障转移",集群模式解决 "分片 + 分布式高可用";

    --: |

    | CLUSTER INFO | 查看集群整体状态(健康度、槽位、故障转移数) |

    | CLUSTER NODES | 查看所有节点的 ID、角色、槽位、连接状态 |

    | CLUSTER SLOTS | 查看所有槽位的分配情况(槽位→节点映射) |

    | CLUSTER GETKEYSINSLOT 槽位号 数量 | 查看指定槽位中的 key |

    | CLUSTER SETSLOT 槽位号 NODE 节点ID | 手动分配槽位到指定节点 |

    | redis-cli --cluster check 节点IP:端口 | 检查集群健康度(槽位分配、主从关系) |

    | redis-cli --cluster rebalance 节点IP:端口 | 均衡集群槽位分配 |

总结

  1. Redis Cluster 核心是16384 个哈希槽,通过槽位分片实现数据分布式存储,支持水平扩展。

  2. 架构去中心化,主从复制 + 自动故障转移保障高可用,最小部署需 3 主 3 从。

  3. 核心限制是跨槽多键操作受限,需通过哈希标签 {} 解决,客户端需支持集群协议。

  4. 底层复用 :哨兵模式和集群模式都基于主从复制实现数据同步,主从复制是三者的核心底层机制;

  5. 功能递进:主从复制解决 "数据备份",哨兵模式解决 "主从的自动故障转移",集群模式解决 "分片 + 分布式高可用";

  6. 场景替代:集群模式可完全替代 "哨兵 + 主从",是大规模生产环境的首选;哨兵模式仅适用于无需分片的中小规模场景。

相关推荐
TongSearch2 小时前
TongSearch中分片从何而来,又解决了什么问题
java·elasticsearch·tongsearch
进阶小白猿2 小时前
Java技术八股学习Day26
java·开发语言·学习
余瑜鱼鱼鱼2 小时前
synchronized总结
java·开发语言
小宇的天下2 小时前
Calibre :SVRF rule file example
java·开发语言·数据库
码农水水2 小时前
大疆Java面试被问:使用Async-profiler进行CPU热点分析和火焰图解读
java·开发语言·jvm·数据结构·后端·面试·职场和发展
我真的是大笨蛋2 小时前
MVCC解析
java·数据库·spring boot·sql·mysql·设计模式·设计规范
秃头续命码农人2 小时前
谈谈对Spring、Spring MVC、SpringBoot、SpringCloud,Mybatis框架的理解
java·spring boot·spring·mvc·maven·mybatis
阿湯哥2 小时前
Reactor响应式编程中Flux和FluxSink
运维·服务器·网络
ahauedu2 小时前
SpringBoot 3.5.10引入springdoc-openapi-starter-webmvc-ui版本
java·spring boot·后端