Redis集群从搭建到设计,总有一些你不曾了解的东西

2023-05-16

Redis集群是Redis服务器高可用的设计模型,也是我们线上应用最多的Redis部署架构。本文主要针对Redis集 群入门搭建、Redis集群节点及其底层数据结构、hash槽、重新分片、消息等核心操作及原理进行分享。本文是基于Redis6.0.1版本展开。

集群搭建

在学习底层原理之前我们首先需要集群是如何应用及搭建部署的。本小节主要介绍集群搭建的核心步骤(本文都是在linux环境上进行操作,至于怎么下载Redis安装包及make过程不在本文讲解内容之内,因为它过于基础)。

环境准备

将安装好的Redis包放到任意目录,我这里是放到了/Users/mm/application/redis-cluster中。我这里就以伪集群的方式来进行说明(与集群搭建部署方式基本一致),部署6个集群节点。

  • 在redis-cluster/config目录中新建6个目录(我这里分别命名为7001、7002、7003、7004、7005、7006,代表6个节点),将redis.conf配置和redis-server启动文件分别cp到这6个目录中(我这里也将每个节点的redis.conf配置文件也分别命名成redis7001.conf、redis7002.conf … …),并将这6个目录进行授权。

  • 修改每个节点中redis.conf的配置(可以先修改一个节点的配置,然后使用例如sed -i ‘’ ‘s/7001/7002/g’ redis7002.conf):

    bind 192.XXX.XXX.XXX     		#改为实际的外网ip
    port 7001                       #端口(伪集群模式下ip一致、端口不一致)
    cluster-enabled yes            	#开启此配置,启用集群模式
    logfile "/log7001.log"          #集群日志文件配置,因为是伪集群,日志名称通过端口进行区分命名,集群下无所谓
    
  • 新建一个redis集群启动脚本(因为节点太多,每个节点都用命令启动太麻烦了),脚本我就放在了redis-cluster根目录下,cluster.sh:

    cd config/7001
    ./redis-server ./redis7001.conf&
    cd ../7002
    ./redis-server ./redis7002.conf&
    cd ../7003
    ./redis-server ./redis7003.conf&
    cd ../7004
    ./redis-server ./redis7004.conf&
    cd ../7005
    ./redis-server ./redis7005.conf&
    cd ../7006
    ./redis-server ./redis7006.conf&
    
启动

现在我们就可以启动集群了。

  • 执行上面编写好的cluster.sh脚本。

    mm@mmdeiMac redis-cluster % ./cluster.sh 
    
  • 启动之后查看reids进程:
    在这里插入图片描述
    我们看到6个节点都已经启动,并且是以cluster的模式启动。

  • 但此时redis集群还没有真正搭建完成,因为此时主从节点还未分配、hash槽也未分配。下面为创建集群及自动分配hash槽:
    在这里插入图片描述

  • 经过上述部署,集群基本搭建完成,我们可以用redis-cli来登陆客户端,看下集群效果(以集群方式连接客户端):
    在这里插入图片描述
    上面通过cluster info查看到了redis集群节点的状态、cluster nodes查看到了集群中的每个节点的主从关系及每个节点负责的hash槽位。可以通过set、get来测试了。

集群节点数据结构

在这里插入图片描述

上图描述了集群中的节点的数据结构:

  • clusterState:集群中当前节点的描述信息。

    struct clusterState {
    	* myself;
    	currentEpoch;
    	* slots;
    	* nodes;
    	flag;
    	...
    }
    

    myself:指向当前节点本身的指针;
    currentEpoch:当前集群的纪元;
    slots:集群中所有的槽位数组,每个数组索引指向负责该槽位的节点;
    nodes:当前节点已知的集群中的所有节点;
    flag:标记当前节点的角色;
    state:当前节点的状态(在线/下线)。

  • clusterNode:描述集群中的节点信息。

    struct clusterNode {
    	ip;
    	port;
    	flag;
    	* sort;
    	...
    }
    

    ip:节点的ip;
    port:节点的端口;
    flag:节点的角色;
    sort:指针数组,记录了所属节点负责的槽位。即是一个长度16384的数组,每一个索引代表一个槽位,索引值为当前索引槽位是否属于当前节点,若值为1即当前槽位是属于这个节点的,否则为0,即当前槽位不属于当前节点。

