Redis设计与实现第17章 -- 集群 总结1(节点 槽指派)

集群通过分片sharding来进行数据共享,并提供复制和故障转移功能。

17.1 节点

一个Redis集群通常由多个节点node组成,刚开始每个节点都是相互独立的,必须将各个独立的节点连接起来,才能构成一个包含多个节点的集群。通过CLUSTER MEET <ip><port>命令完成,向一个节点发送该命令,可以让node节点与ip/port所指定的节点进行握手handshake,当握手成功后,node节点就会将ip/port所指定的节点添加到节点当前所在的集群中。

17.1.1 启动节点

一个节点就是一个运行在集群模式下的Redis服务器,这个服务器会在启动时根据cluster-enabled配置选项是否为yes来决定是否开启服务器的集群模式。

节点会继续使用所有在单机模式中使用的服务器组件。

初次之后,只有集群模式下才会用到的数据,节点保存在了clusterNode/clusterLink/clusterState结构。

17.1.2 集群数据结构

clusterNode结构保存了一个节点的当前状态,比如节点的创建时间、名字、配置纪元、IP地址和端口号。每个节点都使用一个clusterNode结构来记录自己的状态,并且也记录集群里其他节点的作用。

struct clusterNode{//创建节点的时间mstime_t ctime;//节点的名字,由40个十六进制字符组成//例如68eef66df23420a5862208ef5b1a7005b806f2ffchar name[REDIS_CLUSTER_NAMELEN];//节点标识//使用各种不同的标识值记录节点的角色(比如主节点或者从节点),//以及节点目前所处的状态(比如在线或者下线)。int flags;//节点当前的配置纪元,用于实现故障转移uint64 tconfigEpoch;//节点的IP地址Char ip[REDIS_IP_STR_LEN];//节点的端口号int port;//保存连接节点所需的有关信息clusterLink *link;

其中link结构保存了连接节点所需的有关信息,比如套接字描述符、输入缓冲区和输出缓冲区。

typedef struct clusterLink{//连接的创建时间mstime_t ctime;// TCP 套接字描述符int fd;//输出缓冲区,保存着等待发送给其他节点的消息(message)。sds sndbuf;
//输入缓冲区,保存着从其他节点接收到的消息。sds rcvbuf;//与这个连接相关联的节点,如果没有的话就为NULLstruct clusterNode *node;
}clusterLink;

redisClient结构和clusterLink结构都有自己的套接字描述符和输入、输出缓冲区,这两个结构的区别在于,redisClient结构中的套接字和缓冲区是用于连接客户端的,而clusterLink结构中的套接字和缓冲区则是用于连接节点的。

每个节点都保存一个clusterState结构,记录了在当前的视角下,集群目前所处的状态,例如集群是在线还是下线,包含多少个节点,当前的配置纪元。

typedef struct clusterstate//指向当前节点的指针clusterNode *myself;//集群当前的配置纪元,用于实现故障转移uint64 tcurrentEpoch;//集群当前的状态:是在线还是下线int state;//集群中至少处理着一个槽的节点的数量int size;//集群节点名单(包括myself节点)//字典的键为节点的名字,字典的值为节点对应的clusterNode结构dict *nodes;
}clusterState;

17.1.3 CLUSTER MEET命令的实现

通过向节点A发送CLUSTER MEET命令,客户端可以向接收命令的节点A将另一个节点B添加到节点A当前所在的集群里面

收到命令的节点A将与节点B进行握手:

  1. 节点A会为节点B创建一个clusterNode结构,并将该结构添加到自己的clusterState.nodes字典里

  2. 之后,节点A会根据该命令给出的IP地址和端口号,向节点B发送一条MEET消息

  3. 如果一切顺利,节点B将接收到节点A发送的MEET消息,节点B会为节点A创建一个clusternode结构,并将该结构添加到自己的clusterState.nodes字典里

  4. 之后,节点B向节点A发送一条PONG消息

  5. 节点A收到以后,就知道节点B已经成功接收到了自己发送的MEET消息

  6. 节点A向节点B返回一条PING消息

  7. 节点B收到后,握手完成

