10分钟带你了解一致性hash算法_一致性hash为什么是2的32-程序员宅基地

技术标签: 算法  一致性hash  Web服务  hash  

环境描述

在了解hash算法之前先去了解一下缓存中的一个应用场景,再来理解一致性hash算法就会简单很多。

场景描述

假设,公司有三台缓存服务器,用于缓存图片,这三台缓存服务器的编号为0号,1号,2号,现在有三万张图片需要缓存,希望这么多的缓存数据能均匀的缓存到3台服务请求上去(也就是说每台机器上平均分配1万左右的数据),以便能够分摊缓存的压力

  • 此处的问题:

那么应该怎么做?如果我们没有任何规律的将3万张图片平均的缓存到3台服务器上,可不可以满足需求?

  • 答案:

可以!但是如果这么做,当我们需要访问某个和缓存选项时,则需要遍历3台服务器,从这3万个缓存项中找到需要访问的缓存,整个遍历下来的过程时间长,效率低,这样也就失去了缓存存在的价值和意义,缓存存在的目的就是提高速度,改善用户的体验,减轻后端服务器的压力,如果每次都要遍历整个缓存集群服务器,不用想都能累死.

  • 好一点的做法:

原始的做法是对缓存项的键进行hash,将hash后的结果对缓存服务器数量进行取模操作,通过取模后结果,决定缓存项要缓存在那一台服务器上,举例说明:假设以我们使用的图片名称作为访问图片的key,假设图片名称不能重复,那么我们可以使用以下公式,及计算出图片应该存放在那台服务器上。

  • 公式:hash(图片名称)% N

因为图片名称是不能重复的,所以,当我们对同一个图片名称做相同的hash运算时得出的结果应该是不变的,如果有3台服务器,使用hash运算后的结果对3取余,那么余数也一定是0、1、2,正号跟之前服务器编号相同,如果求余的结果为1,就把图片名称对应的图片缓存在1号服务器上,2就和缓存到2号服务器上,那么当我们访问任意一个图片的时候,只要再次对图片名称进行运算即可得出对应的图片应该被放在那台缓存服务器上,只需要去对应的服务器上去查找即可,如果图片在对应的服务器上不存在,证明没有被缓存(接着会把这张图片缓存在这个服务器上),也不用再去遍历其他缓存服务器了。通过此方法可以把3万图片随机分布到3台缓存服务器上,下次访问某张图片时,直接能够判断出该图片应该存放在那台缓存服务器上了。可以把上述算法称为:HASH算法还活着是取模算法

以下是运算原理图:

Alt text

