天天看点

的一致性哈希_深入..浅出的谈谈一致性哈希算法

今天,洪爵来跟大家聊聊一致性哈希。大概从以下几个角度去进行什么是一致性哈希?为什么会出现这种算法?它是为了解决什么样的问题。

我们先来列举个例子:

请求的处理流程

我们知道前台的一个请求发送到了后台,后台会先从缓存中去取数据,如果取到了对应的数据就将结果返回,否则会去查询数据库,然后将获取到的数据放进缓存中,再返回结果(图1):

的一致性哈希_深入..浅出的谈谈一致性哈希算法

为了减少查询数据库所带来的的磁盘IO,有许多中间件应运而生,比如说几乎所有招聘后台开发工程师的岗位要求中都写有需要掌握Redis。通过把数据放入内存中,例如以形式存储数据,以达到能快速的返回用户所需要的信息。

假设一开始这个系统的用户量并不大,用来当做缓存的服务器只有一台;但是当用户的体量上来的时候,一台缓存服务器是不足以支撑处理用户的请求的,发生宕机的情况也是常有,从而连锁反应的导致缓存服务器宕机,用户的请求全部压到了磁盘数据库层面上,毫无疑问的数据库支撑不了多久也会挂掉。

这个时候你可能会想到使用多个缓存服务器嘛,通过负载均衡把请求均匀的打在每一个服务器上,但是这样的话,每一个缓存服务器上的数据都是一样的,而且当我们想要缓存的数据比服务器的内存还要大的时候,可能是因为实时性要求比较高的场景之类,我们需要存每个用户的一些信息。如果用户体量非常大,无疑一台服务器的内存根本容不下。

简单哈希

那我们有没有一种办法,就是让每台服务器都储存不一样的数据,然后我请求的时候就找特定的一个服务器进行访问呢?(最暴力的就是每个缓存服务器都去访问一遍,看看想要查找的key是不是为null,但是无疑增加了网络传输的时间,并且每次都这样轮询,那么其实和单台服务器没什么差别)

通过简单的哈希算法,我们能够实现这一点,和Java中的HashMap类似,例如现在有3台缓存服务器,我们取名为C0,C1,C2。现在我们把需要缓存的数据的key通过哈希算法拿到它的哈希值,然后对这个哈希值进行取模,有几台服务器就取几台,那么现在是有三台服务器,那么我们就把哈希值模3,即

key.hashValue % 3

得到的值如果是0,那么我们就把数据放到C0服务器,如果是为1则把数据放到C1服务器,以此类推(图2):

的一致性哈希_深入..浅出的谈谈一致性哈希算法

看到这里,你可能眼前一亮,这是个好办法呀!但是如果我现在新添加一台服务器呢?

那么我们就需要对key的哈希值和4进行取模操作,并且之前的key和3进行取模而映射到了C0,C1,C2服务器上,但是现在

key.hashValue % 3 和 key.hashValue % 4

这两个值很大概率是不会一样的,也就是说,我们需要对所有的key进行取模,重新映射到每一台机器上,但是以后我要新增一台服务器,或者减少一台服务器都需要大动干戈的进行数据移动,这代价无疑非常高,所以一致性哈希算法就应运而生啦。

一致性哈希算法

我们考虑能不能设计一种算法,在你新增加或者删除一个服务器节点的时候,绝大多数的记录原来分配在哪一个节点,现在还是应该被分配到那一个节点,这样的话,我们就能将数据的移动数量降到最低,这就是一致性哈希算法的思想。

我们之前的简单哈希算法是对服务器节点的数量进行取模,但是一致性哈希算法跳出了这个思想,它是对

2^32

这个数字进行取模,可能你还不是很明白,我们简单画一个图你就了解了(图3)。

的一致性哈希_深入..浅出的谈谈一致性哈希算法

2^32

进行取模,我们的取值范围是:0 - 2^32-1,每一个数代表了一个个节点,我们把这个环叫做哈希环。

现在我们把服务器节点也进行哈希,按照自定义的规则也好,或者单单对服务器的ip地址进行哈希也好,得出来的哈希值取模会落在哈希环的节点上,例如我们得到了这样的一个哈希环(图4):

