分布式Redis(14)哈希槽

news2024/11/15 12:33:37

文章目录

  • 一致性哈希算法
    • 理论
    • 普通哈希的问题
    • 一致性hash算法
  • Redis 使用哈希槽
    • Redis Cluster集群
  • 为什么Redis是使用哈希槽而不是一致性哈希呢?
  • 为什么Redis Cluster哈希槽数量是16384?

关键词:一致性 Hash,哈希槽,

带着问题阅读

  1. 一致性 Hash 的增删节点操作原理
  2. 如何防止增删节点导致连接不平衡问题
  3. 哈希槽和一致性 Hash 的不同之处以及优点
  4. 哈希槽为什么使用 16384 个

一致性哈希算法

理论

一致性哈希算法是一种常用的分布式算法,其主要用途是在分布式系统中,将数据根据其键(key)进行散列(hash),然后将散列结果映射到环上,再根据数据节点的数量,将环划分为多个区间,每个节点负责处理环上一定区间范围内的数据。

普通哈希的问题

分布式集群中,对机器的添加删除,或者机器故障后自动脱离集群这些操作是集群管理最基本的功能。如果采用常用的hash(object)%N取模的方式,在节点进行添加或者删除后,需要重新进行迁移改变映射关系,否则可能导致原有的数据无法找到。

举个栗子
随着业务和流量的增加,假如我们的Redis查询服务节点扩展到了3个,为了将查询请求进行均衡,每次请求都在相同的Redis中,使用hv = hash(key) % 3的方式计算,对每次查询请求都通过hash值计算,得出来0、1 、2的值分别对应服务节点的编号,计算得到的hv的值就去对应的节点处理。
在这里插入图片描述

但是这里有个问题,服务增减是需要对此时的key进行重新计算,比如减少一个服务的时候,此时需要按 hv = hash(key) % 2计算,而增加一个服务节点的时候需要按hv = hash(key) % 4计算,而这种取模基数的变化会改变大部分原来的映射关系,导致数据查询不到
在这里插入图片描述

这个时候只能进行数据迁移,真是太麻烦了,而一致性哈希算法显然是一个更好选择!

一致性hash算法

一致性哈希同样使用了取模的方式,不同的是对 2^32 这个固定的值进行取模运算。
在使用一致哈希算法后,哈希表槽位数(大小)的改变平均只需要对 K/n 个关键字重新映射,其中K是关键字的数量, n是槽位数量,而不需要对所有的映射关系进行重新映射!

Hash环
我们可以把一致哈希算法是对 2^32 进行取模运算的结果值虚拟成一个圆环,环上的刻度对应一个 0~2^32 - 1 之间的数值,如下图:
在这里插入图片描述
节点入环

在这里插入图片描述
不平衡问题
我们通过新增节点和删除节点,知道了该方式会影响该节点的顺时针的后一个节点,其他节点不受影响。
但是因为生成哈希值的分布并不是均匀的,如下图新增k4、k5,如果节点B宕机了,k2和k4也迁移到节点C,导致那么大部分请求就落到节点C了,如果数量更多呢,此时会导致节点C压力陡增,这样就不均衡了!
在这里插入图片描述

那如何解决这个问题呢?那就是通过 虚拟节点
虚拟节点
虚拟节点 可以理解为是作为实际节点的一个copy,多个虚拟节点映射一个实际节点,因为在哈希环上节点越多就分布的越均匀,即使我们现实中不会有那么多真实节点。
在这里插入图片描述

上图中三个真实节点A、B、C,映射了9个虚拟节点,如果key值经过哈希落到临近A-1、A-2、A-3的虚拟节点,那么最终都将映射到真实节点A,你想如果虚拟节点再多点,是不是就会更均衡了!
假设真实节点A被移除,A对应虚拟节点也会移除,但是多虚拟节点方式可以映射更多真实节点,让剩余的节点更好得去承担节点变化的请求压力!
如下图:
在这里插入图片描述
这里简单讲解一下,图中真实节点A被移除,那么对应的虚拟节点移除,那么此时k1的重新映射到C-1、k3重新映射到B-3,也就是说被迁移到真实节点B和C,由此可见节点被移除会被更均衡的分散到其他节点上。图中只简单列举了几个虚拟节点,虚拟节点越多,相对会越均衡。

Redis 使用哈希槽

不知道朋友们记不记得Redis Cluster的实现,也是用了Hash的方式将键值按照一定算法分配到各个节点的,但是却没有使用一致性哈希算法,而是引入了哈希槽的概念!
这是为什么呢?我们先看下一致性哈希和哈希槽在计算上的区别
在这里插入图片描述
图中A、B、C表示的是三个节点,k1和k2表示的是key:一致性哈希是经过 hash() 函数计算后对 2^32 取模的值虚拟成一个圆环
哈希槽是将每个key通过CRC16计算得到一个16bit的值,然后16bit值再对16384取模来决定放置哪个槽
虽说在计算方式上有区别,好像都解决了数据均衡的问题,应该都是不错的选择。
OK,本文将先对Redis集群节点增减时如何进行哈希槽的分配进行分享,再回过头看为什么Redis 集群没有使用一致性hash,而是引入了哈希槽的概念的原因究竟是什么!

