Skip to content
清晨的一缕阳光
返回

Redis Cluster 原理详解

Redis Cluster 原理详解

Redis Cluster 是 Redis 的分布式解决方案,提供自动分片、高可用、水平扩展能力。本文将深入 Cluster 的核心原理和实现机制。

一、Cluster 架构

1.1 集群结构

Redis Cluster (6 节点,3 主 3 从):

┌─────────┐    ┌─────────┐    ┌─────────┐
│Master 1 │    │Master 2 │    │Master 3 │
│192.168  │    │192.168  │    │192.168  │
│.1.1:7000│    │.1.2:7001│    │.1.3:7002│
│0-5460   │    │5461-10922│   │10923-16383│
└────┬────┘    └────┬────┘    └────┬────┘
     │              │              │
┌────┴────┐    ┌────┴────┐    ┌────┴────┐
│ Slave 1 │    │ Slave 2 │    │ Slave 3 │
│192.168  │    │192.168  │    │192.168  │
│.1.4:7003│    │.1.5:7004│    │.1.6:7005│
└─────────┘    └─────────┘    └─────────┘

1.2 核心特性

特性说明
自动分片16384 个槽位,自动分配
去中心化每个节点存储集群元数据
高可用主从复制 + 自动故障转移
水平扩展动态添加/删除节点

二、数据分片

2.1 槽位(Slot)

Redis Cluster 有 16384 个槽位:
- 槽位 0-16383
- 每个主节点负责一部分槽位
- 槽位是数据分片的基本单位

槽位分配:
Master 1: 槽位 0-5460
Master 2: 槽位 5461-10922
Master 3: 槽位 10923-16383

2.2 哈希计算

key → CRC16 → hash → hash % 16384 → slot

示例:
key = "user:1001"
hash = CRC16("user:1001") = 12345
slot = 12345 % 16384 = 12345

key = "{user}:1001"  # 哈希标签
hash = CRC16("{user}") = 6789
slot = 6789 % 16384 = 6789

2.3 哈希标签(Hash Tags)

# 不使用哈希标签
MSET user:1001:name "Alice" user:1001:age 25
# 可能分布在不同节点

# 使用哈希标签
MSET {user:1001}:name "Alice" {user:1001}:age 25
# 保证在同一节点(相同槽位)

应用场景

用户数据:{user:1001}:name, {user:1001}:age, {user:1001}:email
订单数据:{order:2001}:items, {order:2001}:status

三、Gossip 协议

3.1 什么是 Gossip

Gossip(流言蜚语)协议:
- 节点间随机通信
- 传播集群状态
- 最终一致性

特点:
- 去中心化
- 容错性强
- 收敛慢但可靠

3.2 消息类型

PING 消息:
- 定期发送(默认 1 秒)
- 包含节点状态
- 其他节点收到后回复 PONG

PONG 消息:
- 回复 PING
- 广播状态变更

MEET 消息:
- 介绍新节点
- 将新节点加入集群

FAIL 消息:
- 节点故障通知
- 触发故障转移

3.3 通信流程

节点 A                    节点 B
  │                          │
  │────── PING ───────────▶│  每秒发送
  │  (包含节点状态)          │
  │                          │
  │◀───── PONG ────────────│  回复
  │                          │
  │ 传播到其他节点          │
  │                          │
  │────── PING ───────────▶│  定期通信

3.4 节点状态

节点状态:
- myself: 自身
- master: 主节点
- slave: 从节点
- fail?: 疑似故障
- fail: 已故障
- handshake: 握手中
- noaddr: 无地址
- noflags: 无标志

四、故障转移

4.1 故障检测

从节点检测主节点故障:
1. 主节点超过超时时间无响应
2. 标记为主观故障 (PFAIL)
3. 通过 Gossip 传播
4. 多数节点确认 → 客观故障 (FAIL)

4.2 选举流程

主节点故障

从节点检测到 FAIL

从节点发起选举

其他从节点投票

获得多数票的从节点成为主节点

通知集群更新配置

4.3 选举规则

// 选举算法
void clusterHandleSlaveFailover() {
    // 1. 检查主节点是否故障
    if (nodeIsMaster(myself->slaveof)) {
        return;
    }
    
    // 2. 检查是否已超时
    if (now - myself->slaveof->data_received_time < timeout) {
        return;
    }
    
    // 3. 发起选举
    clusterStartFailover(CLUSTER_CFA_FAILOVER);
    
    // 4. 等待投票
    // 5. 获得多数票则成为主节点
}

五、客户端路由

5.1 重定向机制

客户端 ──▶ 节点 A (错误节点)


         MOVED 3456 192.168.1.2:7001


客户端 ──▶ 节点 B (正确节点)


           返回数据

5.2 重定向类型

# MOVED 重定向(永久)
(error) MOVED 3456 192.168.1.2:7001
# 槽位 3456 已迁移到 192.168.1.2:7001

# ASK 重定向(临时)
(error) ASK 3456 192.168.1.2:7001
# 槽位 3456 正在迁移

5.3 智能客户端

from redis.cluster import RedisCluster

# 智能客户端(自动路由)
rc = RedisCluster(
    host='192.168.1.1',
    port=7000,
    password='your_password'
)

# 自动路由到正确节点
rc.set('user:1001:name', 'Alice')  # 路由到 Master 1
rc.set('user:1002:name', 'Bob')    # 路由到 Master 2

# 获取槽位信息
slot = rc.keyslot('user:1001:name')
print(f"Slot: {slot}")

六、集群运维

6.1 创建集群