hash槽

一直在提hash槽,那么hash槽是什么呢?hash槽是redis集群中的一个逻辑值,共有16384个(从0-16383编号),集群中的每个主节点都负责一部分hash槽。即当一个客户端向集群中发起一个set key value请求后,这个键值对会发往哪个节点进行处理,此时就用到了hash槽。hash槽的值=CRC16(key) & 16383,CRC16大家可以理解为是一个算法,最终计算出的值就在0-16383之间,即该请求就会由负责当前槽位的节点处理。

加入新节点

扩展当前集群,向集群中加入新节点:

cluster meet ip port

新建一个节点7007,将7007这个节点加入集群:
在这里插入图片描述
我们可以看到加入集群后的7007节点还没有分配槽位,我们可以通过以下命令分配槽位:

cluster addslots slot … slot

为7007节点分配槽位(0-5400):
在这里插入图片描述
让系统自动重新分配槽位:

redis-cli --cluster reshard ip port
在这里插入图片描述
上面重新分配槽位是报错了,可能是由于节点删除了,相应的槽位没有正确的删除,导致槽位分布不正确。
此时可以通过以下操作完成修复:
在这里插入图片描述

上述操作是修复集群中节点的问题。

以下是7002节点从7001节点分配hash槽的过程:
在这里插入图片描述

cluster meet原理

meet流程
客户端在server A上执行meet操作,希望将server B加入到集群中:

  • 客户端执行meet操作,server A上建立节点B的信息clusterNode,保存到A节点的clusterState.nodes属性中;
  • server A根据cluster meet ip port中的ip和port向server B发送meet请求。
  • server B接收到A的meet请求后,在server B节点上新建一个A节点的信息clusterNode,保存在B节点的clusterState.nodes属性中。server B向节点A发送一个pong消息。
  • server A收到server B的pong消息后,向server A发送一个ping消息。
  • server B收到server A发来的ping消息后,知道server A已经确认了自己发送的消息后,完成了整个握手操作。
  • 完成后,server A会讲server B加入到集群的消息通过Gossip协议发送给集群中的所有节点,至此集群中的所有节点都知道了server B已加入了集群。
addslots原理

cluster addslots {slot…slot}

将任意个空闲槽位加入到当前节点中。实现原理:

  • 根据输入的slot集合,与clusterState.slots中拿出所有槽位进行比较(未用槽位指向null,已用槽位指向负责该槽位的节点),如果输入的slot集合中只要有一个槽位已使用,那么就给客户端一个报错响应;
  • 如果输入的槽位都未使用,那么遍历输入的每一个槽位i,将clusterState.slots[i]指向当前节点,然后将当前节点的clusterNode.slot[i]数组中的值设置为1,表示为当前节点负责这个槽位。

其实通过上面的原理也能看得出来,为什么在clusterState和clusterNode中都会存放一个指向槽位的指针了。因为判断槽位是否可用以及当前槽位属于哪个节点就直接看clusterState.slot[i]是否指向null还是指向具体的clusterNode;如果看当前节点负责那些槽位,直接可以通过当前节点的clusterNode.slot来查询就可以。以上查询的时间复杂度都为o(1)。

MOVED错误

在这里插入图片描述
MOVED错误是在当前节点指向set或get等操作时,通过key计算出的hash槽不在当前节点上,服务器会重定向到正确的节点,也就是负责当前槽位的节点上,在执行客户端请求。当然这个客户端自动跳转是以集群方式开启客户端来说的,以单机模式开启客户端,那么客户端就直接返回给用户一个MOVED的error。

下面就是集群模式的客户端重定向的请求:
在这里插入图片描述

重新分片

在这里插入图片描述在这里插入图片描述
上图很明确的描述了节点重新分片的流程,即将其他节点的槽位及槽位上的数据移至到另一个节点上。
1、通知源节点,将要把5343槽位导入到目标节点中;
2、通知目标节点,将要把5343槽位移除;
3、告知源节点要从5343槽位获取多少键值对;
4、将从源节点移除指定键值对到源节点;
5、通知集群中的其他节点,5343槽位已移动到目标节点中。

