redis集群
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),核心配置:
# 开启集群模式
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)启动所有节点
redis-server redis-6381.conf
redis-server redis-6382.conf
... 启动 6383~6386
初始化集群(推荐 redis-cli --cluster)
Redis 6.0 推荐使用 redis-cli --cluster 工具(替代旧版 redis-trib.rb)快速搭建集群:
创建集群,--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)添加节点到集群
连接任意节点,将其他节点加入集群(以 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)分配槽给主节点
主节点 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)设置从节点
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...> |
为当前节点分配槽(主节点专用)。 |
示例:查看集群状态
连接任意节点(需加 -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)” 并广播。
- 选举新主节点:故障主节点的从节点通过投票竞选新主节点(获得多数票者当选)。
- 迁移槽:新主节点接管原主节点的所有槽,集群恢复正常。
集群高级特性:多键操作与 Hash Tags
集群中,默认要求多键操作(如 MGET、事务、Lua 脚本)的所有键必须属于同一槽,否则会报错。通过 Hash Tags 可强制多键映射到同一槽:
语法:键名中包含
{tag},Redis 仅对tag部分计算槽(忽略其他内容)。示例:
键 {user100}name 和 {user100}age 会映射到同一槽(因 tag 均为 user100) SET {user100}name "Alice" SET {user100}age 25 MGET {user100}name {user100}age # 正常执行,返回 ["Alice", "25"]
集群运维:节点管理与数据迁移
添加节点
添加新主节点(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>
移除节点
移除节点(需先迁移其负责的槽,否则失败)
redis-cli --cluster del-node 127.0.0.1:6381 <待删除节点的node_id>
槽迁移(扩容 / 缩容)
重新分配槽(指定目标节点,按提示输入迁移的槽数量和来源节点)
redis-cli --cluster reshard 127.0.0.1:6381