Redis Cluster 模式 的具体实施细节是什么样的?
概述
参考:What are Redis Cluster and How to setup Redis Cluster locally ? | by Rajat Pachauri | Medium
Redis Cluster 的工作原理是将数据分布在多个节点上,同时确保高可用性和容错能力。以下是 Redis Cluster 运行方式的简要概述:
- 节点发现:Redis 集群使用一种称为“gossip 协议”的概念进行节点发现。每个节点都会维护集群中其他节点的列表,并定期与一些随机选择的节点共享有关集群状态的信息。这有助于节点发现和加入集群。
- 数据分片:Redis Cluster 使用一致性哈希将数据划分为多个哈希槽。集群支持 16384 个哈希槽,每个键使用哈希函数映射到特定槽。哈希槽分布在集群中的节点上。
- 主-副本复制:Redis 集群遵循主-副本复制模型。每个哈希槽都与特定的主节点相关联,并且该槽中的数据被复制到一个或多个副本节点。副本提供冗余,并在主节点发生故障时充当故障转移节点。
- 客户端交互:客户端可以连接到 Redis 集群中的任何节点。当客户端发送与特定键相关的命令时,集群会使用该键的哈希槽来确定负责该槽的节点。然后使用 MOVED 或 ASK 重定向响应将客户端透明地重定向到适当的节点。
- 故障转移和高可用性:Redis 集群支持自动故障转移。当主节点发生故障时,其副本之一将自动升级为主节点,从而确保数据的持续可用性。集群使用共识协议来选举新的主节点。客户端通过重定向响应更新新的主节点信息。
- 集群配置:Redis 集群维护一个集群配置,其中包含有关节点、哈希槽和副本的信息。当节点加入或离开集群时,此配置会动态更新。集群节点交换消息以就集群配置达成共识并确保其一致性。
通过在多个节点之间分配数据和负载,Redis Cluster 可实现水平扩展并提高性能。它提供容错能力,因为副本可以接管发生故障的主节点的角色。集群还平衡哈希槽的分布,并确保每个节点负责一部分槽,从而使集群能够高效扩展。
Redis cluster 简介
Redis cluster 是一种去中心化的 Redis 分布式集群解决方案。通过数据自动分片分配到多个主节点之间(每个主节点 都是 主从搭配)、自动故障检测,实现了高可用和高性能。
特点
Redis Cluster 具有以下几个特点:
-
可扩展性(横向扩展):通过向集群添加更多节点,可以增加 Redis 系统的整体容量和吞吐量。
扩展可以分为Las:垂直扩展(scale up)、水平扩展(scale out)
- 垂直拓展:升级单个 Redis 的硬件配置,比如增加内存容量、磁盘容量、使用更强大的 CPU。【部署简单,但是当数据量大并且使用 RDB 实现持久化,会造成阻塞导致响应慢。另外受限于硬件和成本,拓展内存的成本太大,比如拓展到 1T 内存】
- 水平拓展:横向增加 Redis 实例个数,每个节点负责一部分数据。【便于拓展,同时不需要担心单个实例的硬件和成本的限制。但是,切片集群会涉及多个实例的分布式管理问题,需要解决如何将数据合理分布到不同实例,同时还要让客户端能正确访问到实例上的数据】
-
高可用性:主从复制和故障转移机制提高了集群的可靠性。
- 主从复制模式,从节点实时同步主节点的数据。这种结构不仅提高了数据的冗余性,还在主节点出现故障时提供了数据的可用性。
- 故障转移机制:当主节点不可用时,从节点可以自动提升为主节点。这种自动化的故障处理机制减少了人为干预的需求,确保了系统的持续可用性。
使用场景
高并发应用:需要处理大量并发请求的场景,如电商、社交平台。
数据分片需求:需要水平扩展存储容量的场景。
高可用性需求:需要提供数据冗余和自动故障恢复的应用。
优缺点
优点:
- 水平扩展:通过添加节点轻松扩展集群容量。
- 高可用性:主从复制和故障转移机制提高了集群的可靠性。
- 数据分布均衡:哈希槽机制确保数据在集群中均匀分布。
缺点:
- 复杂性增加:集群的配置和管理相较于单节点模式更加复杂。
- 数据一致性问题:可能出现部分数据不可用的情况,需要应用层处理。()
- 资源消耗:维护多个节点的状态需要额外的资源和网络通信。
Redis Cluster 实现原理
数据分片与哈希槽
Redis 的数据分片(sharding)是将 Redis数据集 分割为多个部分,分别存储在不同的 Redis节点上的技术。通过数据分片技术可以将 一个单独的 Redis数据库扩展到多个物理机器上,从而提高 Redis集群的性能、扩展性。
当 16384 个槽都分配完全,Redis 集群才能正常工作。
在Redis的Cluster集群模式中,使用**哈希槽(hash slot)**的方式来进行数据分片,将整个数据集划分为多个槽,每个槽分配给一个节点(这里的节点是由 主、从模式构成的)。
客户端如何访问/插入数据的?
客户端访问数据时,先计算出数据对应的槽,然后直接连接到该槽所在的节点进行操作。具体的:
如何分片的:Redis集群模式中,使用哈希槽(hash slot)的方式将数据分片。
- 首先,将数据集划分为多个槽,每个槽分配给一个节点。(一个节点会对应多个槽)
- 客户端访问数据时,先计算出数据对应的槽,然后连接到该槽所属的 Redis节点上,然后在该节点上访问对应数据。
具体流程为:假设要查询 键为key1的数据
- 对key1进行哈希计算(使用CRC16算法计算的结果就是 key1的哈希值),假设得到哈希值为12345。
- 对哈希值取模16384,结果为12345。
- key1映射到哈希槽12345,由节点B负责。
数据分片的作用
Redis Cluster中的数据分片具有以下特点:
- 提升性能和吞吐量:通过在多个节点上分散数据,可以并行处理更多的操作,从而提升整体的性能
和吞吐量。这在高流量场景下尤其重要,因为单个节点可能无法处理所有请求。
- 提高可扩展性:分片使得Redis可以水平扩展。可以通过添加更多节点扩展数据库的容量和处理能
力。
- 降低单个节点的内存和计算需求:每个节点只处理数据的一部分,这降低了单个节点的内存和计算需求。
- 避免单点故障:在没有分片的情况下,如果唯一的Redis服务器发生故障,整个服务可能会停止。
在分片的环境中,即使一个节点出现问题,其他节点仍然可以继续运行。
- 数据冗余和高可用性:在某些分片策略中,如Redis集群,每个分片的数据都可以在集群内的其他
节点上进行复制。这意味着即使一个节点失败,数据也不会丢失,从而提高了系统的可用性。
节点类型(主节点、从节点)
在 Redis Cluster 中,节点分为两种类型:主节点(Master)和从节点(Slave)。
上面数据分片时所说的 会将数据分片到不同的节点上。这里的节点就是由 一个 master 和 1或多个slave 组成的。
- 主节点:是数据的主要存储位置,负责处理与数据相关的所有操作,如读、写请求,数据分片等。
- 从节点:主要任务是复制主节点的数据。每个主节点可以有一个或多个从节点,从节点实时同步主节点的数据。这种设计保证了数据的冗余性和高可用性。
注意:关于Redis Cluster 中,从节点是否可以支持 读服务?
-
默认情况下从节点不负责处理读服务,所有的写请求和读请求都会被路由到主节点。
-
然而,Redis提供了READONLY命令,允许客户端将读请求路由到从节点。
但是,这种做法需要谨慎,因为它可能会引入一些问题,比如:
- 延迟读取:从节点可能不会立即反映出主节点的最新数据变化,因为数据复制是异步进行的。
- 一致性风险:如果主从节点之间的网络延迟较大,从节点可能会提供过时的数据
Redis Cluster 的通信协议:Gossip 协议
Redis 的集群节点之间的通信采取 gossip 协议进行通信,在 redis cluster 架构下,每个 redis 要放开两个端口号,比如一个是 6379,另外一个就是 加10000 的端口号,比如 16379,16379 端口号是用来进行节点间通信的。
Gossip protocol 也叫 Epidemic Protocol (流行病协议),实际上它还有很多别名,比如:“流言算法”、“疫情传播算法”等。
Gossip protocol (流言协议),是利用一种 随机、带有传染性的方式,将信息传播到整个网络中,并在一定时间内,使得系统内所有节点数据一致。
Gossip协议的执行过程简答描述为:Gossip 过程是由种子节点发起,当一个种子节点有状态需要更新到网络中的其他节点时,它会随机的选择周围几个节点散播消息,收到消息的节点也会重复该过程,直至最终网络中所有的节点都收到了消息。这个过程可能需要一定的时间,由于不能保证某个时刻所有节点都收到消息,但是理论上最终所有节点都会收到消息,因此它是一个最终一致性协议。
Gossip协议优缺点
优点:
- 扩展性 网络可以允许节点的任意增加和减少,新增加的节点的状态最终会与其他节点一致。
- 容错 网络中任何节点的宕机和重启都不会影响 Gossip 消息的传播,Gossip 协议具有天然的分布式系统容错特性。
- 去中心化 Gossip 协议不要求任何中心节点,所有节点都可以是对等的,任何一个节点无需知道整个网络状况,只要网络是连通的,任意一个节点就可以把消息散播到全网。
- 一致性收敛 Gossip 协议中的消息会以一传十、十传百一样的指数级速度在网络中快速传播,因此系统状态的不一致可以在很快的时间内收敛到一致。消息传播速度达到了 logN。
- 简单 Gossip 协议的过程极其简单,实现起来几乎没有太多复杂性。
缺点:
- 消息的延迟 由于 Gossip 协议中,节点只会随机向少数几个节点发送消息,消息最终是通过多个轮次的散播而到达全网的,因此使用 Gossip 协议会造成不可避免的消息延迟。不适合用在对实时性要求较高的场景下。
- 消息冗余 Gossip 协议规定,节点会定期随机选择周围节点发送消息,而收到消息的节点也会重复该步骤,因此就不可避免的存在消息重复发送给同一节点的情况,造成了消息的冗余,同时也增加了收到消息的节点的处理压力。而且,由于是定期发送,因此,即使收到了消息的节点还会反复收到重复消息,加重了消息的冗余。
Redis Cluster的Gossip机制
Redis Cluster 是在 3.0 版本引入集群功能。为了让让集群中的每个实例都知道其他所有实例的状态信息,Redis 集群规定各个实例之间按照 Gossip 协议来通信传递信息。
上图展示了主从架构的 Redis Cluster 示意图,其中:
- 实线表示节点间的主从复制关系,
- 虚线表示各个节点之间的 Gossip 通信。
Redis Cluster 中的每个节点都维护一份自己视角下的当前整个集群的状态信息(元数据信息),主要包括:
- 当前集群状态
- 集群中各节点所负责的 slots信息,及其migrate状态
- 集群中各节点的master-slave状态
- 集群中各节点的存活状态及怀疑Fail状态
Redis Cluster 的节点之间发送消息的类型
知道了 节点之间是通过 Gossip 协议进行消息的发送,现在来看看它们之间发送消息的类型。较为重要的如下所示:
消息 说明 meet 通过「cluster meet ip port」命令,已有集群的节点会向新的节点发送邀请,加入现有集群,然后新节点就会开始与其他节点进行通信 ping 节点按照配置的时间间隔向集群中其他节点发送 ping 消息,消息中带有自己的状态,还有自己维护的集群元数据,和部分其他节点的元数据 pong 返回ping和meet,包含自己的状态和其他信息,也可以用于信息广播和更新 fail 某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了 定时ping/pong消息(心跳机制)
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发送请求,如果键不在节点A的哈希槽范围内。
- 返回MOVED指令:节点A返回一个MOVED指令,包含目标节点B的地址。
- 客户端重试:客户端向节点B重新发送请求。
- 返回结果:节点B处理请求并返回结果。
注意:重定向MOVED类型,客户端还会更新本地缓存,将该 slot 与 Redis 实例对应关系更新正确。
ASK指令
-
迁移过程中的请求:如果某个键正在从节点A迁移到节点B,客户端请求这个键时,节点A会返回一个ASK指令。
-
临时访问:客户端向节点B发送请求,并在请求前发送ASKING指令,表明这是一次临时访问。
-
数据迁移完成后:客户端可以正常访问节点B,不再需要发送ASKING指令。
注意:ASK 指令并不会更新客户端缓存的哈希槽分配信息。
扩容、缩容
缩容原理
缩容流程:
- 选择要移除的节点
- 哈希槽重分配:在缩容过程中,首先需要将要移除节点上的哈希槽迁移到其他节点。这样可以确保数据的完整性和一致性。
- 数据迁移:哈希槽的迁移意味着对应数据的迁移,Redis Cluster会自动将数据从一个节点复制到另一个节点。
- 将节点从集群中移除
- 更新集群状态:集群状态会随时更新,以反映哈希槽和数据的迁移情况。
- 移除节点:一旦所有数据和哈希槽迁移完成,就可以安全地将节点从集群中移除。
扩容原理
扩容流程:
- 启动新节点
- 将新节点加入集群
- 重新分配哈希槽:在扩容过程中,需要将部分哈希槽从现有节点迁移到新节点,以确保数据分布均匀。哈希槽的重新分配可以通过手动指定或者使用 reshard 命令自动进行。
- 数据迁移:哈希槽迁移意味着对应数据的迁移,Redis Cluster会自动将数据从一个节点复制到另一个节点。数据迁移过程中,Redis Cluster会确保数据的一致性和完整性。
- 更新集群状态:集群状态会随时更新,以反映哈希槽和数据的迁移情况。新节点加入集群后,集群中的其他节点会通过Gossip协议感知新节点的存在,并更新自己的拓扑信息。
- 验证集群状态
主、从节点如何建立的通信
步骤如下:
- 初始配置:每个节点启动时都会加载其配置文件,其中包含节点的 ID、集群状态和分配的哈希槽信息。如果是从节点,还会配置它所跟随的主节点信息。
- 启动节点、发现节点、加入集群:节点通过 Gossip 协议发现和加入集群。每个节点会周期性地向其他节点发送 PING 消息,接收 PONG 响应,了解对方的存在和状态。
- 主从节点建立关系:
- 从节点启动时,根据配置文件中的信息,向其指定的主节点发送复制请求(PSYNC)。
- 主节点接收请求后,开始向从节点复制数据。
- 复制完成后,从节点进入同步状态,定期向主节点发送 ACK 消息,确认接收到的数据。
复制请求(PSYNC)
这里的复制请求(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
-
主节点响: 主节点接收到 PSYNC 命令后,就可以开始数据复制同步了。
参考
- Redis 高可用篇:Cluster 集群原理剖析,集群可以无限拓展么_redis cluster_码哥字节_InfoQ写作社区
- What are Redis Cluster and How to setup Redis Cluster locally ? | by Rajat Pachauri | Medium
- Redis Cluster集群节点间通信:Gossip协议 | 浮生无事Blog (fushengwushi.com)
- 认识Redis集群——Redis Cluster - JJian - 博客园 (cnblogs.com)
- Redis 高可用篇:Cluster 集群原理剖析,集群可以无限拓展么_redis cluster_码哥字节_InfoQ写作社区
-
- 投票选举:被标记为客观下线的主节点的从节点会尝试提升为主节点。
-