Redis Cluster架构与数据分片原理
Redis Cluster是Redis官方提供的分布式方案,通过数据分片实现横向扩展。集群将所有数据划分为16384个槽位(hash slot),每个节点负责一部分槽位。键值对根据CRC16算法计算哈希值,对16384取模后确定所属槽位,再路由到对应节点。
槽位是Redis Cluster数据分布的基本单位。集群最少需要3主3从共6个节点,3个主节点分别负责约5461、5462、5461个槽位。节点间通过Gossip协议通信,维护集群拓扑信息、槽位分配表和节点状态。客户端连接任意节点执行命令时,如果键不在该节点负责的槽位范围内,节点返回MOVED重定向响应,引导客户端到正确节点。
Redis Cluster集群搭建与初始化配置
使用redis-cli创建集群是最快的方式。准备6个Redis实例,配置文件中开启集群模式:
# redis-7000.conf ~ redis-7005.conf
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
appendonly yes
appendfilename "appendonly-7000.aof"
dir /data/redis/7000
logfile /var/log/redis/redis-7000.log
# 绑定地址,确保节点间网络互通
bind 0.0.0.0
protected-mode no
# 开启AOF持久化
appendfsync everysec
启动6个Redis实例后,使用redis-cli创建集群:
# 启动6个Redis实例
redis-server redis-7000.conf
redis-server redis-7001.conf
redis-server redis-7002.conf
redis-server redis-7003.conf
redis-server redis-7004.conf
redis-server redis-7005.conf
# 创建集群:3主3从,自动分配槽位
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1
# 验证集群状态
redis-cli -p 7000 cluster info
redis-cli -p 7000 cluster nodes
--cluster-replicas 1表示每个主节点分配1个从节点。集群创建完成后,查看节点和槽位分配:
# 查看槽位分配
$ redis-cli -p 7000 cluster nodes
# 输出示例:
# 7000: master, slots 0-5460
# 7001: master, slots 5461-10922
# 7002: master, slots 10923-16383
# 7003: slave of 7000
# 7004: slave of 7001
# 7005: slave of 7002
槽位手动分配与集群扩缩容操作
集群创建时槽位自动均匀分配,但运维中可能需要手动调整。集群扩容添加新节点时,需要从现有节点迁移部分槽位到新节点:
# 添加新主节点到集群
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000
# 新节点7006加入集群但未分配槽位
# 从7000迁移4096个槽位到7006
redis-cli --cluster reshard 127.0.0.1:7000 --cluster-from 127.0.0.1:7000 --cluster-to 127.0.0.1:7006 --cluster-slots 4096 --cluster-yes
# 为新主节点7006添加从节点7007
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000 --cluster-slave --cluster-master-id <7006的node-id>
# 验证槽位分布
redis-cli -p 7000 cluster slots
集群缩容移除节点的操作是扩容的逆过程:先将待移除节点的槽位迁移到其他节点,再从集群中移除节点:
# 将7006的槽位迁移到7000和7001
redis-cli --cluster reshard 127.0.0.1:7000 --cluster-from 127.0.0.1:7006 --cluster-to 127.0.0.1:7000 --cluster-slots 4096 --cluster-yes
# 移除从节点7007
redis-cli --cluster del-node 127.0.0.1:7000 <7007的node-id>
# 移除主节点7006(槽位已全部迁出)
redis-cli --cluster del-node 127.0.0.1:7000 <7006的node-id>
故障检测与自动故障转移机制
Redis Cluster通过Gossip协议实现故障检测。节点间定时发送PING/PONG消息,超时未收到PONG响应的节点被标记为PFAIL(疑似故障)。超过半数主节点报告某节点PFAIL时,该节点被标记为FAIL,触发故障转移。
故障转移流程:从节点发现主节点FAIL后,发起选举请求,获得半数以上主节点投票后升级为新主节点,接管原主节点的槽位和数据。配置参数影响故障转移速度:
# 关键配置参数
cluster-node-timeout 5000 # 节点超时时间(ms),超过此时间判定为PFAIL
cluster-replica-validity-factor 10 # 从节点数据落后超过该值*timeout则不参与选举
cluster-migration-barrier 1 # 迁移屏障,主节点最少保留的从节点数
cluster-require-full-coverage yes # 槽位未全覆盖时是否拒绝服务
手动触发故障转移的场景:主节点需要维护时,执行手动故障转移让从节点接管,避免服务中断:
# 在从节点上执行手动故障转移
redis-cli -p 7003 cluster failover
# 强制故障转移(忽略主节点验证)
redis-cli -p 7003 cluster failover FORCE
# 接管模式(直接成为主节点,不复制主节点数据)
redis-cli -p 7003 cluster failover TAKEOVER
客户端连接与MOVED重定向处理
Redis Cluster客户端需要处理MOVED重定向。主流客户端库(Lettuce、Jedis、go-redis)已内置集群支持,自动缓存槽位映射表并处理重定向。Java Lettuce客户端配置:
// Spring Boot 中配置 Redis Cluster
@Configuration
public class RedisClusterConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisClusterConfiguration config = new RedisClusterConfiguration();
config.clusterNode("127.0.0.1", 7000);
config.clusterNode("127.0.0.1", 7001);
config.clusterNode("127.0.0.1", 7002);
config.setMaxRedirects(5); // 最大重定向次数
config.setTimeout(3000); // 命令超时
LettuceClientConfiguration clientConfig = LettuceClientConfiguration
.builder()
.commandTimeout(Duration.ofSeconds(3))
.build();
return new LettuceConnectionFactory(config, clientConfig);
}
@Bean
public RedisTemplate<String, String> redisTemplate(
RedisConnectionFactory factory) {
RedisTemplate<String, String> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
return template;
}
}
批量操作在集群模式下的限制:单条命令涉及多个键时,这些键必须位于同一槽位,否则返回CROSSSLOT错误。使用Hash Tag确保相关键分配到同一槽位:
# Hash Tag: 大括号内的内容参与CRC16计算
SET {user:1000}:profile "data"
SET {user:1000}:settings "config"
# 两个键的Hash Tag都是"user:1000",分配到同一槽位
# 批量操作同槽位键
MGET {user:1000}:profile {user:1000}:settings # 正常执行
MGET user:1000:profile user:2000:profile # CROSSSLOT错误
集群监控与运维注意事项
Redis Cluster的监控需关注槽位覆盖率、节点状态、主从同步延迟等指标。常用监控命令:
# 检查集群健康状态
redis-cli --cluster check 127.0.0.1:7000
# 查看集群信息
redis-cli -p 7000 cluster info | grep -E "cluster_state|cluster_slots|cluster_known_nodes"
# 查看主从同步延迟
redis-cli -p 7003 info replication | grep -E "master_link_status|master_last_io_seconds_ago"
# 查看各节点内存使用
for port in 7000 7001 7002 7003 7004 7005; do
echo "Node $port:"
redis-cli -p $port info memory | grep used_memory_human
done
运维中需注意:cluster-require-full-coverage yes时,任意槽位节点故障且无从节点接管,整个集群拒绝服务。对可用性要求高的场景可设为no,允许部分槽位不可用时其他槽位继续服务。集群不支持跨槽位事务和Lua脚本(除非使用Hash Tag确保所有键在同一槽位)。大key删除使用UNLINK替代DEL避免阻塞。定期执行--cluster fix修复槽位异常。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/rediscluster-ji-qun-cao-wei-fen-pei-ji-zhi-yu-gu-zhang/