0%

redis集群

Redis 集群详解(基于 6.0.10 版本)

Redis 集群(Redis Cluster)是 Redis 3.0 引入的分布式解决方案,旨在解决单机 Redis 的容量和性能瓶颈,支持水平扩展、自动分片和故障转移。本文基于 6.0.10 版本,详细解析集群的核心原理、搭建方法、命令操作及可用性保障。

集群核心原理:虚拟槽(Virtual Slot)分片

Redis 集群采用虚拟槽分片策略,将数据分散到多个节点,平衡负载并支持动态扩展。

虚拟槽的工作机制

  • 槽范围:集群将数据划分为 0~1638316384 个虚拟槽(固定值,由 2^14 计算而来)。
  • 键与槽的映射:存储键值对时,Redis 通过以下步骤定位槽:
    1. 对键执行 CRC16 哈希算法,得到哈希值。
    2. 哈希值对 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 状态(无法达成投票共识)。

故障转移流程

  1. 检测故障:节点定期通过 PING 检测其他节点,若超时(cluster-node-timeout),标记为 “疑似下线(PFAIL)”。
  2. 确认下线:当超过半数主节点标记某节点为 PFAIL 时,将其标记为 “已下线(FAIL)” 并广播。
  3. 选举新主节点:故障主节点的从节点通过投票竞选新主节点(获得多数票者当选)。
  4. 迁移槽:新主节点接管原主节点的所有槽,集群恢复正常。

集群高级特性:多键操作与 Hash Tags

集群中,默认要求多键操作(如 MGET、事务、Lua 脚本)的所有键必须属于同一槽,否则会报错。通过 Hash Tags 可强制多键映射到同一槽:

  • 语法:键名中包含 {tag},Redis 仅对 tag 部分计算槽(忽略其他内容)。

  • 示例:

    1
    2
    3
    4
    # 键 {user100}name 和 {user100}age 会映射到同一槽(因 tag 均为 user100)
    SET {user100}name "Alice"
    SET {user100}age 25
    MGET {user100}name {user100}age # 正常执行,返回 ["Alice", "25"]

集群运维:节点管理与数据迁移

添加节点

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

欢迎关注我的其它发布渠道