当前位置: 首页 > news >正文

Redis Cluster 模式 的具体实施细节是什么样的?

概述

参考:What are Redis Cluster and How to setup Redis Cluster locally ? | by Rajat Pachauri | Medium

Redis Cluster 的工作原理是将数据分布在多个节点上,同时确保高可用性和容错能力。以下是 Redis Cluster 运行方式的简要概述:

  1. 节点发现:Redis 集群使用一种称为“gossip 协议”的概念进行节点发现。每个节点都会维护集群中其他节点的列表,并定期与一些随机选择的节点共享有关集群状态的信息。这有助于节点发现和加入集群。
  2. 数据分片:Redis Cluster 使用一致性哈希将数据划分为多个哈希槽。集群支持 16384 个哈希槽,每个键使用哈希函数映射到特定槽。哈希槽分布在集群中的节点上。
  3. 主-副本复制:Redis 集群遵循主-副本复制模型。每个哈希槽都与特定的主节点相关联,并且该槽中的数据被复制到一个或多个副本节点。副本提供冗余,并在主节点发生故障时充当故障转移节点。
  4. 客户端交互:客户端可以连接到 Redis 集群中的任何节点。当客户端发送与特定键相关的命令时,集群会使用该键的哈希槽来确定负责该槽的节点。然后使用 MOVED 或 ASK 重定向响应将客户端透明地重定向到适当的节点。
  5. 故障转移和高可用性:Redis 集群支持自动故障转移。当主节点发生故障时,其副本之一将自动升级为主节点,从而确保数据的持续可用性。集群使用共识协议来选举新的主节点。客户端通过重定向响应更新新的主节点信息。
  6. 集群配置:Redis 集群维护一个集群配置,其中包含有关节点、哈希槽和副本的信息。当节点加入或离开集群时,此配置会动态更新。集群节点交换消息以就集群配置达成共识并确保其一致性。

通过在多个节点之间分配数据和负载,Redis Cluster 可实现水平扩展并提高性能。它提供容错能力,因为副本可以接管发生故障的主节点的角色。集群还平衡哈希槽的分布,并确保每个节点负责一部分槽,从而使集群能够高效扩展。

Redis cluster 简介

Redis cluster 是一种去中心化的 Redis 分布式集群解决方案。通过数据自动分片分配到多个主节点之间(每个主节点 都是 主从搭配)、自动故障检测,实现了高可用和高性能。

img

特点

Redis Cluster 具有以下几个特点:

  1. 可扩展性(横向扩展):通过向集群添加更多节点,可以增加 Redis 系统的整体容量和吞吐量。

    扩展可以分为Las:垂直扩展(scale up)、水平扩展(scale out)

    • 垂直拓展:升级单个 Redis 的硬件配置,比如增加内存容量、磁盘容量、使用更强大的 CPU。【部署简单,但是当数据量大并且使用 RDB 实现持久化,会造成阻塞导致响应慢。另外受限于硬件和成本,拓展内存的成本太大,比如拓展到 1T 内存】
    • 水平拓展:横向增加 Redis 实例个数,每个节点负责一部分数据。【便于拓展,同时不需要担心单个实例的硬件和成本的限制。但是,切片集群会涉及多个实例的分布式管理问题,需要解决如何将数据合理分布到不同实例,同时还要让客户端能正确访问到实例上的数据
  2. 高可用性主从复制故障转移机制提高了集群的可靠性。

    • 主从复制模式,从节点实时同步主节点的数据。这种结构不仅提高了数据的冗余性,还在主节点出现故障时提供了数据的可用性。
    • 故障转移机制:当主节点不可用时,从节点可以自动提升为主节点。这种自动化的故障处理机制减少了人为干预的需求,确保了系统的持续可用性。

使用场景

高并发应用:需要处理大量并发请求的场景,如电商、社交平台。

数据分片需求:需要水平扩展存储容量的场景。

高可用性需求:需要提供数据冗余和自动故障恢复的应用。

优缺点

优点

  • 水平扩展:通过添加节点轻松扩展集群容量。
  • 高可用性:主从复制和故障转移机制提高了集群的可靠性。
  • 数据分布均衡:哈希槽机制确保数据在集群中均匀分布。

缺点

  • 复杂性增加:集群的配置和管理相较于单节点模式更加复杂。
  • 数据一致性问题:可能出现部分数据不可用的情况,需要应用层处理。()
  • 资源消耗:维护多个节点的状态需要额外的资源和网络通信。