之后,节点A会将节点B的信息通过Gossip协议传播给集群中其他节点,让其他节点也与节点B握手。

17.2 槽指派

Redis集群通过分片的方式来保存数据库中的键值对:集群的整个数据库被划分为16384个槽slot,数据库的每个键都属于这16384个槽的其中一个,集群中的每个节点可以处理0个或最多16384个槽

当数据库中的16384个槽都有节点在处理时,集群处于上线ok状态;否则,处于下线fail状态。

通过向节点发送CLUSTER ADDSLOTS命令,可以将一个或多个槽指派给节点负责,比如127.0.0.1:7000 > CLUSTER ADDSLOTS 0 1 2 3 4 ……5000 表示把槽0至槽5000指派给节点7000负责。

17.2.1 记录节点的槽指派信息

clusterNode结构的slots属性和numslot属性记录了节点负责处理哪些槽。

struct clusterNode{unsigned char slots[16384/8];int numslots;};

slots属性是一个二进制数组,这个数组长度是16384/8=2048个字节,共包含16384个二进制位

Redis以0为起始索引,16383为终止索引,对slots数组中的16384个二进制位进行编号,并根据索引i上的二进制位的值来判断节点是否负责处理槽i。如果该位为1,表示负责处理

因为取出和设置slots数组中的任意一个二进制位的值的复杂度仅为O(1) ,所以检查节点是否负责处理某个槽,或是把某个槽指派给节点负责,复杂度都是O(1)

numslots属性记录节点负责处理的槽的数量,也就是slots数组中值为1的二进制位的数量

17.2.2 传播节点的槽指派信息

一个节点除了会将自己负责处理的槽记录在clusterNode结构的slots属性和numslots属性之后,它还会将自己的slots数组通过消息发送给集群里的其他节点,以此来告知其他节点自己目前正在负责处理哪些槽。

当节点A通过消息从节点B那里接收到节点B的slots数组时,节点A会在自己的clusterState.nodes字典中查找节点B对应的clusterNode结构,并对结构中的slots数组进行保存或更新。

这样,集群里的每个节点都会将自己的slots数组通过消息发送给集群中的其他节点,并且每个接收到slots数组的节点都会将数组保存到相应节点的clusterNode结构里面。因此集群里的每个节点都会知道数据库的16384个槽分别被指派给了集群里的哪些节点

17.2.3 记录集群所有槽的指派信息

clusterState结构的slots数组记录了集群里所有16384个槽的指派信息

typedef struct clusterstate(clusterNode *slots[16384];
}clusterstate;

slots数组包含16384个项,每个数组项都是一个指向clusterNode结构的指针:如果指向NULL,表示尚未指派给任何节点;如果指向一个clusterNode结构,表示槽i已经指派给了clusterNode结构所代表的节点。通过这样的记录方式,程序要检查槽i是否已经被指派,又或者取得负责槽i的节点,只需要访问clusterState.slots[i]的值即可,这个复杂度仅为O(1)

虽然clusterState.slots数组记录了集群中所有槽的指派信息,但是使用clusterNode结构的slots数组来记录单个节点的槽指派信息仍然是有必要的:因为程序需要将某个节点的槽指派信息通过消息发送给其他节点时,程序只需要将相应节点的clusterNode.slots数组整个发送出去就可以了;如果单独使用clusterState.slots数组的话,每次将节点A的槽指派信息传播给其他节点后,需要先遍历整个数组,记录节点A负责处理哪些槽,才能发送,效率低。

clusterState.slots数组记录了集群中所有槽的指派信息,clusterNode结构的slots数组记录clusterNode结构所代表的节点的槽指派信息。

17.2.4 CLUSTER ADDSLOTS命令的实现

CLUSTER ADDSLOTS 命令接受一个或多个槽作为参数,并将所有输入的槽指派给接收该命令的节点负责

