Hash一致性算法(笔记六)

浅谈一致性hash算法

我们在使用Redis的时候,为了保证Redis的高可用,提高Redis的读写性能,最简单的方式我们会做主从复制,组成Master-Master或者Master-Slave的形式,或者搭建Redis集群,进行数据的读写分离,类似于数据库的主从复制和读写分离。

为什么要有hash一致性算法?先抛出一个场景:假如我们现在使用的是redis集群,这个时候我们有三个节点,NodeA,NodeB,NodeC,假如我们没有按任何的规则存储数据在这三个节点中,那么当我们需要查找具体的一个key时,则需要将这三个节点全部都去查询一遍,这样效率就会很低了,很明显的不行。(假设现在有200万张图片资源,需要随机的分配到3台服务器)

取余法:很多人一下子就想到了除余法,通过给每个图片唯一编号(较少的情况),或者通过hash文件名(假设文件名不重复)得到唯一的数字串,然后除余就能随机存放到服务器。

hash(文件名) % n

例如我们将hash(key)%3这样来将具体的Key路由到某一个节点,这样当我们下次需要去查某一个Key时,可以同样的按照hash(key)%3来直接去对应的节点去取出数据,貌似到现在为止,似乎解决了我们前面儿说的需要遍历所有节点的问题,但是一个问题解决了,另一个问题又来了,例如当我们的应用数据越来越多时,我们可能会加一台机器,这个时候按照路由规则hash(key)%4,那么之前存储的key就找不到了或者当某一台机器宕机了,我们需要从集群中剔除掉这台机器,也会导致路由变成hash(key)%2,同样也会导致找不到之前的key了

一致性hash原理(分布式缓存扩容定位引入的一种hash算法):

上面我们说将一个key经过hash算法后会取余节点数,而hash一致性算法中,是取余2的32次方,然后组成一个环,称为hash环

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BYkmqsMj-1632391915256)(C:\Users\涛大爷的笔记本\AppData\Roaming\Typora\typora-user-images\image-20210829101458488.png)]

其他节点也按照取余2的32次方,让它们均匀的分布在hash环上.可以按照节点的ip进行hash或者其他的方式,例如我们有三个节点,结果可能是下面这样.

**[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9M4BEwBg-1632391915260)(C:\Users\涛大爷的笔记本\AppData\Roaming\Typora\typora-user-images\image-20210829102205822.png)]**

然后如果我们要存储具体的key或者取对应的Key时,同样要将hash(key)%2^32,让key分布在hash环上.如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YwPznH6X-1632391915262)(C:\Users\涛大爷的笔记本\AppData\Roaming\Typora\typora-user-images\image-20210829101524016.png)]

按照hash一致性算法,存储key的将是按照顺时针行走,离key最近的节点负责存储具体的key,keyA将存储在NodeA上,keyB将会存储在NodeB上,keyC将会存储在NodeC上。

例如现在我们的NodeB节点宕机了,如下图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cAGrE9lK-1632391915264)(C:\Users\涛大爷的笔记本\AppData\Roaming\Typora\typora-user-images\image-20210829101919439.png)]

按顺时针迁移的规则,这个时候keyA和keyC都不会受影响,但是keyB这个时候会路由到NodeC,所以受影响的只是NodeA到NodeB之间的一部分。映射在NodeB中的数据回存到NodeC中,添加节点也是一样,新添加的节点会导致原来映射到后一个节点的数据映射到自己,受影响的数据仅仅是新服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据

只会有部分区域受影响。所以hash一致性算法并没有完全的一致性算法,它只是扩大取余的基数,然后使受影响的数据范围减少而已。

hash一致性算法还可能会有分布不均匀的情况,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-608oghvT-1632391915266)(C:\Users\涛大爷的笔记本\AppData\Roaming\Typora\typora-user-images\image-20210829102131088.png)]

大部分的key都会跑到NodeA上,就会导致数据倾斜的问题了。采用虚拟节点的方式来解决这个问题。例如将NodeA虚拟出三个节点NodeA#1,NodeA#2,NodeA#3,NodeB#1,NodeB#2,NodeB#3,然后将虚拟节点让它们分布在hash环上。如下图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GU009c60-1632391915268)(C:\Users\涛大爷的笔记本\AppData\Roaming\Typora\typora-user-images\image-20210829102750823.png)]

虚拟节点就会较均匀的分布在hash环上,当我们选择了某一个虚拟节点之后,再将虚拟节点映射到真实节点上即可,例如NodeA#2,映射到真实节点NodeA上,这样就可以避免数据倾斜的问题了。

总结:在移除 / 添加一个 cache 时,它能够尽可能小的改变已存在 key 映射关系,尽可能的满足单调性的要求。

存储key的将是按照顺时针行走,离key最近的节点负责存储具体的key

节点宕机了,部分区域受影响**。所以hash一致性算法没有完全的一致性算法****,它只是扩大取余的基数,使受影响的数据范围减少

缺点:比较复杂,实现复杂,维护也复杂,所以我们推荐应用一开始尽量优先选用对key取余的算法进行扩容,当集群到达一定规模之后,我们可以做一张如上的虚拟节点映射表,将原来的取模算法平滑的切换为虚拟节点算法,对应用没有任何影响,然后再按照虚拟节点的方式进行扩容,这是我们最推荐的方式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值