cluster setslot importing

cluster setslot slot importing source_node_id

当客户端向目标节点发送这个命令后,目标节点会将自身的存储结构clusterState.importing_slots_from属性设置为指向目标节点clusterNode的指针。
在这里插入图片描述

cluster setslot migrating

向目标节点发送cluster setslot slot migrating target_node_id,将告诉目标节点此槽位将要移除,这样目标节点将clusterState.migrating_slots_to属性值置为指向源节点的指针。

故障转移及选举流程

故障转移

当主节点下线后,从节点将对主节点进行故障转移:

  • 发生故障的主节点里面会有一个从节点被选中;
  • 被选中的从节点会成为新的从节点;
  • 新的主节点会撤销已下线的主节点负责的槽位,然后将槽位指派给自己;
  • 新的主节点会向集群中所有节点发送pong消息,告知所以节点原来的主节点已经下线,并且当前的节点成为新的主节点。
  • 主节点开始正常接收客户端的请求。
选举流程
  • 当从节点发现自己正复制的主节点下线后,会向集群中的所以节点发送一条广播;
  • 接收到广播的有选举资格的主节点,并且该主节点没有投票给其他节点,会投票给这个从节点,即会发送一条消息给这个从节点;
  • 该从节点接收到这个消息后,记录收到的消息总和,如果该节点被投票的票数大于节点总数的二分之一,那么就被选举为主节点;
  • 因为集群中有纪元的概念,会保证在一个集群纪元中,保证一个主节点只有一次投票的权利。

最后

写了大半天,累了。如果本文对你有价值,哪怕一点点,请记得关注、点赞,有不足或疑问之处请留言。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Redis集群从搭建到设计,总有一些你不曾了解的东西 的相关文章