但是使用上述hash算法进行缓存时会出现一些缺陷,如果3台并不能满足我们的需求时那么应该怎么做?肯定是增加几台服务器就可以了,假设我们增加1台服务器,服务器的数量由3变成了4,此时仍然用上述方法对同一张图片进行缓存,那么这张图片所在的服务器的编号必定是与原来的3台服务器所在的 编号是不同的,因为除数3变成了4,被除数不变的情况下,余数肯定不同,这情况带来的结果就是当服务器数量变动时,所有和缓存的位置都要发生改变,也就是说缓存服务器数量发生改变时,所有缓存数据在一定时间是失效的,当应用无法从缓存中和获取数据时,则会向后端服务器请求数据,同理,如果3台缓存服务器中突然有一台出现了故障,,无法进行缓存数据,那么需要移除故障机器,但是如果移除了一台缓存服务器后,数量从3变成了2,如果想访问有一张图片,这张图片缓存为位置必定发生改变,以前缓存的图片也会失去缓存的作用和意义,由于==**`大量缓存在同一时间失效,造成了缓存的雪崩(血崩),此时前端缓存已经无法起到成端部分压力的作用,后端服务器将会承担所有巨大压力,会导致整个系统可能会被压垮,==所以为了避免这类情况的发生,一致性hash算法诞生了!

  • 综合一下上述出现的问题:

第一个问题:
当缓存服务器数量发生变化时,会引起缓存的血崩,可能引起整体系统压力过大而崩溃(大量缓存同一时间失效),
第二个问题:
当缓存服务器数量发生变化时,几乎所有缓存的数据都会发生改变,怎么才能尽量减少受影响的缓存?

一致性hash算法概念

其实一致性hash算法也是取模运算,只是,上面描述的取模算法是对服务器数量进行取模,而一致性hash是对2^32取模

  • 插入小知识:
    为什么非得对2^32取余?

对232取余是有依据的IPV4最大数量就是232,所以这样就能保证所有的ip的地址进行取余时不会重复—对应hash环上面的正数。

  1. 首先把2^32想象成有一个大大的圆,就像钟表上由60个点组成的圆,如图:
    Alt text由2^32个点组成的圆环称为hash环。

圆环的正上方代表0,0点右侧第一个1以此类推2,3,4,5,6……一直到最后2^32-1。
假设我们有3台缓存服务器,服务器A,B,C,然后用他们各自的IP地址进行hash计算,使用hash后的结果改过对2^32取模。hash(服务器A的IP地址) % 2^32
通过上面的计算结果一定是一个0到232-1之间的一个整数,我们就用这个整数代表服务器A,既然这个整数肯定处于0到232-1之间,那么必定与hash环的上一个点与这个整数对应。刚才已经说明,使用这个整数代表服务器A,那么服务器A就可以映射到这个环上。

Alt text

  1. 同理服务器B和C也是相同的方法映射到hash环中
    计算公式:

hash(服务器B的IP地址) % 2^32
hash(服务器C的IP地址) % 2^32

算出结果然后将服务器映射到hash环上去。如图所示:
Alt text假设3台服务器均匀到映射到hash环上,(这是理想得到情况)

  1. 假设,我们需要使用缓存服务器缓存图片

而且仍然使用图片的名称作为找到图片的Key,那么我们使用以下公式可以将图片映射到上图中的hash环上。
hash(图片名称) % 2^32

映射后得到的结果如下图:(红点点代表图片)
Alt text
那么问题来了,图片和服务器都被映射到了hash环上,那么上图的图片到底应该缓存到那一台缓存服务器上呢?
答:

应该被缓存到A服务器上,为什么?
因为从图片开始的位置开始,沿着顺时针方向遇到的第一个服务器就是A服务器,所以会被缓存到A服务器上。如下图:

Alt text

  1. 一致性hash算法说明:

通过一致性hash算法这种方法,判断一个对象应该被缓存到那台服务器上的,将缓存服务器与被缓存对象都映射到hash环上以后,从被缓存对象的位置出发,沿着顺时针方向遇到的第一个服务器,就是当前对象将要缓存的服务器,由于被缓存对象与服务器hash后的值都是固定的,所以服务器不变的情况下,一张图片必定会被缓存到固定的服务器上,那么,当下次访问这张图片时,只要再次使用相同的算法进行计算,即可算出这张图片被缓存在那个服务器上,直接去对应的服务器上查找即可。

假设有4张图片需要缓存,如下图:
Alt text1、2图片缓存到A上,3缓存到B上,4缓存到C

一致性hash算法的优点

一致性hash算法能够解决之前出现的问题吗?如果进行简单的取模,当服务器数量发生变化时,会产生缓存的雪崩,从而导致系统崩溃,那么用一致性hash能够避免这个问题吗?

  1. 继续模拟测试实验!!
    假设服务器B出现故障,需要移除B,如下图:
    Alt text
    在服务器B没有移除时,图片3应该缓存到B中,可是移除后,按照一致性hash算法是规则,3应该被缓存到C中,因为从3的位置顺时针除法遇到的第一个服务器节点是C,也就是说如果B出现故障移除后,3的缓存位置发生改变。
    Alt text
    这里的一致性hash算法的优点就体现出来了!
    图片4依然会被缓存到C中,图片1和2突然缓存到A中,与移除B之前没有任何区别,这就是优点!

1)如果使用hash算法:当服务器数量发生改变时,所有的服务器缓存在同一时间失效了
2)而使用一致性hash算法:服务器数量发生改变时,并不是所有都会失效,而只有部分缓存失效,前端的缓存仍然能分担整个系统的压力,而不至于所有压力都在同一个时间集中到后端服务器上。

hash环偏斜问题

在最开始介绍概念年的时候,说的是在理想的情况下是**均匀的分布到hash环上!**如下图
Alt text
但是理想是很丰满的,我们想象的和现实往往是不同的!
Alt text
在实际映射中,服务器可能会被映射成一下模样
Alt text
那么被缓存的对象很有可能大部分集中缓存到某一台服务器上如下图:
Alt text

图上2、3、4、5、6、都很会存储到A服务器上,1会存到B上,C服务器一张也没有,三台服务器并没有合理的平均充分的利用,缓存分布极度不均匀,重要的是如果A出现故障,会导致失效的数量也将达到最大值。在极端的情况下依然会出现系统崩溃的问题!

以上情况被称之为hash环偏斜,那么如何防止hash环偏斜呢?

虚拟节点

“虚拟节点”是“实际节点”(实际的物理服务器)在hash环上的复制品,一个实际节点可以对应多个虚拟节点。如下图:
Alt text
ABC三台服务分别虚拟出一个虚拟节点(也可以虚拟出更多的虚拟节点)引入虚拟节点的概念后,缓存的分布就均衡的多了,上图中3、4、5、的图片都被放到了节点A中如果不放心可以虚拟出更多的虚拟节点,以便减少hash环偏斜所带来的影响,虚拟节点越多,hash环上的节点就越多,缓存均匀分布的概率就越大!!!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_34672033/article/details/88916789

智能推荐

python色卡识别_用Python帮小姐姐选口红,人人都是李佳琦-程序员宅基地

文章浏览阅读502次。原标题:用Python帮小姐姐选口红,人人都是李佳琦 对于李佳琦,想必知道他的女生要远远多于男生,李佳琦最早由于直播向广大的网友们推荐口红,逐渐走红网络,被大家称作“口红一哥”。不可否认的是,李佳琦的直播能力确实很强,他能够抓住绝大多数人的心理,让大家喜欢看他的直播,看他直播推荐的口红适不适合自己,色号适合什么样子的妆容。为了提升效率,让自己的家人或者女友能够快速的挑选出合适自己妆容的口红色号,今..._获取口红品牌 及色号,色值api

linux awk命令NR详解,linux awk命令详解-程序员宅基地

文章浏览阅读3.6k次。简介awk命令的名称是取自三位创始人Alfred Aho 、Peter Weinberger 和 Brian Kernighan姓名的首字母,awk有自己的程序设计语言,设计简短的程序,读入文件,数据排序,处理数据,生成报表等功能。awk 通常用于文本处理和报表生成,最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。awk 通常以文件的一行为处理单位..._linux awk nr

android 网络连接失败!failed to connect to /192.168.1.186(port 8080)_failed to connect to 192.168.88.218:80-程序员宅基地

文章浏览阅读1.3w次,点赞5次,收藏2次。在网上找了一个小时,一直没有头绪,因为上个星期还是好好的,最后看到一个大神的解答,只需要将防火墙关闭就好了.原本向测试功能的,却卡在了登录上.以此记录.另外好像还有种错误是电脑与手机连接的WiFi不同,也可以看看...._failed to connect to 192.168.88.218:80

matlab 多径衰落,利用MATLAB仿真多径衰落信道.doc-程序员宅基地

文章浏览阅读1.9k次。利用MATLAB仿真多种多径衰落信道摘要:移动信道的多径传播引起的瑞利衰落,时延扩展以及伴随接收过程的多普勒频移使接受信号受到严重的衰落,阴影效应会是接受的的信号过弱而造成通信的中断:在信道中存在噪声和干扰,也会是接收信号失真而造成误码,所以通过仿真找到衰落的原因并采取一些信号处理技术来改善信号接收质量显得很重要,这里利用MATLAB对多径衰落信道的波形做一比较。一,多径衰落信道的特点关于多径衰落..._matlab多径衰落工具箱

python对json的操作及实例解析_import json灰色-程序员宅基地

文章浏览阅读1w次,点赞2次,收藏17次。Json简介:Json,全名 JavaScript Object Notation,是一种轻量级的数据交换格式。它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。(来自百度百科)python关于json文_import json灰色

mysql实现MHA高可用详细步骤_mysql mha超详细教程-程序员宅基地

文章浏览阅读1.1k次,点赞6次,收藏3次。一、工作原理MHA工作原理总结为以下几条:(1) 从宕机崩溃的 master 保存二进制日志事件(binlog events);(2) 识别含有最新更新的 slave ;(3) 应用差异的中继日志(relay log) 到其他 slave ;(4) 应用从 master 保存的二进制日志事件(binlog events);(5) 通过Manager控制器提升一个 slave 为新 m..._mysql mha超详细教程

随便推点

Linux环境下主从搭建心得(高手勿喷)_linux的java主从策略是什么-程序员宅基地

文章浏览阅读194次。一 java环境安装:1 安装JDK 参考链接地址:https://blog.csdn.net/qq_42815754/article/details/82968464注:有网情况下直接 yum 一键安装:yum -y list java(1)首先执行以下命令查看可安装的jdk版本(2)选择自己需要的jdk版本进行安装,比如这里安装1.8,执行以下命令:yum install -y java-1.8.0-openjdk-devel.x86_64(3)安装完之后,查看安装的jdk 版本,输入以下指令_linux的java主从策略是什么

ACM第四题_acm竞赛题 i 'm from mars-程序员宅基地

文章浏览阅读104次。定义int 类型,由while实现A,B的连续输入,输出A+B的值按Ctrl Z结束循环。#include<iostream>using namespace std;int main(){ int A,B; while(cin>>A>>B) { cout<<A+B<&_acm竞赛题 i 'm from mars

TextView.SetLinkMovementMethod后拦截所有点击事件的原因以及解决方法-程序员宅基地

文章浏览阅读5.2k次。在需要给TextView的某句话添加点击事件的时候,我们一般会使用ClickableSpan来进行富文本编辑。与此同时我们还需要配合 textView.setMovementMethod(LinkMovementMethod.getInstance());方法才能使点击处理生效。但与此同时还会有一个问题:如果我们给父布局添加一个点击事件,需要在点击非链接的时候触发(例如RectclerV..._linkmovementmethod

JAVA实现压缩解压文件_java 解压zip-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏31次。JAVA实现压缩解压文件_java 解压zip

JDK8 新特性-Map对key和value分别排序实现_java comparingbykey-程序员宅基地

文章浏览阅读1.3w次,点赞7次,收藏21次。在Java 8 中使用Stream 例子对一个 Map 进行按照keys或者values排序.1. 快速入门 在java 8中按照此步骤对map进行排序.将 Map 转换为 Stream 对其进行排序 Collect and return a new LinkedHashMap (保持顺序)Map result = map.entrySet().stream() .sort..._java comparingbykey

GDKOI2021普及Day1总结-程序员宅基地

文章浏览阅读497次。第一次参加GDKOI,考完感觉还可以,结果发现还是不行,有一些地方细节打错,有些失分严重,总结出以下几点:1.大模拟一定要注意,细节打挂就是没分,像T1就是一道大模拟题,马上切了,后面就没想着检查以下,导致有些地方挂掉了,用民间数据一测,才85分。2.十年OI一场空,不开longlonglong longlonglong见祖宗。今天的T2本来想用暴力水点分的,结果没想到longlong→intlong long\to intlonglong→int,40→040\to040→0。3.代码实现能力太差,_gdkoi

推荐文章

热门文章

相关标签