Skip to content

1. 分片集群

1.1 概念

Redis 分片集群(Cluster)是一种分布式解决方案,它通过将数据分散存储到多个节点上来实现水平扩展。每个节点只负责一部分数据,客户端根据键值计算出应该访问哪个节点,从而实现高效的数据读写操作。相比主从复制模式,集群提供了更好的可扩展性和容错能力。

🎯Redis 分片集群中有哪些节点角色

Master Node(主节点):存储实际数据,处理读写请求。

Replica Node(从节点):每个主节点可以有一个或多个从节点,用于备份数据,在主节点故障时进行故障转移。

无专用协调节点:所有节点都是平等的,不存在专门的管理节点。

🎯Redis 分片集群中数据和实例如何对应

Redis Cluster采用哈希槽实现数据与实例之间的映射。整个键空间被划分为 16384个槽位,将key通过CRC16算法计算为一个16bit的值,通过16bit的值对16384取模,得到0~16383的模,确定该键属于哪个槽位。然后这些槽会分配在不同的实例上,相当于就是通过key找到槽,再找到对应的实例。

客户端会定期向集群发起 CLUSTER SLOTS 命令,获取当前各槽位对应的节点信息。根据槽位编号和节点映射关系,直接连接到正确的节点。

🎯Redis 集群如何“通知”客户端

Redis 集群没有中心控制器,也不支持消息推送。它依赖于:

  • 客户端维护本地的集群拓扑缓存(节点 → 槽位映射)
  • 服务器返回特殊错误码,提示客户端“去别处找”
  • 客户端自动更新缓存并重试请求

🎯哈希槽如何分配到不同实例

  1. 方法一:在部署Redis Cluster 方案时,可以使用 cluster create 命令创建集群,此时,Redis 会自动把这些槽平均分布在集群实例上;
  2. 可以使用 cluster meet 命令手动建立实例间的连接,形成集群,再使用 cluster addslots 命令,指定每个实例上的哈希槽个数。

🎯实例新增和删除

在集群中,实例和哈希槽的对应关系并不是一成不变的,实例新增或删除,redis需要重新分配哈希槽,此时客户端无法主动感知这些变化。

Redis提供了重定向机制来解决这个问题,例如哈希槽slot2的数据全部从实例1迁移到实例2了,这时候客户端对某个key进行操作,定位到哈希槽slot2,由于客户端无法感知这时候命令还是会发送到实例1,这时候实例1就会给客户端返回下面的结果,(error) MOVED 2 172.16.19.5:6379,告诉客户端哈希槽2实际上在实例2(172.16.19.5:6379)上面。客户端会再次向实例2发送请求,同时还更新本地缓存,把slot2和实例的对应关系更新过来。

在实际应用中,哈希槽slot2的数据可能非常多,就会出现key1和key2迁移到了实例2,key3和key4还在实例1。当客户端请求实例1的key2的时候,就会收到实例 1 返回的 ASK 命令。ASK 命令表示两层含义:第一,表明 Slot2 数据还在迁移中;第二,ASK 命令把客户端所请求数据的最新实例地址返回给客户端,此时客户端需要给实例 2 发送 ASKING 命令,然后再发送操作命令。如果客户端请求实例1的key3,由于key3还在实例1,会返回value信息,而不是ASK。

和 MOVED 命令不同,ASK 命令并不会更新客户端缓存的哈希槽分配信息。如果客户端再次请求 Slot 2 中的数据,它还是会给实例 1 发送请求。这也就是说,ASK 命令的作用只是让客户端能给新实例发送一次请求,而不像 MOVED 命令那样,会更改本地缓存,让后续所有命令都发往新实例。

  • 主从故障切换、新增节点、删除节点,基本都是返回MOVE;
  • 特殊情况,槽正在迁移中,会返回ASK。

🎯在集群中如何保证Lua脚本的多个key落在同一个redis节点上

哈希标签是 Redis 集群中实现“数据共槽”(key co-location)的核心机制。它通过 {} 指定参与哈希计算的部分字符串,使得多个 key 可以强制分布到同一个哈希槽中,从而支持多 key 操作,同时为业务数据的局部性优化提供了强大支持。

properties
SET {user1000}:profile "Alice"
SET {user1000}:orders  "3"
SET {user1000}:session "abc123"

这三个 key 的哈希标签都是 user1000,因此它们会被映射到同一个哈希槽,无论集群中有多少个主节点。

🎯故障检测与转移

Redis 集群采用了一种去中心化的故障检测机制:

  • PING-PONG 心跳检测:节点间定期交换心跳包,判断对方是否存活。
  • 主观下线(SDOWN):如果某节点未能及时响应心跳,则标记为 SDOWN。
  • 客观下线(ODOWN):多数节点同意某节点不可达后,将其标记为 ODOWN。
  • 故障转移:一旦主节点被标记为 ODOWN,其从节点之一会被提升为主节点,继续服务。

从节点选举与提升:

  • 集群会选择一个从节点作为新主节点的候选者。
  • 候选者需要满足一定的条件(如优先级、复制偏移量等)。
  • 被选中的从节点将执行 REPLICAOF NO ONE 命令,取消与旧主的关系,成为新的主节点。

更新集群状态:

  • 新主节点接管旧主节点负责的所有哈希槽。
  • 其他从节点开始复制新的主节点。
  • 客户端可以通过查询集群状态获取最新的主节点信息。

因此,在 Redis 分片集群中,不再使用哨兵机制来进行主从切换,而是依赖于集群自身的故障检测和自动故障转移能力。

1.2 集群搭建(windows)

  1. 首先是准备6个独立的redis服务,端口号7000~7005,下面仅展示端口7000的配置信息,其他的以此类推就好,然后分别启动这6个redis服务。
java
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 15000
dir "D:\\CodeSoft\\cluster-redis\\redis-7000"
  1. 创建集群服务,由于我是redis5.x版本,不需要依赖Ruby,可以直接执行命令创建,这个命令代表创建三主三从的集群。执行之后会弹出下面的图片,告诉我即将创建集群的主从信息,输入yes即可完成创建。
java
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

  1. 客户端连接集群
java
//连接集群,选取任何一个节点,带上-c
redis-cli -p 7000 -c
//查看集群信息
cluster info
//查看集群节点
cluster nodes
  1. 演示了把一个主节点进行手动故障,发现从节点可以自动变成主节点,但是各个redis服务会提示网络连接异常,因为它们一直在尝试连接这个故障的主节点。当我恢复主节点之后,这个主节点变成了从节点,也不再提示网络连接异常。

  1. 关闭集群,把集群中每个redis实例进行关闭,redis集群就关闭了。
  2. 再起启动集群,不需要执行创建命令,因为每个redis实例已经在配置文件保存了集群信息,单独启动每个redis实例,就可以完成集群的启动。使用集群客户端查看集群状态和节点信息即可。

1.3 SpringBoot整合Redis集群

在redis集群主节点发生故障的时候,完成主节点故障转移之后,springboot客户端是可以通过redis提供的重定向机制,重定向到操作的key对应的正确的redis实例。

java
spring:
  redis:
    timeout: 5000
    cluster:
      nodes: 127.0.0.1:7000,127.0.0.1:7001127.0.0.1:7002,127.0.0.1:7003,127.0.0.1:7004,127.0.0.1:7005

Released under the MIT License.