Redis 集群详解(基于 6.0.10 版本)
Redis 集群(Redis Cluster)是 Redis 3.0 引入的分布式解决方案,旨在解决单机 Redis 的容量和性能瓶颈,支持水平扩展、自动分片和故障转移。本文基于 6.0.10 版本,详细解析集群的核心原理、搭建方法、命令操作及可用性保障。
集群核心原理:虚拟槽(Virtual Slot)分片
Redis 集群采用虚拟槽分片策略,将数据分散到多个节点,平衡负载并支持动态扩展。
虚拟槽的工作机制
- 槽范围:集群将数据划分为
0~16383 共 16384 个虚拟槽(固定值,由 2^14 计算而来)。
- 键与槽的映射:存储键值对时,Redis 通过以下步骤定位槽:
- 对键执行
CRC16 哈希算法,得到哈希值。
- 哈希值对
16384 取余,结果即为该键所属的槽(slot = CRC16(key) % 16384)。
- 槽与节点的映射:集群中的每个主节点负责一部分槽(如节点 A 负责
0~5000,节点 B 负责 5001~10000 等),集群自动维护槽与节点的对应关系。
为什么选择虚拟槽?
对比传统分片策略,虚拟槽的优势显著:
| 分片策略 |
原理 |
缺点 |
虚拟槽的改进 |
取模(如 key%N) |
键对节点数取模定位节点 |
节点增减时,大量键需重新映射(命中率骤降) |
槽与节点解耦,节点增减仅需迁移部分槽 |
| 一致性哈希 |
键和节点映射到 2^32 哈希环 |
节点少时易分布不均,负载失衡 |
16384 个槽均匀分布,负载更均衡 |
集群架构与通信
节点类型与角色
- 主节点(Master):负责处理槽的读写请求,存储数据,每个主节点可挂载多个从节点。
- 从节点(Slave):复制主节点数据,主节点故障时通过选举成为新主节点(类似哨兵模式)。
- 集群规模:最小集群需 3 个主节点(保证投票容错),每个主节点至少 1 个从节点(高可用),推荐规模
3 主 3 从。
节点通信
- 端口要求:每个节点需开放两个端口(如6379和16379):
- 普通端口(如 6379):处理客户端请求。
- 数据端口(普通端口 + 10000,如 16379):节点间通信( gossip 协议)。
- Gossip 协议:节点通过周期性交换信息(如节点状态、槽映射),维护集群元数据一致性。
集群搭建与配置
环境准备
以 3 主 3 从 为例,节点端口分别为 6381~6386,步骤如下:
(1)创建配置文件
为每个节点创建独立配置文件(如 redis-6381.conf),核心配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # 开启集群模式 cluster-enabled yes # 集群配置文件(自动生成,记录节点与槽映射) cluster-config-file nodes-6381.conf # 节点超时时间(毫秒,超时未响应则标记为故障) cluster-node-timeout 15000 # 端口 port 6381 # 后台启动 daemonize yes # 数据目录 dir ./data/6381 # 绑定IP(生产环境需指定具体IP) bind 0.0.0.0
|
(2)启动所有节点
1 2 3
| redis-server redis-6381.conf redis-server redis-6382.conf # ... 启动 6383~6386
|
初始化集群(推荐 redis-cli --cluster)
Redis 6.0 推荐使用 redis-cli --cluster 工具(替代旧版 redis-trib.rb)快速搭建集群:
1 2 3 4 5
| # 创建集群,--cluster-replicas 1 表示每个主节点配 1 个从节点 redis-cli --cluster create \ 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 \ # 3 个主节点 127.0.0.1:6384 127.0.0.1:6385 127.0.0.1:6386 \ # 3 个从节点 --cluster-replicas 1
|
- 执行后,工具会自动分配槽(3 主节点平均分配 16384 个槽),并为每个主节点分配从节点。
- 确认配置后输入
yes,集群初始化完成。
手动配置集群(进阶)
若需手动控制槽分配或节点角色,可分步操作:
(1)添加节点到集群
1 2 3 4
| # 连接任意节点,将其他节点加入集群(以 6381 为种子节点) redis-cli -p 6381 cluster meet 127.0.0.1 6382 redis-cli -p 6381 cluster meet 127.0.0.1 6383 # ... 添加 6384~6386
|
(2)分配槽给主节点
1 2 3 4 5 6 7 8
| # 主节点 6381 负责 0~5461 槽 redis-cli -p 6381 cluster addslots {0..5461}
# 主节点 6382 负责 5462~10922 槽 redis-cli -p 6382 cluster addslots {5462..10922}
# 主节点 6383 负责 10923~16383 槽 redis-cli -p 6383 cluster addslots {10923..16383}
|
(3)设置从节点
1 2 3 4
| # 6384 作为 6381 的从节点(需先通过 cluster nodes 获取 6381 的 node_id) redis-cli -p 6384 cluster replicate <6381的node_id>
# 同理设置 6385 为 6382 的从节点,6386 为 6383 的从节点
|
集群核心命令
| 命令 |
作用 |
CLUSTER INFO |
查看集群状态(如 cluster_state:ok 表示正常)。 |
CLUSTER NODES |
列出所有节点信息(node_id、角色、负责的槽等)。 |
CLUSTER KEYSLOT <key> |
计算键所属的槽。 |
CLUSTER COUNTKEYSINSLOT <slot> |
查看指定槽中的键数量。 |
CLUSTER GETKEYSINSLOT <slot> <count> |
获取指定槽中的 count 个键。 |
CLUSTER MEET <ip> <port> |
将节点加入集群。 |
CLUSTER REPLICATE <node_id> |
将当前节点设为 node_id 节点的从节点。 |
CLUSTER ADDSLOTS <slot...> |
为当前节点分配槽(主节点专用)。 |
示例:查看集群状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 连接任意节点(需加 -c 表示集群模式) redis-cli -c -p 6381
# 查看集群信息 127.0.0.1:6381> CLUSTER INFO cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_size:3 # 主节点数 ...
# 查看节点列表 127.0.0.1:6381> CLUSTER NODES # 输出格式:node_id ip:port 角色 槽范围 ... abc123... 127.0.0.1:6381@16381 master - 0 1620000000000 1 connected 0-5461 def456... 127.0.0.1:6382@16382 master - 0 1620000000000 2 connected 5462-10922 ...
|
集群可用性与故障转移
集群不可用的条件
- 场景 1:任意主节点故障且无可用从节点(无法选举新主节点),集群进入
fail 状态。
- 场景 2:超过半数的主节点故障(无论是否有从节点),集群进入
fail 状态(无法达成投票共识)。
故障转移流程
- 检测故障:节点定期通过
PING 检测其他节点,若超时(cluster-node-timeout),标记为 “疑似下线(PFAIL)”。
- 确认下线:当超过半数主节点标记某节点为 PFAIL 时,将其标记为 “已下线(FAIL)” 并广播。
- 选举新主节点:故障主节点的从节点通过投票竞选新主节点(获得多数票者当选)。
- 迁移槽:新主节点接管原主节点的所有槽,集群恢复正常。
集群中,默认要求多键操作(如 MGET、事务、Lua 脚本)的所有键必须属于同一槽,否则会报错。通过 Hash Tags 可强制多键映射到同一槽:
集群运维:节点管理与数据迁移
添加节点
1 2 3 4 5 6
| # 添加新主节点(6387) redis-cli --cluster add-node 127.0.0.1:6387 127.0.0.1:6381
# 添加新从节点(6388),指定主节点 node_id redis-cli --cluster add-node 127.0.0.1:6388 127.0.0.1:6381 \ --cluster-slave --cluster-master-id <主节点node_id>
|
移除节点
1 2
| # 移除节点(需先迁移其负责的槽,否则失败) redis-cli --cluster del-node 127.0.0.1:6381 <待删除节点的node_id>
|
槽迁移(扩容 / 缩容)
1 2
| # 重新分配槽(指定目标节点,按提示输入迁移的槽数量和来源节点) redis-cli --cluster reshard 127.0.0.1:6381
|