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

Redis集群模式之Redis Cluster(1)

        在前面的文章中我们介绍了什么是主从复制模式和哨兵模式,这两种模式虽然可以使用读写分离策略对读的并发性进行扩展,但是写能力和存储能力无法得到有效的扩展,只能是主节点服务器单服务器的性能上限。如果面对海量数据的存储,就要构建主节点之间的集群,同时要兼具上面两种模式的优点,也就是每个主节点必须有自己的从节点来进行数据冗余存储,这就是Redis Cluster模式。

Redis Cluster主要模块介绍

哈希槽(Hash Slot)

        Redis Cluster没有使用一致性Hash,而是引入了哈希槽的概念。Redis Cluster中有16384(2^14)个哈希槽,每个key通过CRC16校验后对16383取模来决定放置到哪个槽。Cluster中的每个节点负责一部分Hash槽。

        假设集群中存在3个主节点,则可能按照以下数量进行哈希槽的分配:

        主节点1负责0~5400号的哈希槽,主节点2负责5401~10800号的哈希槽,主节点3负责10801~16383号的哈希槽。

Keys Hash Tags

        Hash Tags提供了一种途径,用来将多个相关的key分配到相同的哈希槽中,这是Redis Cluster中实现multi-key操作的基础。

        Hash Tag规则如下,如果满足如下规则,那么“{”和“}”之间的字符将用来计算Hash Slot,以保证这样的key储存在同一个哈希槽中。规则如下:

        (1)key包含一个“{”字符;

        (2)并且如果在这个“{”字符的右边还有一个“}”字符;

        (3)并且如果在“{”和“}”字符之间存在至少一个字符。

        举个例子:

        {id888}.a和{id888}.b这两个key会被存放在同一个哈希槽中,因为哈希值在计算时只考虑“{}”内的值。如果不满足上面的三条规则,则不会启用Hash Tags。

Cluster Nodes属性

        每个节点在Cluster中有一个唯一的名字。这个名字由160bit随机十六进制数字表示,并在节点启动时第一次获得(通常通过/dev/urandom)。节点在配置文件中保留他的ID,并永远使用这个ID,直到被管理员使用CLUSTER RESET HARD命令hard reset这个节点。

        节点ID被用来在整个Cluster中标识每个节点。一个节点可以修改自己的IP地址而不需要修改自己的ID。Cluster可以检测到IP/port的改动并通过运行在Cluster Bus上的gossip协议重新配置该节点。

        节点ID并不是唯一与节点绑定的信息,但是他是唯一的一个总是保持全局一致的字段。每个节点都拥有一系列相关的信息。一些信息是关于本节点在集群中配置的细节,并最终在Cluster内部保持一致。而其他信息,比如节点最后被ping的时间,是节点的本地信息。

        每个节点维护着集群内其他节点的以下信息:节点id、节点的IP和Port、节点标签,主节点id(表明该节点为从节点),最后被挂起的ping的发送时间(如果没有挂起的ping则为0),最后一次收到pong的时间,当前的节点configuration epoch,链接状态,以及最后是该节点服务的哈希槽。

        对节点字段更详细的描述,可以参考对命令CLUSTER NODES的描述。

Cluster总线

        每个Redis Cluster节点有一个额外的TCP端口用来接受其他节点的连接。这个端口与用来接收Client命令的普通TCP端口有一个固定的offset。该端口等于普通命令端口+10000。

        节点到节点的通信只使用集群总线,同时使用集群总线协议:有不同的类型和大小的帧组成的二进制协议。

集群拓扑

        Redis Cluster是一张全网拓扑,节点与其他每个节点之间都保持着TCP连接。在一个拥有N个节点的集群中,每个节点由N-1个TCP传出连接,和N-1个TCP传入连接。这些TCP连接总是保持活性。当一个节点在集群总线上发送了ping请求并期待对方回复pong,如果没有得到回复,在等待足够长时间以便将对方标记为不可达之前,它将先尝试重新连接对方以刷新与对方的连接。而在全网拓扑中的Redis Cluster节点,节点使用gossip协议和配置更新机制来避免在正常情况下节点之间交换过多的消息,因此集群内交换的消息数目(相对节点数目)不是指数级的。

节点握手

        节点总是接受集群总线端口的连接,并且总是会回复ping请求,即使ping来自一个不可信节点。然而,如果发送节点被认为不是当前集群的一部分,那么其他包将被抛弃。

        节点认定其他节点是当前集群的一部分有两种方式:

        (1)如果一个节点出现在一条MEET消息中。一条meet消息非常像一个ping消息,但是它会强制接收者接收一个节点作为集群的一部分。节点只有在接收到系统管理员的CLUSTER MEET ip port命令,才会向其他节点发送MEET消息。

        (2)如果一个被信任的节点gossip了某个节点,那么接收到gossip消息的节点也会将那个节点标记为集群的一部分。也就是说,如果在集群中,A知道B,B知道C,B发送gossip消息到A,告诉A:C是集群的一部分。这时,A会把C注册为网络的一部分,并尝试与C建立连接。

        这就意味着,一旦我们把某个节点加入了连接图,它们最终会自动形成一张全连接图。这意味着只要系统管理员强制加入一条信任关系,集群可以自动发现发现其他节点。

请求重定向

        Redis Cluster采用去中心化的架构,集群的主节点各自负责一部分哈希槽,客户端如何确定key到底会映射到哪个节点上呢?这就是下面我们要介绍的请求重定向。

        在Cluster模式下,节点对请求的处理过程如下:

        (1)检查当前key是否存在当前的节点下(通过CRC16校验后取模,得到对应的Slot值;查询该Slot值负责的节点,得到节点指针;将得到的指针与自身进行比较);

        (2)如果Slot不是自身负责的,则返回MOVED重定向;        

        (3)如果Slot是自身负责的,并且key在Slot中,则返回该key对应的结果;

        (4)如果key不在此Slot中,检查该Slot是否正在迁出(MIGRATING);

        (5)如果key正在迁出,返回ASK错误,重定向客户端到迁移的目的服务器上;

        (6)如果Slot未迁出,检查Slot是否导入中;

        (7)如果Slot导入中且有ASKING标记,则直接操作;

        (8)否则返回MOVED重定向。

        我们来讲解一下什么是MOVED重定向和ASK重定向。

MOVED重定向

        

        MOVED具体的流程如下:

        (1)客户端发送键命令给任意节点;

        (2)任意节点对键进行Slot值的计算并得到对应节点的指针;

        (3)接着判断得到的指针是否指向自身,并判断是否槽命中。如果是,则执行命令,如果不是,则返回MOVED重定向命令给客户端。

        (4)客户端根据重定向重新发送键命令到对应节点。

        槽命中:指的是所找的键在当前节点负责的哈希槽中可以找到。

ASK重定向

        ASK重定向发生于集群伸缩(集群中节点数量扩充或缩减)时,集群伸缩会导致哈希槽的迁移,当我们去源节点访问时,此时的数据可能已经迁移到了目标节点,使用ASK重定向来解决此问题。

Smart客户端

        上述两种重定向机制使得客户端的实现更加复杂,通过Smart客户端(Jedis Cluster)来减低复杂性,追求更好的性能。客户端内部负责计算/维护键\rightarrow\rightarrow节点的映射,用于快速定位目标节点。具体的实现原理如下:

        (1)从集群中选取一个可运行节点,使用Cluster Slots得到槽和节点的映射关系。

        (2)将上述映射关系储存到本地,通过映射关系就可以直接对目标节点进行操作(CRC16(key)\rightarrowSlot\rightarrowNode),很好地避免了MOVED重定向,并且为每个节点创建Jedis Pool。

        至此,客户端就可以用来命令操作了,具体的流程图如下:

        

        本篇文章我们主要介绍了Redis Cluster要解决的问题、Redis Cluster中的一些基本概念和Redis Cluster中的重定向机制,大家有什么问题或者勘误可以在评论区留言,笔者看到都会回复的。

http://www.xdnf.cn/news/993097.html

相关文章:

  • SPP——神经网络中全连接层输出尺寸限制的原因和解决办法
  • 【强连通分量 拓扑序】P9431 [NAPC-#1] Stage3 - Jump Refreshers|普及+
  • HashMap真面目
  • Python数据可视化艺术:动态壁纸生成器
  • 《C++初阶之类和对象》【类 + 类域 + 访问限定符 + 对象的大小 + this指针】
  • Vue3+TypeScript实现中介者模式
  • 【Docker管理工具】安装容器管理工具Oxker
  • 通信网络编程2.0——JAVA
  • HALCON第五讲-> 形状匹配
  • 每日八股文6.12
  • 蓝桥杯20112 不同的总分值
  • 网页怎么调用字体ttf文件?
  • Go 语言安装指南:并解决 `url.JoinPath` 及 `Exec format error` 问题
  • [论文阅读] 系统架构 | 零售 IT 中的微服务与实时处理:开源工具链与部署策略综述
  • MySQL数据库:关系型数据库的基石
  • AVL树的平衡艺术:用C++写出会“站立”的二叉树(未完待续)
  • 【SAS求解多元回归方程】REG多元回归分析-多元一次回归
  • windows基线配置
  • ss928v100模型的导出、量化和转换
  • 中科院1区|IF6.7:基于PCA/OPLS-DA和KEGG通路分析的多组学整合,揭示沙棘-水飞蓟复方改善高脂血症的分子基础
  • C语言:指针进阶(下)
  • OpenAI推出专业级大模型o3-pro:为高精度任务而生
  • 【技术追踪】纵向 MRI 生成和弥漫性胶质瘤生长预测的治疗感知扩散概率模型(TMI-2025)
  • 商标注册小类怎么选?业务+战略双维度匹配
  • 离线部署openstack 2024.1 nova
  • C++实现文本编辑功能
  • cocosCreator 2.4 使用 flavor 配置安卓多渠道
  • OpneLayers 创建地图卷帘
  • 系统设计基本功:流量与存储需求估算
  • 40 C 语言日期与时间函数详解:time、ctime、difftime、clock(含 UTC/本地时间转换)