Redis Cluster 实现原理

数据分片与哈希槽

Redis 的数据分片(sharding)是将 Redis数据集 分割为多个部分,分别存储在不同的 Redis节点上的技术。通过数据分片技术可以将 一个单独的 Redis数据库扩展到多个物理机器上,从而提高 Redis集群的性能、扩展性。

当 16384 个槽都分配完全,Redis 集群才能正常工作

img

在Redis的Cluster集群模式中,使用**哈希槽(hash slot)**的方式来进行数据分片,将整个数据集划分为多个槽,每个槽分配给一个节点(这里的节点是由 主、从模式构成的)。

客户端如何访问/插入数据的?

客户端访问数据时,先计算出数据对应的槽,然后直接连接到该槽所在的节点进行操作。具体的:

如何分片的:Redis集群模式中,使用哈希槽(hash slot)的方式将数据分片。

  • 首先,将数据集划分为多个槽,每个槽分配给一个节点。(一个节点会对应多个槽)
  • 客户端访问数据时,先计算出数据对应的槽,然后连接到该槽所属的 Redis节点上,然后在该节点上访问对应数据。

具体流程为:假设要查询 键为key1的数据

  1. key1进行哈希计算(使用CRC16算法计算的结果就是 key1的哈希值),假设得到哈希值为12345。
  2. 对哈希值取模16384,结果为12345。
  3. key1映射到哈希槽12345,由节点B负责。

数据分片的作用

Redis Cluster中的数据分片具有以下特点:

  1. 提升性能和吞吐量:通过在多个节点上分散数据,可以并行处理更多的操作,从而提升整体的性能
    和吞吐量。这在高流量场景下尤其重要,因为单个节点可能无法处理所有请求。
  2. 提高可扩展性:分片使得Redis可以水平扩展。可以通过添加更多节点扩展数据库的容量和处理能
    力。
  3. 降低单个节点的内存和计算需求:每个节点只处理数据的一部分,这降低了单个节点的内存和计算需求。
  4. 避免单点故障:在没有分片的情况下,如果唯一的Redis服务器发生故障,整个服务可能会停止。
    在分片的环境中,即使一个节点出现问题,其他节点仍然可以继续运行。
  5. 数据冗余和高可用性:在某些分片策略中,如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 协议来通信传递信息。

img

上图展示了主从架构的 Redis Cluster 示意图,其中:

  • 实线表示节点间的主从复制关系,
  • 虚线表示各个节点之间的 Gossip 通信。

Redis Cluster 中的每个节点都维护一份自己视角下的当前整个集群的状态信息元数据信息),主要包括:

  1. 当前集群状态
  2. 集群中各节点所负责的 slots信息,及其migrate状态
  3. 集群中各节点的master-slave状态
  4. 集群中各节点的存活状态及怀疑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 的工作原理可以概括成两点:

  1. 一是,每个实例之间会按照一定的频率,从集群中随机挑选一些实例,把 PING 消息发送给挑选出来的实例,用来检测这些实例是否在线,并交换彼此的状态信息。

    例自身的状态信息、部分其它实例的状态信息,以及 Slot 映射表。

  2. 二是,一个实例在接收到 PING 消息后,会给发送 PING 消息的实例,发送一个 PONG 消息。PONG 消息包含的内容和 PING 消息一样。

img

故障检测与自动故障转移

Redis Cluster保证高可用(High Availability)主要还是依靠:故障检测故障转移

自动故障检测

故障检测的机制如下(通过Gossip协议发送消息进行检测):

关于节点参与情况说明:

  1. 主观下线:每个节点(包括主节点从节点)都会检测其他节点的状态。如果检测到某个节点不可用,会将其标记为主观下线(PFAIL)。
  2. 客观下线主节点之间会交换彼此的主观下线状态,如果超过半数的主节点都认为某个节点不可用,则该节点会被标记为客观下线(FAIL)。
  1. 疑似下线:Redis Cluster 中的节点会定期检查已经发送 PING 消息(即上述的心跳机制)的接收方节点是否在规定时间 ( cluster-node-timeout ) 内返回了 PONG 消息,如果没有则会将其标记为疑似下线状态(possible fail,PFAIL)。
    img

  2. 客观下线:当一个节点将另一个节点标记为"疑似失败"后,它会通过Gossip协议将这个信息传播给其他节点。如果一个节点从大多数主节点那里都收到了某个节点的"疑似失败"信息,那么这个节点将被标记为"客观失败"(FAIL)。并将该节点 客观下线的信息,发送给所有节点。