# 使用 redis-cli
redis-cli --cluster create \
  192.168.1.1:7000 192.168.1.2:7001 192.168.1.3:7002 \
  192.168.1.4:7003 192.168.1.5:7004 192.168.1.6:7005 \
  --cluster-replicas 1 \
  --cluster-yes

# 输出示例
# >>> Performing hash slots allocation on 6 nodes...
# >>> Using 3 masters:
# 192.168.1.1:7000
# 192.168.1.2:7001
# 192.168.1.3:7002
# >>> Adding replica 192.168.1.4:7003 to 192.168.1.1:7000
# >>> Adding replica 192.168.1.5:7004 to 192.168.1.2:7001
# >>> Adding replica 192.168.1.6:7005 to 192.168.1.3:7002
# >>> Nodes created as: 3 Masters, 3 Slaves
# [OK] All nodes agree about slots configuration

6.2 检查集群

# 检查集群状态
redis-cli --cluster check 192.168.1.1:7000

# 输出示例
# 192.168.1.1:7000 (0001) -> 0-5460
# 192.168.1.2:7001 (0002) -> 5461-10922
# 192.168.1.3:7002 (0003) -> 10923-16383
# [OK] All nodes agree about slots configuration
# [OK] All 16384 slots covered

6.3 添加节点

# 1. 启动新节点
redis-server /etc/redis/7006.conf

# 2. 添加到集群(作为从节点)
redis-cli --cluster add-node \
  192.168.1.7:7006 \
  192.168.1.1:7000 \
  --cluster-slave

# 3. 重新分片(如果需要)
redis-cli --cluster reshard \
  192.168.1.1:7000

6.4 删除节点

# 1. 迁移槽位
redis-cli --cluster reshard \
  192.168.1.1:7000

# 2. 删除节点
redis-cli --cluster del-node \
  192.168.1.1:7000 \
  <node-id>

# 3. 删除从节点
redis-cli --cluster del-node \
  192.168.1.1:7000 \
  <slave-node-id>

七、监控与维护

7.1 集群信息

# 集群信息
CLUSTER INFO

# 输出示例
# cluster_state:ok
# cluster_slots_assigned:16384
# cluster_slots_ok:16384
# cluster_slots_pfail:0
# cluster_slots_fail:0
# cluster_known_nodes:6
# cluster_size:3

7.2 节点信息

# 节点列表
CLUSTER NODES

# 输出示例
# 0001 192.168.1.1:7000@17000 myself,master - 0 0 1 connected 0-5460
# 0002 192.168.1.2:7001@17001 master - 0 1640000000000 2 connected 5461-10922
# 0003 192.168.1.3:7002@17002 master - 0 1640000000000 3 connected 10923-16383
# 0004 192.168.1.4:7003@17003 slave 0001 0 1640000000000 4 connected
# 0005 192.168.1.5:7004@17004 slave 0002 0 1640000000000 5 connected
# 0006 192.168.1.6:7005@17005 slave 0003 0 1640000000000 6 connected

7.3 槽位信息

# 槽位状态
CLUSTER SLOTS

# 输出示例
# 1) 1) (integer) 0
#    2) (integer) 5460
#    3) 1) "192.168.1.1"
#       2) (integer) 7000
#       3) "0001"
#    4) 1) "192.168.1.4"
#       2) (integer) 7003
#       3) "0004"

八、最佳实践

8.1 部署建议

推荐配置:
- 至少 3 个主节点
- 每个主节点 1-2 个从节点
- 节点部署在不同机器
- 跨机房部署(容灾)

8.2 配置优化

# cluster.conf
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-replica-validity-factor 10
cluster-migration-barrier 1
cluster-require-full-coverage yes

8.3 监控指标

指标告警阈值说明
cluster_state!= ok集群状态异常
cluster_slots_fail> 0槽位故障
cluster_known_nodes< 6节点数不足

8.4 故障处理

# 1. 检查集群状态
redis-cli --cluster check 192.168.1.1:7000

# 2. 修复故障
redis-cli --cluster fix 192.168.1.1:7000

# 3. 重新分片
redis-cli --cluster reshard 192.168.1.1:7000

# 4. 故障转移
redis-cli --cluster failover 192.168.1.1:7000

九、常见问题

Q1: Cluster vs Sentinel?

Cluster:
- 分布式,自动分片
- 水平扩展
- 适合大数据量

Sentinel:
- 高可用,手动分片
- 主从复制
- 适合小数据量

选择建议:
- 数据量 > 单节点容量 → Cluster
- 高可用要求 → Sentinel

Q2: 槽位迁移慢?

# 原因:数据量大
# 解决:
# 1. 分批迁移
redis-cli --cluster reshard --cluster-pipeline 100

# 2. 低峰期迁移
# 3. 监控进度

Q3: 客户端连接失败?

# 检查集群状态
CLUSTER INFO

# 检查槽位覆盖
CLUSTER SLOTS

# 检查网络连通性
telnet 192.168.1.1 7000

Q4: 脑裂问题?

原因:网络分区
解决:
1. cluster-require-full-coverage yes
2. 配置合理的 cluster-node-timeout
3. 使用网络分区检测

总结

Redis Cluster 核心要点:

特性说明
分片16384 个槽位
协议Gossip 协议
故障转移自动选举
扩展水平扩展
路由重定向机制

最佳实践

  1. 至少 3 主 3 从
  2. 使用哈希标签保证数据局部性
  3. 配置合理的超时时间
  4. 监控集群状态
  5. 定期备份数据

掌握 Cluster,构建可扩展的 Redis 架构!

参考资料


分享这篇文章到:

上一篇文章
RocketMQ EventBridge 事件驱动架构实战
下一篇文章
Redis 消息队列实现方案