Redis Cluster详解

Redis Cluster介绍

通过深入理解Redis哨兵模式我们知道哨兵模式在主从复制模式的基础上实现了自动故障转移,提高了系统的高可用性。然而,它仍然无法实现数据分片。如果需要实现数据分片和负载均衡,可以考虑使用Redis Cluster模式。

Cluster 即 集群模式,类似MySQL,Redis 集群也是一种分布式数据库方案,集群通过分片(sharding)模式来对数据进行管理,并具备分片间数据复制、故障转移和流量调度的能力。

Redis Cluster 实现原理

数据分片

Redis Cluster 采用哈希槽(Hash Slot),来处理数据和实例之间的映射关系。在 Redis Cluster 方案中,一个切片集群共有 16384 个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中。具体的映射过程分为两大步:首先根据键值对的 key,按照CRC16 算法计算一个 16 bit 的值;然后,再用这个 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。

我们在部署 Redis Cluster 时,可以使用 cluster create 命令创建集群,此时,Redis 会自动把这些槽平均分布在集群实例上。例如,如果集群中有 N 个实例,那么,每个实例上的槽个数为 16384/N 个。

客户端访问集群过程

正常情况访问集群过程

在定位键值对数据时,它所处的哈希槽是可以通过计算得到的,这个计算可以在客户端发送请求时来执行。但是如何知道哈希槽分布在哪个实例上呢?

一般来说,客户端和集群实例建立连接后,实例就会把哈希槽的分配信息发给客户端。但是,在集群刚刚创建的时候,每个实例只知道自己被分配了哪些哈希槽,是不知道其他实例拥有的哈希槽信息的。那么,客户端为什么可以在访问任何一个实例时,都能获得所有的哈希槽信息呢?这是因为,Redis 实例会把自己的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散。当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了。客户端收到哈希槽信息后,会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给相应的实例发送请求了。

故障转移时访问集群过程

但是,在集群中,实例和哈希槽的对应关系并不是一成不变的,最常见的变化有两个:

  • 在集群中,实例有新增或删除,Redis 需要重新分配哈希槽;
  • 为了负载均衡,Redis 需要把哈希槽在所有实例上重新分布一遍。

此时,实例之间还可以通过相互传递消息,获得最新的哈希槽分配信息,但是,客户端是无法主动感知这些变化的。这就会导致,它缓存的分配信息和最新的分配信息就不一致了,那该怎么办呢?

Redis Cluster 方案提供了一种重定向机制,所谓的"重定向",就是指,客户端给一个实例发送数据读写操作时,这个实例上并没有相应的数据,客户端要再给一个新实例发送操作命令。那客户端又是怎么知道重定向时的新实例的访问地址呢?当客户端把一个键值对的操作请求发给一个实例时,如果这个实例上并没有这个键值对映射的哈希槽,那么,这个实例就会给客户端返回下面的 MOVED 命令响应结果,这个结果中就包含了新实例的访问地址。

上图可以看到,由于负载均衡,Slot 1 中的数据已经从node1 迁移到了node3,但是,客户端缓存仍然记录着Slot 1node1的信息,所以会给node1发送命令。node1 给客户端返回一条 MOVED 命令,把 Slot 1 的最新位置返回给客户端,客户端就会再次向node3发送请求,同时还会更新本地缓存,把 Slot 1 与实例的对应关系更新过来。

上面是slot 1的数据全部迁移到node3时得过程,如果slot 1的数据比较多,迁移了一半到node3,这时返回结果会收到一个 ASK 命令。这个结果中的 ASK 命令就表示,客户端请求的键值对所在的哈希槽,在 node3 这个实例上,但是这个哈希槽正在迁移。此时,客户端需要先给 node3 这个实例发送一个 ASKING 命令。这个命令的意思是,让这个实例允许执行客户端接下来发送的命令。然后,客户端再向这个实例发送 GET 命令,以读取数据。

故障恢复

当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master可能会有多个slave。Failover的过程需要经过类Raft协议的过程在整个集群内达到一致, 其过程如下:

  • slave发现自己的master变为FAIL
  • 将自己记录的集群currentEpoch加1,并广播Failover Request信息
  • 其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个epoch只发送一次ack
  • 尝试failover的slave收集FAILOVER_AUTH_ACK
  • 超过半数后变成新Master
  • 广播Pong通知其他集群节点

Gossip 协议

Gossip 协议是一种去中心化的信息传播协议,它被用于分布式系统中节点之间的通信,以便在整个系统中传播信息。在 Redis 中,Gossip 协议被用于 Redis Cluster 中的节点之间的集群管理。

Gossip算法又被称为反熵(Anti-Entropy),熵是物理学上的一个概念,代表杂乱无章,而反熵就是在杂乱无章中寻求一致,这充分说明了Gossip的特点:在一个有界网络中,每个节点都随机地与其他节点通信,经过一番杂乱无章的通信,最终所有节点的状态都会达成一致。每个节点可能知道所有其他节点,也可能仅知道几个邻居节点,只要这些节可以通过网络连通,最终他们的状态都是一致的,当然这也是疫情传播的特点。

以下是 Redis Gossip 协议的工作流程:

工作流程

  1. 节点定期通信: 每个节点定期向其他节点发送自身的信息,包括节点的 ID、IP 地址、端口号、槽的分配情况等。

  2. 随机选择目标节点: 在每次通信时,节点随机选择一些其他节点作为目标进行通信。这有助于降低通信的复杂性,并确保信息在整个集群中传播。

  3. 信息交换: 节点之间交换信息,将自身的状态信息传播给其他节点。接收到的信息被用于更新节点自身的状态,以确保集群中所有节点的信息是最新的。

  4. 状态同步: 通过 Gossip 协议,集群中的节点能够及时同步各自的状态,包括节点的存活状态、槽的分配等。这有助于集群能够动态地适应节点的加入、退出以及槽的变化等情况。

总结

Cluster在提供高可用性的同时,实现了数据分片和负载均衡,适用于大规模数据存储和高性能要求的场景。

相关推荐
王佑辉2 分钟前
【redis】redis缓存和数据库保证一致性的方案
redis·面试
杜杜的man39 分钟前
【go从零单排】go中的结构体struct和method
开发语言·后端·golang
幼儿园老大*40 分钟前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
llllinuuu42 分钟前
Go语言结构体、方法与接口
开发语言·后端·golang
Karoku06642 分钟前
【企业级分布式系统】Zabbix监控系统与部署安装
运维·服务器·数据库·redis·mysql·zabbix
cookies_s_s42 分钟前
Golang--协程和管道
开发语言·后端·golang
为什么这亚子1 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
gorgor在码农1 小时前
Redis 热key总结
java·redis·热key
想进大厂的小王1 小时前
项目架构介绍以及Spring cloud、redis、mq 等组件的基本认识
redis·分布式·后端·spring cloud·微服务·架构
Java 第一深情1 小时前
高性能分布式缓存Redis-数据管理与性能提升之道
redis·分布式·缓存