这时,集群会触发故障转移流程,从失败节点的从节点中选举一个新的主节点。

自动故障转移

节点参与情况说明:

  • 从节点投票:当一个主节点被标记为客观下线后,它的从节点会发起故障转移过程。故障转移请求会被发送到其他主节点,以请求授权进行故障转移。

  • 授权投票:其他主节点会对故障转移请求进行投票,同意票数超过半数后,候选从节点会被提升为新的主节点。

当Redis Cluster中的主节点被标记为客观下线(FAIL)时,会触发故障转移(failover)流程。故障转移(failover)是指当主节点不可用时,从节点自动提升为新的主节点,以保证集群的高可用性。故障转移的流程包括以下几个步骤:

  1. 投票选举:被标记为客观下线的主节点的从节点会尝试提升为主节点。
    1. 这些从节点会向集群中的其他主节点请求支持,开始选举过程。
    2. 各个主节点会根据从节点的优先级(配置文件中的 slave-priority 参数)、复制偏移量(replication offset)等因素进行投票。
  2. 选择新的主节点
    1. 得到多数票(超过半数)的从节点会被提升为新的主节点。
    2. 如果没有从节点得到足够的票数,则选举失败,并在短时间后重试。
  3. 配置更新:当选举出新的主节点后,该主节点会通知所有的其他节点,告知他是新的主节点。
  4. 数据同步:原主节点的从节点现在会成为新主节点的从节点,并开始从新主节点同步数据。如果原主节点恢复后重新加入集群,它也会成为新主节点的从节点,并从新主节点同步数据。

重定向

为什么需要重定向

当客户端第一次连接到 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 实例对应关系更新正确。

img

ASK指令

  1. 迁移过程中的请求:如果某个键正在从节点A迁移到节点B,客户端请求这个键时,节点A会返回一个ASK指令。

  2. 临时访问:客户端向节点B发送请求,并在请求前发送ASKING指令,表明这是一次临时访问。

  3. 数据迁移完成后:客户端可以正常访问节点B,不再需要发送ASKING指令。

注意:ASK 指令并不会更新客户端缓存的哈希槽分配信息

扩容、缩容

缩容原理

缩容流程:

  1. 选择要移除的节点
  2. 哈希槽重分配:在缩容过程中,首先需要将要移除节点上的哈希槽迁移到其他节点。这样可以确保数据的完整性和一致性。
  3. 数据迁移:哈希槽的迁移意味着对应数据的迁移,Redis Cluster会自动将数据从一个节点复制到另一个节点。
  4. 将节点从集群中移除
  5. 更新集群状态:集群状态会随时更新,以反映哈希槽和数据的迁移情况。
  6. 移除节点:一旦所有数据和哈希槽迁移完成,就可以安全地将节点从集群中移除。

扩容原理

扩容流程:

  1. 启动新节点
  2. 将新节点加入集群
  3. 重新分配哈希槽:在扩容过程中,需要将部分哈希槽从现有节点迁移到新节点,以确保数据分布均匀。哈希槽的重新分配可以通过手动指定或者使用 reshard 命令自动进行。
  4. 数据迁移:哈希槽迁移意味着对应数据的迁移,Redis Cluster会自动将数据从一个节点复制到另一个节点。数据迁移过程中,Redis Cluster会确保数据的一致性和完整性。
  5. 更新集群状态:集群状态会随时更新,以反映哈希槽和数据的迁移情况。新节点加入集群后,集群中的其他节点会通过Gossip协议感知新节点的存在,并更新自己的拓扑信息。
  6. 验证集群状态

主、从节点如何建立的通信

步骤如下:

  1. 初始配置:每个节点启动时都会加载其配置文件,其中包含节点的 ID、集群状态和分配的哈希槽信息。如果是从节点,还会配置它所跟随的主节点信息
  2. 启动节点、发现节点、加入集群:节点通过 Gossip 协议发现和加入集群。每个节点会周期性地向其他节点发送 PING 消息,接收 PONG 响应,了解对方的存在和状态。
  3. 主从节点建立关系
    1. 从节点启动时,根据配置文件中的信息,向其指定的主节点发送复制请求(PSYNC)
    2. 主节点接收请求后,开始向从节点复制数据。
    3. 复制完成后,从节点进入同步状态,定期向主节点发送 ACK 消息,确认接收到的数据。