Redis Cluster集群

Redis集群是一种分布式数据库方案,通过服务器分片技术进行数据管理,我们来对它进行一个归纳总结。

哈希槽
集群将数据划分为 16384 (2^14)个槽位(哈希槽),每个Redis服务节点分配了一部分槽位,因为槽位的信息存储于每个节点中,客户端请求的key通过CRC16校验后对16384取模来决定放置哪个槽,这样也就定位到指定的节点中。
在这里插入图片描述
上图中 key 【小许】和【code】经过 CRC16 计算后再对哈希槽总个数 16384 取模,得到哈希槽位置分别是在888的节点A上和10924的节点C上面。
重点:每个节点都会记录哪些槽分配给了自己,哪些槽被分配给了其他节点

增加节点

新增一个节点D,redis cluster的这种做法是从各个节点的前面各拿取一部分slot(槽)到D上,会变成这样:
在这里插入图片描述
此时服务A、B、C、D通过分配各自有了对应的哈希槽,新增节点后集群会自动进行哈希槽的重新平均分配,比如上图中四个节点中每个节点的槽位数是:18384 / 4 = 4096。
当然这个你使用命令 【cluster addslots】为每个节点自定义分配槽的数量,这里有个特点,如果我们节点的机器性能有差异,那就可以为性能好的,配置更多槽位,更好的利用机器性能。

减少节点
如果减少一个节点C,redis cluster同样会自动进行槽数量的重新计算分配,然后后变成下面样子:
在这里插入图片描述
删除节点C之后,此时服务A、B节点中每个节点的槽位数是:18384 / 2 = 8192

客户端访问节点数据
Redis cluster的主节点各自负责一部分槽,我们来看下来自客户端的请求的key是如何定位到具体的节点,然后返回对应的数据的。
在这里插入图片描述
来自Redis-Cli客户端的请求连接到的是集群中的任何一个节点
● 首先检查当前key是否存在集群中的节点
● 通过CRC16(key)/ 16384计算出slot
● 查询负责该slot负责的节点是否存在
● 在该节点的话就直接就直接返回key对应的结果
● 不在该节点的话,那么会 MOVED重定向(包含槽位和目标地址)指引客户端转向至正确的节点,并再次发送之前执行的命令

为什么Redis是使用哈希槽而不是一致性哈希呢?

有人可能会说是当节点太少时,一致性哈希容易数据分布不均匀更容易导致雪崩。
但是看过我开头分享的一致性哈希文章,通过引入虚拟节点是基本可以避免这个问题的
如果非要说极限情况,那么Redis哈希槽,也有可能某些hash 区间的值特别多,然后导致该节点导访问过于集中的问题。
抛开这些极端情况,通过上面对哈希槽的总结,以下这些是更值得信服的回答:

  • 当发生扩容时候,Redis可配置映射表的方式让哈希槽更灵活,可更方便组织映射到新增server上面的slot数,比一致性hash的算法更灵活方便。
  • 在数据迁移时,一致性hash 需要重新计算key在新增节点的数据,然后迁移这部分数据,哈希槽则直接将一个slot对应的数据全部迁移,实现更简单
  • 可以灵活的分配槽位,比如性能更好的节点分配更多槽位,性能相对较差的节点可以分配较少的槽位

为什么Redis Cluster哈希槽数量是16384?

我们知道一致性哈希算法是对2的32次方取模,而哈希槽是对2的14次方取模
Redis作者认为这样做不太值得;并且一般情况下一个redis集群不会有超过1000个master节点,所以16k的槽位是个比较合适的选择。
Redis作者的回答在这里:why redis-cluster use 16384 slots? · Issue #2576 · redis/redis
在这里插入图片描述
总结起来主要有以下因素

  • Redis节点间通信时,心跳包会携带节点的所有槽信息,它能以幂等方式来更新配置。如果采用 16384 个插槽,占空间 2KB (16384/8);如果采用 65536 个插槽,占空间 8KB (65536/8)。
  • Redis Cluster 不太可能扩展到超过 1000 个主节点,太多可能导致网络拥堵。
  • 16384 个插槽范围比较合适,当集群扩展到1000个节点时,也能确保每个master节点有足够的插槽
    这也就是为什么哈希槽的数量是16384了!

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

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

相关文章

双指针算法详解

什么是双指针 双指针算法是一种常用的算法策略,通常用于处理有序数组或链表,能够高效地解决许多问题。其核心思想是通过维护两个指针在数组或链表中移动,从而达到减少时间复杂度的目的。我们将通过三个示例代码来深入了解双指针算法的…

《动手学深度学习》笔记2.2——神经网络从基础→进阶 (参数管理-每层的权重/偏置)