随机推荐

  • 通过sysinfo获取Linux系统状态信息

    系统运行状态信息是我们关注的重点 xff0c 通过当前系统的输出信息 xff0c 如内存大小 进程数量 运行时间等 xff0c 以便分析CPU负载 软硬件资源占用情况 xff0c 确保系统高效和稳定 Linux系统中 xff0c 提供sys
  • Keil AC5/Keil AC6/IAR指定数据绝对存储地址

    文章目录 1 前言2 实现方法3 例子 1 前言 编译过程中 xff0c 指定数据绝对存储地址在实际项目中会经常使用到或者必须用到 xff0c 这样使得项目实现某些功能可以非常灵活 xff0c 常用的场景有 xff1a IAP升级时候 xf
  • 嵌入式开发常用到的在线工具

    文章目录 IP地址计算常用加解密 xff0c AES DSE Base64 MD5异或 xff08 BCC xff09 校验CRC计算十六进制格式化字符串Json格式化HTML运行器常用在线编译器 xff08 C C 43 43 C JAV
  • STM32H7xx 串口DMA发送&接收(LL库)

    文章目录 1 前言2 STM32H7实现2 1 关键步骤2 2 注意事项 3 代码仓库 1 前言 关于串口DMA收发实现 xff0c 不同CPU其套路都是类似的 xff0c 不同之处在于寄存器配置 依赖BSP库等差异 串口DMA收发详细实现
  • 正交编码器溢出处理

    文章目录 1 正交编码器1 1 参数特性1 2 应用范围 2 正交编码器使用2 1 溢出问题2 2 中断模式2 3 循环模式延伸 1 正交编码器 正交编码器一般指的是增量式光栅 xff08 磁栅 xff09 编码器 xff0c 通常有三路输
  • PX4多旋翼期望姿态矩阵生成算法

    1 PX4多旋翼期望姿态生成算法 1 1 求期望体轴X轴向量1 2 求期望体轴Y轴向量1 3 求期望姿态矩阵1 4 求期望姿态角 1 PX4多旋翼期望姿态生成算法 PX4多旋翼期望姿态生成采用旋转矩阵方法 xff0c 基本思路为根据外环解算
  • git安装

    Git介绍 分布式 xff1a Git版本控制系统是一个分布式的系统 xff0c 是用来保存工程源代码历史状态的命令行工具 保存点 xff1a Git的保存点可以追踪源码中的文件 并能得到某一个时间点上的整个工程项目的状态 xff1b 可以
  • linux更改ssh连接方式将publickey改为用户名密码登录

    1 vim etc ssh sshd config 2 PermitRootLogin no 改为 PermitRootLogin yes 3 service restart sshd
  • dsp2812 pmsm foc之速度环电流环

    61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 速度环PI 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • leetcode(c++)

    放假没事刷几道leetcode xff0c 一些常见典型题的答案和解析 平时python用的比较多 xff0c 但分析复杂度的时候用python编程不方便 xff0c 所以刷题的时候用了c 43 43 C 43 43 基础 C 43 43
  • 基于STM32的超声波雷达项目【可拟合构建平面地图】(代码开源)

    前言 xff1a 本文为手把手教学基于STM32的超声波雷达 项目 HC SR04雷达 本次项目采用的是STM32作为MCU xff0c 搭配常用的HC SR04超声波模块与舵机SG90实现模拟雷达检测 的效果 模拟了雷达图UI 可以拟合构
  • android sdk manager不显示更新,只显示已安装,解决办法

    启动 Android SDK Manager xff0c 打开主界面 xff0c 依次选择 Tools Options xff0c 弹出 Android SDK Manager Settings 窗口 xff1b 在 Android SDK
  • detectron2学习:KeyError: “No object named ‘XXXXX‘ found in ‘BACKBONE‘ registry!“

    问题来源 在使用FB的框架detectron2改写模型的时候碰到了KeyError 34 No object named 39 XXXXX 39 found in 39 BACKBONE 39 registry 34 的bug 分析 xff
  • linux内核网络协议栈--linux网络设备理解(十三)

    网络层次 linux网络设备驱动与字符设备和块设备有很大的不同 字符设备和块设备对应 dev下的一个设备文件 而网络设备不存在这样的设备文件 网络设备使用套接字socket访问 xff0c 虽然也使用read write系统调用 xff0c
  • makefile使用--命令(三)

    一 Make的概念 Make这个词 xff0c 英语的意思是 34 制作 34 Make命令直接用了这个意思 xff0c 就是要做出某个文件 比如 xff0c 要做出文件a txt xff0c 就可以执行下面的命令 span class t
  • 【笔记】ubuntu18.04 ros melodic turtlebot3 源码下,导航gmapping仿真

    编写本笔记原因 xff1a 源码编译没问题 xff0c 但是在运行roslaunch turtlebot3 slam turtlebot3 slam launch slam methods 61 cartgrapher时出现下面这个错误 x
  • 从kernel层面分析synchronized、volatile,进大厂必备硬核小伎俩(上)

    synchronized volatile对于java程序员来说再熟悉不过了 xff0c 但 是你知道这两个关键字底层是如何实现的吗 xff08 甚至在操作系层面是 通过什么指令来实现的 xff09 xff1f 以及与其相关的术语 xff1
  • linux内核原理剖析——内存寻址(一)

    最近总想分享点硬核的原创文章出来 xff0c 一是硬核技术是一个程序员真正应该修炼 的内功 xff1b 二是修炼硬核技能是通往架构师领域的必经之路 本系列文章将分享关 于linux内核设计原理相关的内容 xff0c 希望能打通我们的七经八脉
  • linux内核原理剖析——磁盘寻址、分区

    继上一篇 lt lt linux内核原理剖析 内存寻址 xff08 一 xff09 gt gt 之后 xff0c 发现大家 对底层技术关注度比较高之后 xff0c 今天继上一篇的内存寻址一文后 xff0c 补 充一篇关于更为底层的 磁盘寻址
  • Redis集群从搭建到设计,总有一些你不曾了解的东西

    Redis集群是Redis服务器高可用的设计模型 xff0c 也是我们线上应用最多的Redis部署架构 本文主要针对Redis集 群入门搭建 Redis集群节点及其底层数据结构 hash槽 重新分片 消息等核心操作及原理进行分享 本文是基于