复制请求(PSYNC)

这里的复制请求(PSYNC)主要使用的是 Redis 协议(REdis Serialization Protocol, RESP)。

RESP(Redis Serialization Protocol) 是 Redis 的内部协议,用于客户端和服务器之间的通信,也用于 Redis 集群节点之间的通信。该协议简单、高效且便于实现。

复制请求(PSYNC)的流程:

  1. 读取 replicaof 指令,获取主节点信息:

    1. 从节点的配置文件中会包含一条 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
      
    2. 启动从节点,当从节点启动时,它会读取配置文件并解析 replicaof 指令。

  2. 连接主节点:从节点根据 replicaof 指令中指定的 IP 地址和端口,尝试连接主节点。

  3. 发送 PSYNC 命令:一旦连接成功,从节点会向主节点发送 PSYNC 命令以请求复制。PSYNC 命令用于部分重同步或全量重同步。

    PSYNC <replicationid> <offset>
    
  4. 主节点响: 主节点接收到 PSYNC 命令后,就可以开始数据复制同步了。

参考

  1. Redis 高可用篇:Cluster 集群原理剖析,集群可以无限拓展么_redis cluster_码哥字节_InfoQ写作社区
  2. What are Redis Cluster and How to setup Redis Cluster locally ? | by Rajat Pachauri | Medium
  3. Redis Cluster集群节点间通信:Gossip协议 | 浮生无事Blog (fushengwushi.com)
  4. 认识Redis集群——Redis Cluster - JJian - 博客园 (cnblogs.com)
  5. Redis 高可用篇:Cluster 集群原理剖析,集群可以无限拓展么_redis cluster_码哥字节_InfoQ写作社区

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【IT领域新生必看】 Java编程中的重载(Overloading):初学者轻松掌握的全方位指南
  • 基于Java的网上花店系统
  • 认识异常详解
  • 01背包问题-队列分支限界法-C++
  • 数据结构之“栈”(全方位认识)
  • C++初学者指南-4.诊断---基础:警告和测试
  • 宿舍报修小程序的设计
  • 从入门到深入,Docker新手学习教程
  • 网络-calico问题分析
  • Java面试八股之MySQL存储货币数据,用什么类型合适
  • 24.6.30
  • C++笔试强训2
  • c_各个unsigned int 和 int的取值范围
  • Exploting an API endpoiint using documentation
  • 011 多线程问题
  • 分享的文章《人生如棋》
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 【RocksDB】TransactionDB源码分析
  • 【面试系列】之二:关于js原型
  • 2017-08-04 前端日报
  • bearychat的java client
  • golang中接口赋值与方法集
  • javascript数组去重/查找/插入/删除
  • Node 版本管理
  • Node项目之评分系统(二)- 数据库设计
  • node学习系列之简单文件上传
  • npx命令介绍
  • Python 基础起步 (十) 什么叫函数?
  • SAP云平台里Global Account和Sub Account的关系
  • Swift 中的尾递归和蹦床
  • SwizzleMethod 黑魔法
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • 从零开始的无人驾驶 1
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 模型微调
  • 你真的知道 == 和 equals 的区别吗?
  • 移动端唤起键盘时取消position:fixed定位
  • ​浅谈 Linux 中的 core dump 分析方法
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • #数学建模# 线性规划问题的Matlab求解
  • (1)(1.9) MSP (version 4.2)
  • (1)无线电失控保护(二)
  • (附源码)springboot人体健康检测微信小程序 毕业设计 012142
  • (四)Controller接口控制器详解(三)
  • (一)Neo4j下载安装以及初次使用
  • ... 是什么 ?... 有什么用处?
  • .net refrector
  • .net 获取url的方法
  • .net 获取某一天 在当月是 第几周 函数
  • .NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)
  • .Net的DataSet直接与SQL2005交互
  • /proc/interrupts 和 /proc/stat 查看中断的情况
  • @NotNull、@NotEmpty 和 @NotBlank 区别
  • [ C++ ] STL_list 使用及其模拟实现
  • [2024最新教程]地表最强AGI:Claude 3注册账号/登录账号/访问方法,小白教程包教包会