目录 0. 前言 正文:参数管理 1. 参数访问 1.1 [目标参数] 1.2 [一次性访问所有参数] 1.3 [从嵌套块收集参数] 2. 参数初始化 2.1 [内置初始化] 2.2 [自定义初始化] 2.3 [参数绑定-共享参数] 3. 小结 4. 练习 0. 前言 课程全部代码(pytorch版…

echarts地图的简单使用

echarts地图的简单使用 文章说明核心源码效果展示源码下载 文章说明 主要介绍echarts地图组件的简单使用,记录为文章,供后续查阅使用 目前只是简单的示例,然后还存在着一些小bug,主要是首个Legend的点击会导致颜色全部不展示的问题…

笔试编程-百战成神——Day02

1.简写单词 题目来源: 简写单词——牛客网 测试用例 算法原理 本题的主要难点就是如何识别每一个单词并且返回其首字母大写,最终组成一个新的字符串后输出,这里我们使用while(cin>>str)就可以解决,直接忽略每一个空格直接…

深入理解及如何使用main函数参数

目录 前言:一、main函数参数二、main函数参数的意义及如何使用三、从操作系统层面(指令)理解main函数参数 前言: 在平时编写代码的过程中,我们会经常写main函数,这是一个程序必不可少的,main 函…

信息汇总(避坑)系统

本系统前期设定为公司避坑系统,在此基础上衍生出公司信息汇总功能 主要功能点:避坑分类、标签、随笔记录、阅读人数、评论(用户评论、匿名评论,评论回复等)、系统留言(支持表情留言)、避坑信息…

JavaScript中的无穷大

JavaScript中的无穷大 溢出:overflow,数字结果超过JS表示的数字上限,结果为一个特殊的无穷大Infinity或负无穷大-Infinity. 下溢:underflow是当前结果无限接近于0比JS能表示的最小值还要小,将会返回0,负数下溢就是-0…

剑指offer JZ7 重建二叉树

描述: 给定节点数为 n 的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。 思路: 这道题考察的是二叉树根据先序…

蓝桥杯备赛---引言

我是来自成都锦城学院的2021级学生,第一次参加第十五届蓝桥杯嵌入式赛道获得了国二的名次,接下来将为大家分享各个模块的代码,可以速成省一,但想要取得国一的成绩则需要补偿数据结构、基本c语言函数等相关知识,很遗憾没…

C++ 创建型设计模式

何为设计模式 设计模式是指在软件开发中,经过验证的,用于解决在特定环 境下,重复出现的,特定问题的解决方案; 设计原则 依赖倒置 开放封闭 一个类应该对扩展(组合和继承)开放,对…

犀牛检测系统源码分享

犀牛检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

N诺计算机考研-错题

B A.LLC,逻辑链路控制子层。一个主机中可能有多个进程在运行,它们可能同时与其他的一些进程(在同一主机或多个主机中)进行通信。因此在一个主机的 LLC子层的一个服务访问点,以便向多个进程提供服务。B.MAC地址,称为物理地址、硬件地址,也称为局域网地址,用来定义网络设…

python与html链接测试

做这个测试我使用了两个资源 1.csdn上收集的参考资料,特此感谢 链接如下:Pycharm社区版创建Flask项目(配置项目文件)_pycharm community flask-CSDN博客 2.kimi 网址如下:Kimi.ai - 帮你看更大的世界 (moonshot.cn) 这是试出来的操作步骤…

python如何查看文件的目录

1、sys.arg[0]: import sys print(sys.argv[0])#当前脚本的位置 输出结果: G:/Pythonxx/test.py 2、os模块 import os print("1111") print (os.getcwd())#获得当前目录 print (os.path.abspath(.))#获得当前工作目录 print (os.path.abspath(..))#获得当…

基于丹摩智算部署可图(Kolors)

🍑个人主页:Jupiter. 🚀 所属专栏:Linux从入门到进阶 欢迎大家点赞收藏评论😊 目录 丹摩智算平台简介一、Kolors 简介介绍技术背景部署与使用前提条件 二、DAMODEL 平台创建适配机器1.1、实例创建 三、服务部署安装 An…

性能测试利器 - Locust框架解析

01 认识Locust 说起性能测试工具,大家肯定想到的都是Jmeter,是的,由于其简单易用、功能强大,已经变成主流的压测工具之一。当需要实现一些高级功能的时候,可以使用Java语言对Jmeter进行扩展。 但是很多小伙伴只会Pyt…

10种数据库技术的发展历程与现状

数据库是互联网的基石,存储着海量信息,使信息可被高效地组织、检索和分享。没有数据库,网站无法记忆用户数据,应用无法提供个性化服务,信息交流将失去智能与连贯性。因此,数据库技术极大地推动了互联网的发…

如何使用 Windows 自带的虚拟机 Hyper-V

当前环境: Windows 10 Pro 开启 Hyper-V 功能 开启 Hyper-V 功能 开始菜单, 搜索 “control” 打开控制面板点击 “程序” > “启用或关闭 Windows 功能”开启所有的 Hyper-V 选项 安装虚拟机 准备系统镜像 .iso 文件 进入 itellyou.cn 进行下载所需镜像我选择的是: Wind…

nginx部署手册

1、在安装nginx前首先要确认系统中安装了gcc、pcre-devel、zlib-devel、openssl-devel yum -y install gcc pcre-devel zlib-devel openssl openssl-devel2、 新建nginx用户 (1)groupadd 命令用于创建一个新的用户组 groupadd nginx(2&#…