Redis 集群原理与部署
来源: 豆包ai, redis原理-1,redis 安装与数据模型-2,redis主从搭建,redis哨兵
Redis 集群(Redis Cluster)是 Redis 官方提供的分布式解决方案,核心目标是解决 单点故障 、容量上限 和 性能瓶颈 问题,支持数据分片存储、自动故障转移和水平扩展,适用于高可用、大规模的生产环境。
一、Redis 集群核心原理
1.1、数据分片与角色
-
数据分片:一致性哈希与槽位(Slot)机制
-
Redis 集群不使用传统一致性哈希,而是采用 固定槽位分片 策略,这是集群数据分布的核心:
-
槽位总数:固定 16384 个(0~16383),每个槽位对应一个数据存储单元;
-
数据映射规则 :通过
CRC16(key) % 16384计算键的哈希值,将键分配到对应槽位; -
节点与槽位绑定:集群中每个主节点(Master)负责一部分槽位(需手动分配或自动分配),所有主节点的槽位不重叠、全覆盖 16384 个槽,数据按槽位分散存储在不同主节点上。
-
-
3 主节点的槽位分配
主节点 负责槽位范围 槽位数量 node1 0~5460 5461 node2 5461~10922 5462 node3 10923~16383 5461
-
-
节点角色与副本机制
- Redis 集群节点分为 主节点(Master) 和 从节点(Slave) ,角色分工明确:
- 主节点(Master):
- 唯一负责槽位的读写操作,接收客户端请求并处理;
- 一个主节点可对应多个从节点(建议 1~2 个,兼顾高可用与资源开销)。
- 从节点(Slave):
- 不负责槽位,仅同步主节点的数据(通过 Redis 复制机制:全量复制 + 增量复制);
- 主节点故障时,从节点可通过选举晋升为新主节点,实现故障转移。
- 核心原则
- 主节点故障后,其负责的槽位由晋升后的新主节点接管,客户端无感知;
- 从节点仅提供读服务(需客户端开启只读路由),可分担主节点读压力。
- 主节点(Master):
- Redis 集群节点分为 主节点(Master) 和 从节点(Slave) ,角色分工明确:
1.2、集群通信:Gossip 协议
Redis 集群节点间通过 Gossip 协议 实现去中心化通信,无需中心协调节点:
- 作用
- 同步集群元数据,包括节点状态(在线 / 离线)、槽位分配、主从关系。
- 支撑故障检测,节点通过消息交互判断其他节点健康状态。
- 保障集群去中心化,无单点依赖,节点加入 / 退出无需全局同步。
- 工作机制
- 节点随机选择集群中部分节点(通常 3-5 个),定期发送 PING 消息。
- 消息包含自身状态、已知其他节点状态及槽位信息。
- 接收消息的节点更新本地集群信息,再转发给其他随机节点,形成 "病毒式传播"。
- 消息传播有天然延迟,但通过高频发送(默认每秒),集群状态最终会趋于一致。
- 特点
- 优点:去中心化,无中心节点故障风险;通信开销低,无需全局广播
- 缺点:消息传播存在延迟(毫秒级),极端情况下可能出现集群状态短暂不一致
- 在 Redis 集群中的具体应用
- 节点心跳检测:每个节点通过 Gossip 协议向其他节点发送 PING,接收 PONG 响应,判断节点是否存活。
- 故障状态扩散:节点标记某节点为 "疑似下线(PFAIL)" 后,通过 Gossip 协议广播该状态,供其他节点投票判断是否 "确定下线(FAIL)"。
- 槽位与拓扑更新:槽位迁移、主从切换后,节点通过 Gossip 协议同步新的槽位分配和拓扑关系,让整个集群感知变化。
1.3、故障切换说明
集群通过 "节点心跳" 和 "投票选举" 实现故障自愈:
-
故障检测
- 每个节点定期向其他节点发送 PING 消息,接收 PONG 响应;
- 若节点 A 连续多次(默认 15 秒)未收到节点 B 的 PONG 响应,A 标记 B 为 "疑似下线(PFAIL)";
- A 将 B 的 PFAIL 状态通过 Gossip 协议广播给其他节点;
- 当集群中 超过半数主节点 标记 B 为 PFAIL 时,B 被标记为 "确定下线(FAIL)"。
-
故障转移(仅主节点故障触发)
- 被标记为 FAIL 的主节点的所有从节点,会触发 "选举资格检查"(如复制偏移量是否接近主节点,确保数据一致性);
- 符合条件的从节点向集群中所有主节点发送 "选举请求";
- 主节点收到请求后,若未投票,会给该从节点投一票;
- 若某从节点获得 超过半数主节点的选票,则晋升为新主节点;
- 新主节点接管原主节点的所有槽位,并通知集群中其他节点更新拓扑信息;
- 原主节点恢复后,会自动成为新主节点的从节点。
-
流程图