def CLUSTER ADDSLOTS(*allinput slots):
#遍历所有输入槽,检查它们是否都是未指派槽
for i in all input slots:
#如果有哪怕一个槽已经被指派给了某个节点
#那么向客户端返回错误,并终止命令执行if clusterState.slots[i]!=NULL:reply error()return
#如果所有输入槽都是未指派槽
#那么再次遍历所有输入槽,将这些槽指派给当前节点
for i in all input slots:
#设置clusterstate结构的slots数组
#将slots[i]的指针指向代表当前节点的clusterNode结构clusterState.slotsi]=clusterState.myself
#访问代表当前节点的clusterNode结构的slots数组
#将数组在索引i上的二进制位设置为1setSlotBit(clusterstate.myself.slots,i)

命令执行完后,节点会通过发送消息告知集群中的其他节点,自己目前正在负责处理哪些槽

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/62706.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS4+NEXT星河版入门与项目实战(25)------UIAbility启动模式(文档编辑案例)

文章目录 1、启动模式2、Specified启动模式实现步骤3、文档编辑案例1、文件创建2代码实现3、Statge 创建4、添加配置1、启动模式 Singleton启动模式: 每个 UIAbility 只存在一个实例,是默认的启动模式,任务列表中只会存在一个相同的 UIAbilityStandard启动模式: 每次启动 U…

python股票数据分析(Pandas)练习

需求&#xff1a; 使用pandas读取一个CSV文件&#xff0c;文件内容包括股票名称、价格和交易量。完成以下任务&#xff1a; 找出价格最高的股票&#xff1b; 计算总交易量&#xff1b; 绘制价格折线图。 代码实现&#xff1a; import pandas as pd import matplotlib.pyplot …

【软考速通笔记】系统架构设计师⑨——软件可靠性基础知识

文章目录 一、前言二、软件可靠性基础概念三、软件可靠性建模方法四、软件可靠性设计4.1 容错设计4.2 检错设计4.3 降低复杂度设计4.4 系统配置设计 五、软件可靠性测试 一、前言 笔记目录大纲请查阅&#xff1a;【软考速通笔记】系统架构设计师——导读 二、软件可靠性基础概念…

鸿蒙NEXT元服务:论如何免费快速上架作品

【引言】天下武功&#xff0c;唯快不破。 本文讨论如何免费且以最快速度上架自己的作品。 作者以自己从零开始到提交发布审核一共俩小时的操作流程分享给大家作参考。 【1】立项选择 结论&#xff1a;元服务&#xff0c;单机&#xff0c;工具类&#xff08;非游戏&#xff…

el-select 修改样式

这样漂亮的页面&#xff0c;搭配的却是一个白色风格的下拉框 &#xff0c;这也过于刺眼。。。 调整后样式为&#xff1a; 灯红酒绿总有人看着眼杂&#xff0c;但将风格统一终究是上上选择。下面来处理这个问题。 分为两部分。 第一部分&#xff1a;是修改触发框的样式 第二部…

python数据分析之爬虫基础:爬虫介绍以及urllib详解

前言 在数据分析中&#xff0c;爬虫有着很大作用&#xff0c;可以自动爬取网页中提取的大量的数据&#xff0c;比如从电商网站手机商品信息&#xff0c;为市场分析提供数据基础。也可以补充数据集、检测动态变化等一系列作用。可以说在数据分析中有着相当大的作用&#xff01;…

M|两小无猜

title: 两小无猜 Jeux d’enfants time: 2024-12-01 周日 rating: 7 豆瓣: 7.9 上映时间: “2003” 类型: M爱情 导演: 杨塞谬尔 Yann Samuell 主演: 吉约姆卡内 Guillaume Canet玛丽昂歌迪亚 Marion Cotillard 国家/地区: 法国比利时 片长/分钟: 93分钟 M&#xff…

你的网站真的安全吗?如何防止网站被攻击?

你的网站被黑客攻击过&#xff0c;很可能不止一次&#xff01; 这可不是危言耸听。微软最近发布了《2024 年微软数字防御报告》&#xff0c;报告中写到&#xff1a;“Windows 用户每天面临超过 6 亿次网络犯罪和国家级别的攻击&#xff0c;涵盖了从勒索软件到网络钓鱼再到身份…

深度学习中的前向传播与损失函数

