Redis 的高可用之Redis Cluster 集群模式

2023年 9月 27日 45.2k 0

一、Redis Cluster 集群是什么

1.1 Redis Cluster 集群诞生的背景

哨兵模式基于主从模式,实现读写分离,它还可以自动切换,系统可用性更高。

但是它每个节点存储数据是一样,浪费内存,并且不好在线扩容。

因此,Reids Cluster 集群(切片集群实现方案)应运而生,它在 Redis3.0 加入,实现了 Redis 分布式存储。

比如你一个 Redis 实例保存 15G 甚至更大数据,响应就会很慢,这是因为Redis RDB 持久化机制导致,Redis 会 fork 子进程完成 RDB 持久化操作,fork 执行耗时与 Redis 数据量成正相关;这就引起了下面三个问题。

graph LR
A(Redis 单节点限制) ---> B(容量限制)
A(Redis 单节点限制) ---> E(高可用性)
A(Redis 单节点限制) ---> D(并发性能)

style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style E fill:#98FB98,stroke:#98FB98,stroke-width:2px

这时候你很容易想到,把 15G 数据分散来存储就好了嘛。这就是 Redis 切片集群初衷。切片集群是啥呢?来看个例子,如果你要用 Redis 保存 15G 数据,可以用单实例 Redis,或者 3 台 Redis 实例组成切片集群,对比如下:

单例Redis

flowchart LR
    客户端 --> Redis,15G数据

切片集群

flowchart LR
    客户端 --> Redis1,5G数据
    客户端 --> Redis2,5G数据
    客户端 --> Redis3,5G数据

切片集群和 Redis Cluster 区别:Redis Cluster 是从 Redis3.0 版本开始,官方提供一种实现切片集群方案。

1.2 Redis Cluster 集群定义

Redis Cluster是Redis数据库的集群解决方案,用于将数据分布在多个节点上,实现分布式存储和处理。它通过自动分片和数据复制来提供高可用性和容错性。

实现了分布式的数据存储和处理,提供了高可用性、容错性和扩展性的优势,使得Redis能够在大规模应用中应对高并发和大数据量的需求。

Redis Cluster的主要特点包括:

graph LR
A(Redis Cluster主要特点) ---> B(分布式存储)
A(Redis Cluster主要特点) ---> C(数据复制)
A(Redis Cluster主要特点) ---> D(自动分片和故障转移)
A(Redis Cluster主要特点) ---> E(节点间通信)

style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style E fill:#98FB98,stroke:#98FB98,stroke-width:2px
  • 分布式存储:Redis Cluster将数据分散存储在多个节点上,每个节点负责存储和处理其中的一部分数据。这种分布式存储方式允许集群处理更大的数据集,并提供更高的性能和可扩展性。

  • 数据复制:每个主节点都有一个或多个从节点,从节点会自动复制主节点上的数据。数据复制可以提供数据的冗余备份,并在主节点故障时自动切换到从节点,以保证系统的可用性。

  • 自动分片和故障转移:Redis Cluster会自动将数据分片到不同的节点上,同时提供自动化的故障检测和故障转移机制。当节点发生故障或下线时,集群会自动检测并进行相应的故障转移操作,以保持数据的可用性和一致性。

  • 节点间通信:Redis Cluster中的节点之间通过内部通信协议进行交互,共同协作完成数据的分片、复制和故障转移等操作。节点间通信的协议和算法确保了数据的正确性和一致性。

二、Redis Cluster 怎么处理实例和数据的映射关系的?

2.1 Redis Cluster使用哈希槽(hash slot)来管理实例和数据之间的映射关系

哈希槽是一个由0到16383之间的整数组成的空间,每个槽可以存放一部分数据。

当你向Redis Cluster中添加节点时,集群会自动分配哈希槽给每个节点。默认情况下,Redis Cluster有16384个哈希槽,每个节点负责一部分槽。

当你向Redis Cluster中写入数据时,Redis会使用一致性哈希算法来确定数据应该存储在哪个哈希槽中。具体的步骤如下:

flowchart TD
    A[1.根据数据的键,Redis Cluster使用CRC16算法计算出一个16位的哈希值]
    B[2.根据哈希槽索引,Redis Cluster确定存储该数据的节点]
    C[3.根据哈希槽索引,Redis Cluster确定存储该数据的节点]

    A --> B --> C