1.4、客户端路由机制
Redis 集群客户端支持两种路由模式:
-
智能客户端(推荐):
- 首次连接时,客户端会从任意节点获取 全量槽位分配表(槽位 -> 主节点地址映射);
- 后续请求时,客户端本地计算键的槽位,直接向对应主节点发送请求,无需转发,性能高;
- 若槽位迁移(扩容 / 缩容)或节点故障,客户端收到
MOVED/ASK错误后,自动更新本地槽位表,并重试请求。
-
非智能客户端:
- 客户端随机连接一个节点,若该节点不负责目标槽位,会返回
MOVED错误(包含目标主节点地址); - 客户端需重新向目标节点发送请求,每次路由都需转发,性能低,不推荐生产使用。
- 客户端随机连接一个节点,若该节点不负责目标槽位,会返回
-
关键区别对比
特点 智能客户端 非智能客户端 槽位映射获取 首次连接获取全量表,本地缓存 无本地缓存,靠节点返回 MOVED告知请求转发 无转发,直接连目标主节点 需多次连接(随机节点→目标节点) 性能 高(减少网络开销和节点压力) 低(多轮交互,浪费资源) 适配场景 生产环境、高并发场景 测试环境、低流量临时使用 典型示例 JedisCluster、Spring Data Redis 原生 redis-cli(未加 -c参数)
二、开始搭建
2.1、前置准备
-
前置条件
-
先安装好redis: redis 安装与数据模型-2, 我们用7.2.12版本
-
依赖安装: Redis 集群依赖
ruby和rubygemsbash# CentOS yum install -y ruby rubygems # Ubuntu apt-get install -y ruby rubygems -
关闭防火墙或开放 6379,6380 端口(避免主从通信失败):
bash# 临时关闭防火墙(CentOS) systemctl stop firewalld # 永久开放 firewall-cmd --permanent --add-port=6379/tcp firewall-cmd --permanent --add-port=6380/tcp firewall-cmd --permanent --add-port=16379/tcp firewall-cmd --permanent --add-port=16380/tcp # 或者,推荐用富策略,三台之间互通就行, # 避免生产用久了要修复版本漏洞怪麻烦,如果在机房 ssh端口都建议关掉 firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.189.129" protocol value="tcp" accept' firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.189.134" protocol value="tcp" accept' firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.189.135" protocol value="tcp" accept' firewall-cmd --reload
-
-
节点数量:至少 3 个主节点(保证故障投票时超过半数),每个主节点建议 1 个从节点,共 6 个节点;
-
服务器规划 , 上章编译的redis ,提取码:1234
服务器 IP 节点 1(端口) 节点 2(端口) 角色 192.168.189.129 6379 6380 主 / 从 192.168.189.134 6379 6380 主 / 从 192.168.189.135 6379 6380 主 / 从
2.2、开始搭建
-
创建节点目录与配置文件
-
在每台服务器上创建 2 个节点的目录(区分端口),并编写 Redis 配置文件
redis.conf:bash# 示例:在 192.168.189.129 服务器创建目录 mkdir -p /data/redis/cluster/{6379,6380} # 两个,用vi 直接 :1,$s6379@6380@gi 改就成 cd /data/redis/cluster/6379 cd /data/redis/cluster/6380 <-- 配置里的端口也要改一下 vim redis.conf ##################### 基础配置 # 节点端口(6379/6380) port 6379 # PID 文件路径 pidfile /data/redis/cluster/6379/redis-6379.pid # 数据存储目录 dir /data/redis/cluster/6379 # 后台运行 daemonize yes # 日志文件 logfile /data/redis/cluster/6379/redis.log ##################### 集群核心配置 # 启用集群模式 cluster-enabled yes # 集群节点信息文件(自动生成/更新) cluster-config-file nodes-6379.conf # 节点超时时间(毫秒,故障检测阈值) cluster-node-timeout 15000 # 从节点选举有效性因子(默认 10) cluster-replica-validity-factor 10 # 主节点最小从节点数(防止脑裂,默认 1) cluster-migration-barrier 1 ##################### 其他优化配置 # 允许所有IP访问(生产环境需限制具体IP) bind 0.0.0.0 # 关闭保护模式(需配合密码或IP限制) protected-mode no # 节点密码(所有节点密码必须一致) requirepass xiong # 主从同步密码(与 requirepass 一致) masterauth xiong # 开启AOF持久化(保证数据不丢失) appendonly yes # AOF同步策略(每秒同步) appendfsync everysec-
自启脚本
bash# 两个,用vi 直接 :1,$s6379@6380@gi 改就成 vi /usr/lib/systemd/system/redis_cluster_6379.service vi /usr/lib/systemd/system/redis_cluster_6380.service [Unit] Description=Redis Cluster Node 6379 After=network.target Wants=network.target [Service] Type=forking User=root Group=root PIDFile=/data/redis/cluster/6379/redis-6379.pid ExecStart=/data/redis/bin/redis-server /data/redis/cluster/6379/redis.conf ExecStop=/data/redis/bin/redis-cli -a xiong -p 6379 shutdown Restart=always RestartSec=3 LimitNOFILE=65535 [Install] WantedBy=multi-user.target -
启动节点并自启
bash# 启动节点 systemctl start redis_cluster_6379 systemctl start redis_cluster_6380 # 设置开机自启 systemctl enable redis_cluster_6379 systemctl enable redis_cluster_6380 -
验证
bashsystemctl status redis_cluster_6379 systemctl status redis_cluster_6380 # 会自动在fock一个16379跟16380 LISTEN 0 511 *:6379 *:* users:(("redis-server",pid=9791,fd=7)) LISTEN 0 511 *:6380 *:* users:(("redis-server",pid=9810,fd=7)) LISTEN 0 511 *:16379 *:* users:(("redis-server",pid=9791,fd=8)) LISTEN 0 511 *:16380 *:* users:(("redis-server",pid=9810,fd=8))- 端口说明:
- 6379/6380 是给客户端用的 "业务端口"
- 16379/16380 是集群节点间 "内部沟通的管理端口"。
- 端口说明:
-
-
2.3、创建redis集群
-
通过
redis-cli工具执行集群创建命令(只需在任意一台服务器执行一次):bash# 语法:redis-cli --cluster create 主节点1:端口 主节点2:端口 主节点3:端口 从节点1:端口 从节点2:端口 从节点3:端口 --cluster-replicas 1 [root@localhost bin]# echo yes | REDISCLI_AUTH=xiong ./redis-cli --cluster create \ > 192.168.189.129:6379 192.168.189.134:6379 192.168.189.135:6379 \ > 192.168.189.129:6380 192.168.189.134:6380 192.168.189.135:6380 \ > --cluster-replicas 1 echo yes | # 免输yes REDISCLI_AUTH=xiong # 用环境变量的传密 # 也可以用-a xiong # 节点密码(与配置文件 requirepass 一致) --cluster-replicas 1 # 每个主节点分配 1 个从节点(自动配对主从) -
执行后会提示槽位分配方案
bash>>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 192.168.189.134:6380 to 192.168.189.129:6379 Adding replica 192.168.189.135:6380 to 192.168.189.134:6379 Adding replica 192.168.189.129:6380 to 192.168.189.135:6379 M: ec4a22...be9e20d69e2f 192.168.189.129:6379 slots:[0-5460] (5461 slots) master M: 5eea782....5cf2e38ba9b 192.168.189.134:6379 slots:[5461-10922] (5462 slots) master M: 71caa595...c1b12d716f4 192.168.189.135:6379 slots:[10923-16383] (5461 slots) master S: 71caa595....d716f4 192.168.189.129:6380 replicates 71caa595...c1b12d716f4 S: 5bd5255....7082543f 192.168.189.134:6380 replicates ec4a22...be9e20d69e2f S: 1ab0ef1.....7b83aab 192.168.189.135:6380 replicates 5eea782....5cf2e38ba9b -
验证集群状态:连接集群任意节点,查看集群信息:
bash# 连接集群(-c 表示启用集群模式客户端) redis-cli -a xiong -c -h 192.168.189.129 -p 6379 # 查看集群状态(所有节点在线、槽位全部分配) 192.168.189.129:6379> cluster info cluster_state:ok # 集群状态(ok 表示正常) cluster_slots_assigned:16384 # 已分配槽位数量(16384 表示全部分配) cluster_slots_ok:16384 # 正常槽位数量 cluster_slots_pfail:0 # 疑似故障槽位数量 cluster_slots_fail:0 # 故障槽位数量 cluster_known_nodes:6 # 集群节点总数 cluster_size:3 # 主节点数量 cluster_current_epoch:6 # 当前集群纪元 cluster_my_epoch:1 # 本节点纪元 cluster_stats_messages_ping_sent:334 cluster_stats_messages_pong_sent:315 cluster_stats_messages_sent:649 cluster_stats_messages_ping_received:310 cluster_stats_messages_pong_received:334 cluster_stats_messages_meet_received:5 cluster_stats_messages_received:649 total_cluster_links_buffer_limit_exceeded:0 # 查看节点详情(主从关系、槽位分配) 192.168.189.129:6379> cluster nodes # 输出格式:节点ID 节点IP:端口 角色 槽位范围 纪元 状态 192.168.189.129:6379> CLUSTER NODES 5bd...43f 192.168.189.134:6380@16380 slave ec4...e2f 0 1763562044000 1 connected 1ab...aab 192.168.189.135:6380@16380 slave 5ee...a9b 0 1763562043000 2 connected 2f0...3e9 192.168.189.129:6380@16380 slave 71c...6f4 0 1763562045000 3 connected 5ee...a9b 192.168.189.134:6379@16379 master - 0 1763562044974 2 connected 5461-10922 71c...6f4 192.168.189.135:6379@16379 master - 0 1763562045984 3 connected 10923-16383 ec4...e2f 192.168.189.129:6379@16379 myself,master - 0 1763562044000 1 connected 0-5460 -
测试集群功能
-
数据写入与路由:
bash# 我们在连接的时候加上 -c 开启集群模式,让 redis-cli 变成 "临时智能客户端" # name 这个糟位在134上面,它就会自动跳转到对应的主节点之上 192.168.189.129:6379> set name redis-cluster # 自动路由到对应主节点 -> Redirected to slot [5798] located at 192.168.189.134:6379 OK 192.168.189.134:6379> get name "redis-cluster" -
故障转移测试(手动停止一个主节点,验证从节点晋升):
bash# 任选一台 systemctl stop redis_cluster_6379 # 需要等一会 30秒左右 停了6379就会有一台3680接上来 192.168.189.134:6379> CLUSTER nodes 2f0...3e9 192.168.189.129:6380@16380 slave 71c...6f4 0 176...457 3 connected 5bd...43f 192.168.189.134:6380@16380 master - 0 176...444 7 connected 0-5460 1ab...aab 192.168.189.135:6380@16380 slave 5ee...a9b 0 176...436 2 connected 5ee...a9b 192.168.189.134:6379@16379 myself,master - 0 176...000 2 connected 5461-10922 ec4...e2f 192.168.189.129:6379@16379 master,fail - 176...036 176...000 1 disconnected 71c...6f4 192.168.189.135:6379@16379 master - 0 176..000 3 connected 10923-16383 # 如果我们此时在将6379启动 就会发现它变成了slave从节点
-
三、集群扩容与缩容
3.1、扩容(新增 1 主 1 从)
-
129、跟134在复制一个6381, 启动
-
新节点加入集群
bash# 就是将 192.168.189.129:6381 加入到 192.168.189.129:6379 节点中 ./redis-cli -a xiong --cluster add-node 192.168.189.129:6381 192.168.189.129:6379 # 此时可以发现已经有四个master节点,但它现在没有糟点, 不会保存数据 192.168.189.134:6379> cluster nodes 2f0d....3e9 192.x.x.129:6380@16380 slave 71ca....6f4 0 1763563444517 3 connected 5bd5....43f 192.x.x.134:6380@16380 master - 0 1763563444000 7 connected 0-5460 1ab0....aab 192.x.x.135:6380@16380 slave 5eea....a9b 0 1763563444000 2 connected f65e....012 192.x.x.129:6381@16381 master - 0 1763563445000 0 connected 5eea....a9b 192.x.x.134:6379@16379 myself,master - 0 1763563443000 2 connected 5461-10922 ec4a....e2f 192.x.x.129:6379@16379 slave 5bd5....43f 0 1763563445528 7 connected 71ca....6f4 192.x.x.135:6379@16379 master - 0 1763563443501 3 connected 10923-16383 -
为新主节点分配槽位(从现有主节点迁移槽位):
bash./redis-cli -a xiong --cluster reshard 192.168.189.129:6379 .... M: f65ed30aef6a1a0b98cf4080ee08d5a831104012 192.168.189.129:6381 .... .... 问:要迁移多少个槽位? 答:输入具体数量, "总槽位 16384/主节点总数" 分配, 16384/(3+1)≈4096 How many slots do you want to move (from 1 to 16384)? 4096 # 糟位的id号 上面会直接打印 What is the receiving node ID? f65ed30aef6a1a0b98cf4080ee08d5a831104012 # 从所有现有主节点平均迁移,推荐 Please enter all the source node IDs. Type 'all' to use all the nodes as source nodes for the hash slots. Type 'done' once you entered all the source nodes IDs. Source node #1: all <---输入all # 在输入yes开始迁移 Do you want to proceed with the proposed reshard plan (yes/no)? -
将新从节点加入集群并绑定主节点:
bash./redis-cli -a xiong --cluster reshard 192.168.189.129:6379 # 将 192.168.189.134:6381 也加入到集群 cluster-slave, 最后跟主节点id 也就是 129:6381的id ./redis-cli -a xiong --cluster add-node 192.168.189.134:6381 192.168.189.129:6379 --cluster-slave --cluster-master-id f65ed30aef6a1a0b98cf4080ee08d5a831104012 # 就是加进去的糟位不怎么连贯 ./redis-cli -a xiong -h 192.168.189.134 -p 6379 -c 192.168.189.134:6379> CLUSTER nodes 2f0...3e9 192.x.x.129:6380@16380 slave 71c...6f4 0 1763564061575 3 connected 71c...6f4 192.x.x.135:6379@16379 master - 0 1763564060000 3 connected 12288-16383 5bd...43f 192.x.x.134:6380@16380 master - 0 1763564060564 7 connected 1365-5460 ec4...e2f 192.x.x.129:6379@16379 slave 5bd...43f 0 1763564059551 7 connected 5ee...a9b 192.x.x.134:6379@16379 myself,master - 0 1763564061000 2 connected 6827-10922 1ab...aab 192.x.x.135:6380@16380 slave 5ee...a9b 0 1763564058000 2 connected efa...169 192.x.x.134:6381@16381 slave f65...012 0 1763564058542 8 connected f65...012 192.x.x.129:6381@16381 master - 0 1763564060000 8 connected 0-1364 5461-6826 10923-12287
3.2、缩容(移除 1 主 1 从)
-
执行槽位迁移命令(连接集群任意节点均可,这里用
192.168.189.134:6379)bash# 替换你的密码(123456 改为实际密码) redis-cli -a 123456 --cluster reshard 192.168.189.134:6379 M: 5eea782a7466ae154c24c19f8c7555cf2e38ba9b 192.168.189.134:6379 .... # 按提示逐步输入(关键输入已标红): How many slots do you want to move? (from 1 to 16384) 4096 # 输入 4096(目标主节点的所有槽位数量,必须精确)。 What is the receiving node ID? 5e..ba9b # 我就用134:6379接收它 # 接收这些槽位的目标主节点 ID , 挑选任意一个主节点号 Please enter all the source node IDs... # 从哪个源节点迁移槽位? # source node #1: 要迁移的源节点 ID # Source node #2: done Do you want .. reshard plan? (type 'yes' to accept) yes # 输入yes就会开始迁移 -
迁移验证
bash./redis-cli -a xiong -c -h 192.168.189.129 -p 6381 cluster nodes | grep "myself" f65ed30aef6a1a0b98cf4080ee08d5a831104012 192.168.189.129:6381@16381 myself,master - 0 1763566000000 8 connected -
移除目标主节点对应的从节点(192.168.189.134:6381)
bash./redis-cli -a 123456 --cluster del-node 192.168.189.134:6381 efaf6a1d9f872210efb1ad66d3ea62c0591e9169 >>> Sending CLUSTER RESET SOFT to the deleted node. -
移除空主节点(192.168.189.129:6381)
bash./redis-cli -a xiong --cluster del-node 192.168.189.129:6381 f65ed30aef6a1a0b98cf4080ee08d5a831104012 >>> Sending CLUSTER RESET SOFT to the deleted node. -
最后在查看就只有3主3从了
四、注意事项
- 节点密码 :所有节点必须设置相同密码(
requirepass和masterauth),否则主从同步和集群通信失败; - 持久化配置:必须开启 AOF 或 RDB 持久化(推荐 AOF),防止节点重启后数据丢失;
- 服务器规划:主从节点需部署在不同服务器(跨机架 / 机房),避免单点故障;
- 槽位分配 :确保 16384 个槽位全部分配(
cluster_slots_assigned:16384),否则集群状态为fail; - 故障转移参数 :调整
cluster-node-timeout(默认 15 秒),根据业务容忍度设置(如核心业务可设 5~10 秒); - 客户端选择:使用智能客户端(如 Java 的 JedisCluster、Spring Data Redis),避免非智能客户端的转发开销;
- 监控告警 :监控集群状态(
cluster_state)、节点在线状态、槽位健康度、主从同步延迟,设置告警阈值; - 避免脑裂 :开启
cluster-migration-barrier 1(默认),确保主节点至少有 1 个健康从节点才允许槽位迁移。 - 总结:
- Redis 集群通过 槽位分片 实现数据分布式存储,通过 主从复制 和 自动故障转移 保证高可用,通过 Gossip 协议 实现节点通信,支持水平扩容 / 缩容。部署时需满足 "至少 3 主" 的核心要求,生产环境需重点关注持久化、跨节点部署、密码配置和监控告警,确保集群稳定运行。