目录 ​编辑 前向传播&#xff1a;神经网络的推理过程 什么是前向传播&#xff1f; 前向传播的步骤 数学表达 代码示例&#xff1a;前向传播 损失函数&#xff1a;衡量预测与真实值的差异 损失函数的定义 损失函数的作用 常见的损失函数 代码示例&#xff1a;损失函…

【Math】奇异值分解(SVD)详解及 Python 实现

1. 什么是奇异值分解&#xff08;SVD&#xff09; 奇异值分解&#xff08;Singular Value Decomposition&#xff0c;简称 SVD&#xff09;是矩阵分解的一种方法&#xff0c;它将任意矩阵 A A A 分解为三个矩阵的乘积&#xff1a; A U Σ V T A U \Sigma V^T AUΣVT 其中&…

桶排序(代码+注释)

#include <stdio.h> #include <stdlib.h>// 定义桶的结构 typedef struct Bucket {int* data; // 动态数组int count; // 当前存储的元素个数int capacity; // 桶的容量 } Bucket;// 初始化桶 void InitBucket(Bucket* bucket) {bucket->capacity 10; // 初…

【Linux】进程控制,手搓简洁版shell

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 1、进程创建2、进程终止3、进程等待4、进程程序替换5、手写简洁版shell 1、进程创建 fork函数&#xff1a;从已经存在的进程中创…

雪花算法生成ID

下面将简单介绍雪花算法的简单应用和在web应用中的使用。 雪花算法的组成&#xff1a;雪花算法是由64位组成&#xff1a;符号位(1)、时间戳(41)、机器码(5[数据中心]5[机器ID])、计数器(12) 对于雪花算法的源码可以在这里看&#xff1a;bwmarrin/snowflake: A simple to use …

EasyDarwin搭建直播推流服务

学习链接 easydarwin官网 - 这里看介绍 easydarwin软件下载地址 - 百度网盘 easydarwin视频 B站 文章目录 学习链接使用下载EasyDarwin压缩包&#xff0c;并解压到目录启动EasyDarwin点播直播easyplayer.jsapidocffmpeg推流rtsp & ffplay拉流 使用 下载EasyDarwin压缩包…

云备份实战项目

文章目录 前言一、整体项目简介二、服务端环境及功能简介三、 客户端环境及功能简介四、服务端文件管理类的实现1. 获取文件大小&#xff0c;最后一次修改时间&#xff0c;最后一次访问时间&#xff0c;文件名称&#xff0c;以及文件内容的读写等功能2. 判断文件是否存在&#…

关于ConstarintLayout有关的点

目录 一、概述 二、过程。 1、介绍 主要特点 关键概念 使用示例 总结 2、我遇到的问题 问题&#xff1a; 可能的原因&#xff1a; 结论 一、概述 在学习过程中&#xff0c;发现对ConstarintLayout理解不够到位&#xff0c;下面是发现并解决问题过程。 二、过程。 1…

《数字图像处理基础》学习07-图像几何变换之最近邻插值法放大图像

目录 一&#xff0c;概念 二&#xff0c;题目及matlab实现 1&#xff0c;解题思路 2&#xff0c;matlab实现 1&#xff09;matlab思路 2&#xff09;完整代码 三&#xff0c;放大图像及matlab实现 一&#xff0c;概念 通过上一篇&#xff0c;我已经学习了使用最邻近插…

计网-子网划分

基于本视频观看做的笔记&#xff0c;帮助自己理解 子网掩码&#xff1a;用于识别IP地址中的网络号和主机号的位数 表示方法 第一种.32位二进制数字&#xff0c;在子网掩码中&#xff0c;网络号用”1“表示&#xff0c;主机号用”0“表示 e.g.:IP地址1.1.1.1的子网掩码是255…

【Solidity】入门指南:智能合约开发基础

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 Solidity入门指南&#xff1a;智能合约开发基础引言1. 开发环境搭建1.1 Remix I…

如何高效地架构一个Java项目

引言 Java是企业级应用开发的主流语言之一&#xff0c;而我们作为使用Java语言的程序员&#xff0c;职称有初级、中级、高级、资深、经理、架构&#xff0c;但我们往往只是慢慢通过经验的积累迭代了自己的等级&#xff0c;如果没有保持学习的习惯&#xff0c;大多数程序员会停留…