一旦数据被分配到了特定的节点,该节点就负责处理这个数据。当你进行读取操作时,Redis Cluster会根据数据的键计算哈希值,并将请求发送到负责该哈希槽的节点上。

2.2 示例

假设当前集群有 A、B、C 3 个节点,每个节点上负责哈希槽数 =16384/3,那么可能存在一种分配:

flowchart LR
    O[客户端]
    B[节点A]
    N[节点B]
    D[节点C]
    E[负责哈希槽0到5460]
    F[负责哈希槽5461到10922]
    G[负责哈希槽10923到16383]
    O --> B --> E
    O --> N --> F
    O --> D --> G

每个节点负责一部分哈希槽,确保数据在整个集群中均匀分布。在这种配置下,每个节点负责约1/3的哈希槽。

当你添加或移除节点时,Redis Cluster会自动重新分配哈希槽,以适应节点的变化。例如,如果你添加一个新节点,集群会将一部分哈希槽从现有节点迁移到新节点上,以保持数据的均衡性。

三、Redis Cluster中的哈希槽迁移是如何进行的?

3.1 Redis Cluster中的哈希槽迁移过程

在Redis Cluster中,哈希槽迁移是一个自适应的过程,它会根据集群的状态和负载情况动态进行,实现了数据的无损迁移和负载均衡。

哈希槽迁移是通过以下步骤进行的:

graph TD;

subgraph 主流程
    A[节点握手]
    B[哈希槽重分配]
    C[迁移数据同步]
    D[槽迁移确认]
    E[客户端重定向]
end

subgraph 两种同步方式
    F[全量同步]
    G[增量同步]
end

A --> B --> C --> D --> E

C --> F
C --> G
  • 节点握手:当新节点加入Redis Cluster或者一个节点离开集群时,集群中的其他节点会与新节点建立握手连接。节点之间通过握手来交换集群拓扑信息和状态。

  • 哈希槽重分配:一旦握手完成,集群会开始进行哈希槽的重分配。这涉及到将一部分哈希槽从现有的负责节点(源节点)迁移到新的负责节点(目标节点)。哈希槽的迁移是逐个槽进行的,每次迁移一个槽。

  • 迁移数据同步:在哈希槽迁移期间,源节点会将属于目标节点负责的槽中的数据发送给目标节点。数据同步可以通过全量同步或增量同步来完成。

    • 全量同步:源节点将属于目标节点的槽中的所有数据发送给目标节点。这通常发生在初始迁移或网络断开后的重新连接时。

    • 增量同步:源节点将新写入的数据或数据更新发送给目标节点。这发生在全量同步完成后,源节点继续接收和处理写入操作时。

  • 槽迁移确认:目标节点在接收完数据后,会向源节点发送槽迁移确认消息,告知源节点迁移已完成。源节点收到确认后,将标记该槽已成功迁移。

  • 客户端重定向:在迁移过程中,客户端可能会尝试访问正在迁移的槽。为了确保数据一致性,Redis Cluster会向客户端发送重定向消息,告知客户端正确的目标节点地址,使其重新发送请求到正确的节点。

3.2 在哈希槽迁移期间,如果源节点发生故障会怎么样?

Redis Cluster有一套自己的故障转移机制,能够应对节点故障,并在故障发生后继续保持数据的可用性和一致性。

这种自动化的故障处理机制是Redis Cluster的一个关键特性,使得集群具备高可用性和容错性。

当源节点故障时,目标节点会触发故障转移(failover)机制,++选举出一个新的主节点来代替故障的源节点。选举过程涉及到Redis Cluster中的主节点投票和协调机制++。

一旦新的主节点选举完成,哈希槽迁移会继续进行:

flowchart TD
    A[新的主节点接管]
    B[客户端重定向]
    C[数据同步]
    
    A --> B --> C

新的主节点接管:新选举的主节点会接管原先故障节点负责的哈希槽。它会继续从源节点接收数据并完成哈希槽的迁移过程。

客户端重定向:与故障节点相关的哈希槽的客户端会收到重定向消息,告知它们新的主节点地址。客户端需要重新发送请求到新的主节点。

数据同步:如果故障的源节点在故障转移过程中恢复,它会作为一个从节点加入集群,并从新的主节点进行数据同步,以保持数据的一致性。

3.3 Redis Cluster如何确保数据在整个集群中的均匀分布?

Redis Cluster 是通过多种机制组合策略,来确保数据在整个集群中的均匀分布:

flowchart TD
    A[均匀策略]
    B[哈希槽分配]
    C[哈希槽迁移]
    D[一致性哈希算法]
    E[重新平衡]
    
    A --> B
    A --> C
    A --> D
    A --> E
  • 哈希槽分配:Redis Cluster将所有的哈希槽(0到16383)均匀地分配给集群中的节点。每个节点负责一部分哈希槽,确保数据可以在节点之间平衡地存储。

  • 哈希槽迁移:当节点加入或离开集群时,Redis Cluster会自动进行哈希槽的迁移。迁移过程会调整节点负责的哈希槽范围,以达到数据的均衡分布。哈希槽迁移是自适应的,它会根据集群的状态和负载情况动态进行,确保数据在节点之间均匀分布。

  • 一致性哈希算法:Redis Cluster使用一致性哈希算法来确定数据应该存储在哪个哈希槽中。这种算法保证了相同的键(key)总是被映射到相同的哈希槽,从而保证了数据的一致性和均匀分布。

  • 重新平衡:Redis Cluster会定期检查节点的负载情况,并根据需要进行哈希槽的重新分配和迁移,以重新平衡数据的分布。这样可以避免出现某些节点负载过重而导致性能不均衡的情况。

四、MOVED 重定向和 ASK 重定向是干什么用的?

客户端给一个 Redis 实例发送数据读写操作时,如果这个实例上并没有相应数据,会怎么样呢?

嘿嘿,这就是MOVED 重定向和 ASK 重定向要干的事了;

先看看请求来了的处理流程:

flowchart TD
    A[1. 通过哈希槽映射,检查当前 Redis key 否存在当前节点]
    B[2. 若哈希槽不由自身节点负责,就返回 MOVED 重定向]
    C[3. 若哈希槽确实由自身负责,且 key 在 slot 中,则返回该 key 对应结果]
    D[4. 若 Redis key 不存在此哈希槽中,检查该哈希槽否正在迁出?]
    E[5. 若 Redis key 正在迁出,返回ASK 错误重定向客户端到迁移目服务器上]
    F[6. 若哈希槽未迁出,检查哈希槽否导入中?]
    G[7. 若哈希槽导入中且有 ASKING 标记,则直接操作,否则返回 MOVED 重定向]
    
    A --> B --> C --> D --> E --> F --> G

4.1 Moved 重定向

客户端给一个 Redis 实例发送数据读写操作时,如果计算出来槽不在该节点上,这时候它会返回 MOVED 重定向错误,MOVED 重定向错误中,会将哈希槽所在新实例 IP 和 port 端口带回去。这就 Redis Cluster MOVED 重定向机制。

流程图如下:

sequenceDiagram
    participant Client as 客户端
    participant RedisCluster as Redis Cluster
    participant SourceNode as 源节点
    participant TargetNode as 目标节点
    
    Client->>RedisCluster: 发送命令(携带哈希槽)
    RedisCluster->>RedisCluster: 计算槽对应节点
    RedisCluster->>RedisCluster: 检查哈希槽状态
    alt  哈希槽正常
        RedisCluster->>SourceNode: 执行命令
        SourceNode->>Client: 返回结果
    end
    
    alt 哈希槽正在迁移
        RedisCluster->>Client: 返回MOVED错误响应
        Client->>RedisCluster: 解析重定向信息
        Client->>TargetNode: 重新发送命令
        TargetNode->>Client: 返回结果
    end

检查哈希槽状态:Redis Cluster 接收到命令后,会检查该命令涉及的哈希槽的状态。如果该哈希槽正在迁移过程中,即从源节点迁移到目标节点,那么 Redis Cluster 将会返回一个 MOVED 错误响应。

4.2 ASK 重定向

Ask 重定向一般发生于集群伸缩时候。集群伸缩会导致槽迁移,当我们去源节点访问时,此时数据已经可能已经迁移到了目标节点,使用 Ask 重定向可以解决此种情况。

流程图如下:

sequenceDiagram
    participant Client as 客户端
    participant RedisCluster as Redis Cluster
    participant SourceNode as 源节点
    participant TargetNode as 目标节点
    
    Client->>RedisCluster: 发送写入命令(携带哈希槽)
    RedisCluster->>RedisCluster: 计算槽对应节点
    RedisCluster->>RedisCluster: 检查哈希槽状态
    alt 哈希槽正常
        RedisCluster->>SourceNode: 执行写入操作
        SourceNode->>Client: 返回结果
    end
    
    alt 哈希槽正在迁移
        RedisCluster->>Client: 返回ASK错误响应
        Client->>RedisCluster: 解析重定向信息
        Client->>TargetNode: 重新发送写入命令
        TargetNode->>Client: 返回结果
    end

检查哈希槽状态:Redis Cluster 接收到写入命令后,会检查该命令涉及的哈希槽的状态。如果该哈希槽正在迁移过程中,即从源节点迁移到目标节点,但迁移尚未完成,那么 Redis Cluster 将会返回一个 ASK 错误响应。

五、使用Redis Cluster 有什么需要注意的?

  • 数据分片和哈希槽:Redis Cluster 使用数据分片和哈希槽来实现数据的分布式存储。每个节点负责一部分哈希槽,确保数据在集群中均匀分布。在设计应用程序时,需要考虑数据的分片规则和哈希槽的分配,以便正确地将数据路由到相应的节点。

  • 节点的故障和扩展:Redis Cluster 具有高可用性和可伸缩性。当节点发生故障或需要扩展集群时,需要正确处理节点的添加和删除。故障节点会被自动检测和替换,而添加节点需要进行集群重新分片的操作。

  • 客户端的重定向:Redis Cluster 在处理键的读写操作时可能会返回重定向错误(MOVED 或 ASK)。应用程序需要正确处理这些错误,根据重定向信息更新路由表,并将操作重定向到正确的节点上。

  • 数据一致性的保证:由于 Redis Cluster 使用异步复制进行数据同步,所以在节点故障和网络分区恢复期间,可能会发生数据不一致的情况。应用程序需要考虑数据一致性的问题,并根据具体业务需求采取适当的措施。

  • 客户端连接的负载均衡:在连接 Redis Cluster 时,应该使用适当的负载均衡策略,将请求均匀地分布到集群中的各个节点上,以避免单个节点过载或出现热点访问。

  • 事务和原子性操作:Redis Cluster 中的事务操作只能在单个节点上执行,无法跨越多个节点。如果需要执行跨节点的原子性操作,可以使用 Lua 脚本来实现。

  • 集群监控和管理:对 Redis Cluster 进行监控和管理是很重要的。可以使用 Redis 自带的命令行工具或第三方监控工具来监控集群的状态、性能指标和节点健康状况,以及执行管理操作,如节点添加、删除和重新分片等。

5.1 有没有推荐的负载均衡策略可以在Redis Cluster中使用?

在 Redis Cluster 中,可以采用以下几种负载均衡策略来分发客户端的请求:

graph LR
A(负载均衡策略) ---> B(随机选择节点)
A(负载均衡策略) ---> C(轮询选择节点)
A(负载均衡策略) ---> D(哈希分片选择节点)
A(负载均衡策略) ---> E(基于节点负载的选择)
A(负载均衡策略) ---> F(一致性哈希选择节点)

style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style E fill:#98FB98,stroke:#98FB98,stroke-width:2px
style F fill:#ADD8E6,stroke:#ADD8E6,stroke-width:2px
  • 随机选择节点:每次请求随机选择一个节点来处理。这种策略简单且易于实现,但++无法考虑节点的负载情况++。

    • 适用于负载均衡要求不高的场景
  • 轮询选择节点:按照轮询的方式依次选择节点来处理请求。这样可以均匀地将请求分发到各个节点上,但++无法考虑节点的负载情况++。

    • 适用于节点负载相对均衡的场景。
  • 哈希分片选择节点:根据请求的键进行哈希计算,将相同哈希值的请求分发到同一个节点上。这样可以保证相同键的请求总是落到同一个节点上,但++无法考虑节点的负载情况++。

    • 适用于节点负载相对均衡的场景。
  • 基于节点负载的选择:通过监控节点的负载情况(如 CPU 使用率、内存使用率等),选择负载较低的节点来处理请求。这种策略++需要实时监控节点的状态++,并根据实际负载情况进行动态调整。

  • 一致性哈希选择节点:使用一致性哈希算法将请求的键映射到节点,确保在节点添加或删除时,尽量减少键的迁移量。这种策略可以提供较好的负载均衡和节点扩展性,但++可能导致不均匀的数据分布++。

    • 适用于节点负载相对均衡的场景。

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论