图解一致性哈希算法,一篇就吃透!

哈希的基础知识

在了解一致性哈希算法之前先介绍下哈希的基础知识,有助于后续进阶到具体算法的理解

哈希

哈希(Hash)也称为散列,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,这个输出值就是散列值。

哈希表

哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表

哈希算法

在介绍一致性哈希算法之前先看简单的取模哈希算法

场景:假设现在有三台服务器(分别编号A、B、C)和3000w个key,需要将3000w个key能均匀的分布在这三台机器上,可能想到的方案是 取模算法 hash(key)%n 即:对key进行hash运算后取模,N是服务器的数量

这样对3取模之后的结果一定是 0、1、2,可以分别对应机器A、B、C 刚好达到数据的均匀分布

当需要查询目标数据时,也是通过同样的hash算法定位数据存储的目标服务器:

  1. 计算hash值
  2. 取模
  3. 定位目标服务器

局限

当业务流量突增数据变多,三台服务器已经无法承载量级时,就需要增加服务器数量,服务器数量从3变成了4,那么hash函数就变成了:hash(key)%4,此时再看上述场景,计算后得到的目标服务器大多数都会发生变化,之前缓存的数据就会失效。如下图:

此时就需要将所有缓存数据做迁移, 当大量缓存在同一时间失效,包含非常多热点数据,则会造成缓存雪崩,进而导致整个系统的不可用,这是绝对无法接受的!

如上述的集群扩容,集群收缩也是同样的情况,所以这种对机器数量取模的hash函数,在集群扩容和收缩时都有非常大的局限性,为了解决该问题,一致性哈希算法应运而生~

一致性哈希算法

一致性哈希算法本质上也是取模,不过不是对服务器的数量取模,而是对固定值(2^32)进行取模 : hash(key)%2^32

IPv4的地址是4组8位2进制数组成,所以用2^32可以保证每个IP地址会有唯一的映射;

2^32 抽象成一个环,即hash环:存储节点和数据都会经过hash函数映射到这个收尾相连的hash环中

一致性hash需要有两步hash:

  • 对存储节点做hash,也就是对存储数据的服务器的ip地址做哈希,均会落入哈希环中(上面也讲过用2^32可以保证每个ip地址都会有唯一的映射)
  • 对要存储的数据做hash,无论是数据的存储还是访问,都需要进行这一步骤

假设现在有三个节点,经过hash计算,映射到如下hash环中:

❓❓❓如何确定存储某个数据或访问某个数据的节点?

  1. 对key进行哈希计算出在哈希环中的位置
  2. 沿此位置顺时针找到第一个节点,即就是存储该key的服务器节点

假设数据key1、key2、key3经过hash函数计算之后落入哈希环的如下位置,那么按照如上描述的寻址策略则:

key1->节点A,key2->节点B,key3->节点C

如何解决集群扩容和收缩时数据迁移的问题?

❓❓❓ 那么当集群扩容和收缩时,在该算法下就不会有数据失效?完全不用迁移数据吗?

结论先行:仍然需要迁移数据,不过并不是所有数据失效需要迁移,只是一部分数据需要迁移处理,只会影响哈希环上顺时针相邻的后继节点

📢📢📢扩容:当现在新增节点D时,如下图所示,只会将key2迁移至节点D上,为啥需要这样迁移?

迁移规则还是遵从上述的寻址规则,key2会沿着顺时针找到第一个节点就确定为其的数据存储结点,当新增节点D后,就会去节点D中查询key2数据,但是key依然存储在节点B中,所以需要将key2数据从节点B迁移到节点D中

📢📢📢收缩:当下线节点B时,如下图所示,只会将key2迁移至节点C上,迁移规则何扩容同理

如何提高均衡度?

引入哈希算法是为了实现数据的均衡分配,但是当节点过少时,就会出现如下图所示的严重不均衡:

这种虽然有三个节点,但所有数据都存储在节点C上,一点也不均衡,当集群扩容或收缩时,受影响的数据过多,相当于退化为了普通哈希,如果节点C被移除了,那么根据规则节点C上的数据就会迁移到节点B上,若数据量过多超过了节点B的处理上限,那么节点B就会出问题,以此类推可能出现一连串的系统瓶颈问题,直到整个系统瘫痪

其实这个问题只有当节点过少的时候才会出现,如果节点很多,那么节点在整个hash环上的分布就会比较均匀,那么数据的分布也会变得均衡,所以就需要加入大量的节点,但在实际场景中,很难避免节点很多的情况,所以就加入了虚拟节点,即真实节点的副本

不再将真实节点映射到哈希环上,而是将虚拟节点映射到哈希环上,虚拟节点再映射到真实节点上,所以这里有两层映射关系:真实节点 <-> 虚拟节点 <-> 哈希环

数据寻址步骤:数据 -> 哈希环 -> 虚拟节点 -> 真实节点

比如对每个节点分别设置 3 个虚拟节点:

  • 对节点 A 加上编号来作为虚拟节点:A1、A2、A3
  • 对节点 B 加上编号来作为虚拟节点:B1、B2、B3
  • 对节点 C 加上编号来作为虚拟节点:C1、C2、C3

如图所示,通过增加虚拟节点即可使得节点均匀的分布在哈希环上,从而使得数据均匀分配。

另外我设置3个虚拟节点只是举个栗子,在大部分实际场景中,3个还是远远不够的,请大家以实际应用场景而定

  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值