参考:What are Redis Cluster and How to setup Redis Cluster locally ? | by Rajat Pachauri | Medium
Redis Cluster 的工作原理是将数据分布在多个节点上,同时确保高可用性和容错能力。以下是 Redis Cluster 运行方式的简要概述:
通过在多个节点之间分配数据和负载,Redis Cluster 可实现水平扩展并提高性能。它提供容错能力,因为副本可以接管发生故障的主节点的角色。集群还平衡哈希槽的分布,并确保每个节点负责一部分槽,从而使集群能够高效扩展。
Redis cluster 是一种去中心化的 Redis 分布式集群解决方案。通过数据自动分片分配到多个主节点之间(每个主节点 都是 主从搭配)、自动故障检测,实现了高可用和高性能。
Redis Cluster 具有以下几个特点:
可扩展性(横向扩展):通过向集群添加更多节点,可以增加 Redis 系统的整体容量和吞吐量。
扩展可以分为Las:垂直扩展(scale up)、水平扩展(scale out)
- 垂直拓展:升级单个 Redis 的硬件配置,比如增加内存容量、磁盘容量、使用更强大的 CPU。【部署简单,但是当数据量大并且使用 RDB 实现持久化,会造成阻塞导致响应慢。另外受限于硬件和成本,拓展内存的成本太大,比如拓展到 1T 内存】
- 水平拓展:横向增加 Redis 实例个数,每个节点负责一部分数据。【便于拓展,同时不需要担心单个实例的硬件和成本的限制。但是,切片集群会涉及多个实例的分布式管理问题,需要解决如何将数据合理分布到不同实例,同时还要让客户端能正确访问到实例上的数据】
高可用性:主从复制和故障转移机制提高了集群的可靠性。
高并发应用:需要处理大量并发请求的场景,如电商、社交平台。
数据分片需求:需要水平扩展存储容量的场景。
高可用性需求:需要提供数据冗余和自动故障恢复的应用。
优点:
缺点:
Redis 的数据分片(sharding)是将 Redis数据集 分割为多个部分,分别存储在不同的 Redis节点上的技术。通过数据分片技术可以将 一个单独的 Redis数据库扩展到多个物理机器上,从而提高 Redis集群的性能、扩展性。
当 16384 个槽都分配完全,Redis 集群才能正常工作。
在Redis的Cluster集群模式中,使用**哈希槽(hash slot)**的方式来进行数据分片,将整个数据集划分为多个槽,每个槽分配给一个节点(这里的节点是由 主、从模式构成的)。
客户端访问数据时,先计算出数据对应的槽,然后直接连接到该槽所在的节点进行操作。具体的:
如何分片的:Redis集群模式中,使用哈希槽(hash slot)的方式将数据分片。
具体流程为:假设要查询 键为key1
的数据
key1
进行哈希计算(使用CRC16算法计算的结果就是 key1的哈希值),假设得到哈希值为12345。key1
映射到哈希槽12345,由节点B负责。Redis Cluster中的数据分片具有以下特点:
在 Redis Cluster 中,节点分为两种类型:主节点(Master)和从节点(Slave)。
上面数据分片时所说的 会将数据分片到不同的节点上。这里的节点就是由 一个 master 和 1或多个slave 组成的。
注意:关于Redis Cluster 中,从节点是否可以支持 读服务?
默认情况下从节点不负责处理读服务,所有的写请求和读请求都会被路由到主节点。
然而,Redis提供了READONLY
命令,允许客户端将读请求路由到从节点。
但是,这种做法需要谨慎,因为它可能会引入一些问题,比如:
- 延迟读取:从节点可能不会立即反映出主节点的最新数据变化,因为数据复制是异步进行的。
- 一致性风险:如果主从节点之间的网络延迟较大,从节点可能会提供过时的数据
Redis 的集群节点之间的通信采取 gossip 协议进行通信,在 redis cluster 架构下,每个 redis 要放开两个端口号,比如一个是 6379,另外一个就是 加10000 的端口号,比如 16379,16379 端口号是用来进行节点间通信的。
Gossip protocol
也叫 Epidemic Protocol
(流行病协议),实际上它还有很多别名,比如:“流言算法”、“疫情传播算法”等。
Gossip protocol (流言协议),是利用一种 随机、带有传染性的方式,将信息传播到整个网络中,并在一定时间内,使得系统内所有节点数据一致。
Gossip协议的执行过程简答描述为:Gossip 过程是由种子节点发起,当一个种子节点有状态需要更新到网络中的其他节点时,它会随机的选择周围几个节点散播消息,收到消息的节点也会重复该过程,直至最终网络中所有的节点都收到了消息。这个过程可能需要一定的时间,由于不能保证某个时刻所有节点都收到消息,但是理论上最终所有节点都会收到消息,因此它是一个最终一致性协议。
优点:
缺点:
Redis Cluster 是在 3.0 版本引入集群功能。为了让让集群中的每个实例都知道其他所有实例的状态信息,Redis 集群规定各个实例之间按照 Gossip 协议来通信传递信息。
上图展示了主从架构的 Redis Cluster 示意图,其中:
Redis Cluster 中的每个节点都维护一份自己视角下的当前整个集群的状态信息(元数据信息),主要包括:
知道了 节点之间是通过 Gossip 协议进行消息的发送,现在来看看它们之间发送消息的类型。较为重要的如下所示:
消息 | 说明 |
---|---|
meet | 通过「cluster meet ip port 」命令,已有集群的节点会向新的节点发送邀请,加入现有集群,然后新节点就会开始与其他节点进行通信 |
ping | 节点按照配置的时间间隔向集群中其他节点发送 ping 消息,消息中带有自己的状态,还有自己维护的集群元数据,和部分其他节点的元数据 |
pong | 返回ping和meet,包含自己的状态和其他信息,也可以用于信息广播和更新 |
fail | 某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了 |
Redis Cluster 中的节点都会定时地向其他节点发送 PING
消息,来交换各个节点状态信息,检查各个节点状态,包括在线状态、疑似下线状态 PFAIL 和已下线状态 FAIL。
Redis 集群的定时 PING/PONG
的工作原理可以概括成两点:
一是,每个实例之间会按照一定的频率,从集群中随机挑选一些实例,把 PING 消息发送给挑选出来的实例,用来检测这些实例是否在线,并交换彼此的状态信息。
例自身的状态信息、部分其它实例的状态信息,以及 Slot 映射表。
二是,一个实例在接收到 PING 消息后,会给发送 PING 消息的实例,发送一个 PONG 消息。PONG 消息包含的内容和 PING 消息一样。
Redis Cluster保证高可用(High Availability)主要还是依靠:故障检测与故障转移。
故障检测的机制如下(通过Gossip协议发送消息进行检测):
关于节点参与情况说明:
- 主观下线:每个节点(包括主节点和从节点)都会检测其他节点的状态。如果检测到某个节点不可用,会将其标记为主观下线(PFAIL)。
- 客观下线:主节点之间会交换彼此的主观下线状态,如果超过半数的主节点都认为某个节点不可用,则该节点会被标记为客观下线(FAIL)。
疑似下线:Redis Cluster 中的节点会定期检查已经发送 PING
消息(即上述的心跳机制
)的接收方节点是否在规定时间 ( cluster-node-timeout
) 内返回了 PONG
消息,如果没有则会将其标记为疑似下线状态(possible fail,PFAIL)。
客观下线:当一个节点将另一个节点标记为"疑似失败"后,它会通过Gossip协议将这个信息传播给其他节点。如果一个节点从大多数主节点那里都收到了某个节点的"疑似失败"信息,那么这个节点将被标记为"客观失败"(FAIL)。并将该节点 客观下线的信息,发送给所有节点。
这时,集群会触发故障转移流程,从失败节点的从节点中选举一个新的主节点。
节点参与情况说明:
从节点投票:当一个主节点被标记为客观下线后,它的从节点会发起故障转移过程。故障转移请求会被发送到其他主节点,以请求授权进行故障转移。
授权投票:其他主节点会对故障转移请求进行投票,同意票数超过半数后,候选从节点会被提升为新的主节点。
当Redis Cluster中的主节点被标记为客观下线(FAIL)时,会触发故障转移(failover)流程。故障转移(failover)是指当主节点不可用时,从节点自动提升为新的主节点,以保证集群的高可用性。故障转移的流程包括以下几个步骤:
slave-priority
参数)、复制偏移量(replication offset)等因素进行投票。当客户端第一次连接到 Redis Cluster 时,它会连接到集群中的一个节点(通常是配置好的一个或多个节点之一)。这个节点会提供当前集群的拓扑结构,包括每个节点负责的哈希槽范围。
但是,后续如果节点进行扩容、缩容之后,每个节点的哈希槽范围会改变。此时,客户端是无法感知的。
之后通过重定向一次之后,客户端会根据节点返回 MOVED 或 ASK 错误,客户端更新其拓扑结构,并将请求重发到新的节点。
在此之后,客户端维护的拓扑结构更新到最新的状态。
一句话:在 Redis Cluster 中,每个键通过哈希槽分配到不同的节点。如果你向某个节点写入数据,但该数据应该存储在另一个节点上,Redis Cluster 会返回重定向指令,告诉你应该访问哪个节点。这确保了数据的分布和存取的正确性。
MOVED:当客户端请求的键在另一个节点上时,节点会返回MOVED
指令。该指令包含目标节点的地址。客户端收到MOVED
指令后,会重新请求目标节点。
ASK:在数据迁移过程中,如果某个键正在从一个节点迁移到另一个节点,当客户端请求这个键时,节点会返回ASK
指令。ASK
指令告诉客户端临时访问新的目标节点,通常在数据迁移完成之前。
重定向过程的详细步骤:
MOVED
指令:节点A返回一个MOVED
指令,包含目标节点B的地址。注意:重定向MOVED
类型,客户端还会更新本地缓存,将该 slot 与 Redis 实例对应关系更新正确。
ASK
指令迁移过程中的请求:如果某个键正在从节点A迁移到节点B,客户端请求这个键时,节点A会返回一个ASK
指令。
临时访问:客户端向节点B发送请求,并在请求前发送ASKING
指令,表明这是一次临时访问。
数据迁移完成后:客户端可以正常访问节点B,不再需要发送ASKING
指令。
注意:ASK 指令并不会更新客户端缓存的哈希槽分配信息。
缩容流程:
扩容流程:
reshard
命令自动进行。步骤如下:
主从节点建立关系
:
这里的复制请求(PSYNC)主要使用的是 Redis 协议(REdis Serialization Protocol, RESP)。
RESP(Redis Serialization Protocol) 是 Redis 的内部协议,用于客户端和服务器之间的通信,也用于 Redis 集群节点之间的通信。该协议简单、高效且便于实现。
复制请求(PSYNC)的流程:
读取 replicaof
指令,获取主节点信息:
从节点的配置文件中会包含一条 replicaof
指令,用于指定它要跟随的主节点的 IP 地址和端口。例如:
port 7001
cluster-enabled yes
cluster-config-file nodes-7001.conf
cluster-node-timeout 5000
appendonly yes
replicaof 127.0.0.1 7000
启动从节点,当从节点启动时,它会读取配置文件并解析 replicaof
指令。
连接主节点:从节点根据 replicaof
指令中指定的 IP 地址和端口,尝试连接主节点。
发送 PSYNC
命令:一旦连接成功,从节点会向主节点发送 PSYNC
命令以请求复制。PSYNC
命令用于部分重同步或全量重同步。
PSYNC <replicationid> <offset>
主节点响: 主节点接收到 PSYNC
命令后,就可以开始数据复制同步了。