聊聊一致性hash算法的原理

https://mp.weixin.qq.com/s/BnErT5xrPpq76A4qUEyQCw

工程师经常使用服务器的集群来设计和实现数据缓存,他们常见的策略是:

1:不管是添加,删除和查询数据,都是先将数据的id通过hash函数生成一个hash值,记为key。

2:如果有N台机器,则会计算key%N的值,这个值就是所属机器的编号,无论是添加,删除和查询数据,都是在这台机器上操作。

请分析上面的策略存在的问题,并提出解决的方案。

2解答

1:首先来想下在什么情况下会产生问题。一般情况下,在不增加机器的情况下,产生的hash值相同,那么就会在某一台机器上操作,不会产生什么问题,但是如果增加或者删除了机器,即N变化的时候,代价就会比较高,所有的数据都需要根据id重新计算一次hash值,并通过hash值对新的机器进行重新取模操作,然后对数据进行大规模的迁移。

2:那么为了解决这些问题,我们就引入了一致性hash算法,这是一种很好的数据缓存解决方案。

假设通过id生成的hash值是0到(2^32)-1 的范围,那么我们可以想象成一个闭合的圆,一个数据id计算出的hash值就是对应圆中的某一个位置,如图所示

当采用一致性哈希算法,把分布式集群中新的机器加入。其原理是通过使用与对象存储一样的Hash算法将机器也映射到圈中(一般情况下对机器的hash计算是采用机器的IP或者唯一的别名作为输入值),当数据和机器同时属于这个圈的时候,一条数据如何确定归属到哪台机器呢?

首先把该数据的id用hash算法计算出hash值之后,映射到圈中的相应位置上,然后以顺时针的方向查找,将对象存储到离自己最近的机器中,那台机器就是该数据的归属。

假设现在有三台机器中,通过hash算法得到对应的KEY值,分别是KEY1,KEY2,KEY3,映射到环中,其示意图如下

object1算出的hash值是key1,顺时针查找的第一台机器是大写的KEY1,key3顺时针查找的第一台机器是大写的KEY2,key2和key4顺时针查找的第一台机器是大写的KEY3。

3:节点的添加

假设有两台机器,大写的KEY1和大写的KEY3和四个数据key1,key2,key3,key4,如上图所示,此时key1属于KEY1的归属,key2,key3,key4属于KEY3的归属。

如果此时插入机器(大写的KEY2),假如计算出机器的hash值在key3和key2的中间,当添加KEY2的时候,key3的旧数据就要迁移到KEY2上,只迁移了一个数据,由此可见,添加机器时调整的代价是比较小的,同理在删除机器的时候,只要把删除机器的数据全部复制到顺时针找到的下一台机器即可。

4:根据上面的图解分析,一致性哈希算法满足了单调性和负载均衡的特性以及一般hash算法的分散性,但这还并不能当做其被广泛应用的原由,因为如果机器在整个圈上的分布不均匀,就会导致机器之间的负载不均衡。

为了解决这种数据分布不均匀的问题,一致性hash算法引入了虚拟节点机制,即对每一台机器通过hash算法计算出多个hash值,比如object1,object2,通过hash(object1),hash(object1-1),hash(object2),hash(object2-1),对多个位置放置一个服务节点,叫做虚拟节点。

具体的做法可以是在机器ip或主机名后面添加编号或端口号实现,如下图,若去掉KEY3-2和KEY1-2机器,那么此时key3,key2,key4是分配个机器KEY3-1的,key1是属于机器KEY1-1的,对象在机器上的分布很不均衡。

现在我们添加2个副本(添加了KEY3-2和KEY1-2)为例,这样整个hash环就存在4个虚拟节点,根据hash函数的性质,节点多了,平衡性就会变好一些。

5:总结

我们一步步分析了什么是一致性Hash算法,主要是考虑到分布式系统每个节点都有可能失效,并且新的节点很可能动态的增加进来的情况,如何保证当系统的节点数目发生变化的时候,我们的系统仍然能够对外提供良好的服务,这是值得考虑的

原文地址:https://www.cnblogs.com/eryun/p/12158038.html