的一致性哈希_深入..浅出的谈谈一致性哈希算法

接下来我们把要缓存数据的key进行哈希,哈希取模过后的值我们也映射到哈希环上的节点上,如果刚好落在了服务器所在的节点上,那么就让这个服务器存储该数据;如果不是落在服务器的节点上,那么我们就让该数据落在顺时针方向碰到的第一台服务器节点上。例如说,现在有4台服务器C0,C1,C2,C3,有5个需要存储的数据:V,W,X,Y,Z。

如图所示(图5):

的一致性哈希_深入..浅出的谈谈一致性哈希算法

一共有4个服务器节点分布在哈希环上,我们把V数据的key进行哈希取模过后,发现和C0服务器算出来的值一样,刚好打在了这个点上,那么就由服务器C0保存这个数据,W落在了服务器C0和C1之间,那么按照原则,顺时针遇到的第一个服务器节点就保存它的数据,那么是由C1进行保存的,以此类推(图6):(黑线为实际落环位置,红线为该数据节点映射到的服务器节点)

的一致性哈希_深入..浅出的谈谈一致性哈希算法

新增节点

这样的哈希环有什么好处呢,我们来看一下,当我们需要新增一个服务器节点的时候:例如在C3节点和C0节点处添加一个新的服务器会发生什么事情(图7)。

的一致性哈希_深入..浅出的谈谈一致性哈希算法

我们惊讶的发现,当我们新增了一个节点后,对于数据V,W,X,Y来说映射到的服务器节点位置是没有发生变化的,变化的只有新增节点逆时针遇到的第一个服务器节点这一段区间的数据,即

( C3节点 , C4节点 ]

这一段哈希环需要对数据进行迁移,从原本映射到C0服务器节点转为映射到C4新节点上。而

( C4节点 , C0节点 ]

这一段区间还是映射到C0节点,这就大大降低了新增服务器节点时候数据的迁移量。

删除节点

如果是删除一个节点呢?会不会导致数据的大量移动呢?我们来看看(图8)。

的一致性哈希_深入..浅出的谈谈一致性哈希算法

假设现在C3节点挂掉了,那么在

( C2节点 , C3节点]

这段的数据就需要重新映射到C0节点上,即挂掉节点逆时针遇到的第一个服务器节点的这一段哈希环,那么因为C3的宕机,Y这个数据就会重新存储在C0这个节点。

总的来说,无论是新增一个节点或者是删除一个节点所影响的都只是逆时针遇到第一个节点的这段区间的数据。相比简单哈希所带来的全盘数据移动,一致性哈希算法带来的效率无疑是有着本质的提升。

数据倾斜问题

一致性哈希算法介绍到这里,其实还没有结束,我们仔细看上面这张图,其实还是存在有问题的。因为现在只有C0,C1,C2三个节点,如果我们把C0和C2节点所在位置连起来(相当于圆环的直径),左上半部分的节点相当于都落在了C0节点上,也就是说几乎有一半的数据节点都落在C0服务器上,这是因为服务器节点分布不均匀或者数量过少导致的数据倾斜问题。

虚拟节点

的一致性哈希_深入..浅出的谈谈一致性哈希算法

为了避免数据倾斜问题的发生,引入虚拟节点进行解决。我们需要对服务器节点进行多次哈希运算,使得一个服务器节点有多个节点在环上与之对应,这样就可以进一步削弱或者避免数据倾斜问题。一致性哈希算法的本质不需要改变,我们只需要多添加从虚拟节点到真实节点的映射关系就行了,如图(图9):

的一致性哈希_深入..浅出的谈谈一致性哈希算法

至于一致性哈希算法的创建人,哪一年创建的。大家可以百度搜索一致性哈希,查看相关的百度百科哈。

的一致性哈希_深入..浅出的谈谈一致性哈希算法

愿每个人都能带着怀疑的态度去阅读文章并探究其中原理。

道阻且长,往事作序,来日为章。

期待我们下一次相遇!