消费方 应该多调用几次,
不知道你这个问题是否已经解决, 如果还没有解决的话:一致性哈希算法为了解决互联网的Hot Spot问题(热点问题)而产生的。
在一致性Hash算法提出了判断哈希算法好坏的四个定义,这里引用别人的文章来:
1.平衡性:平衡性是指哈希的结果能够尽可能分布到所有的缓冲去,这样可以使得所有的缓冲空间都得到利用。
2.单调性。单调性是指如果已经有一些内容通过哈希分派到相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应该能够保证原有已分配的内容可以被映射到原有的或者新的缓冲去,而不会被映射到旧的缓冲集合中的其他缓冲区。
3.分散性。在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。
4.负载(Load):负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同 的内容。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低缓冲的负荷。
在分布式集群中,节点的添加或者删除,或者节点故障都是分布式集群管理的很正常的现象,如果采用普通hash算法,会导致一旦节点出现变更(增删或者故障转移),变更节点上的数据就会出现找不到或者需要全部重新计算hash迁移数据的问题。
那么一致性哈希算法相比于普通的哈希算法多了哪些改进呢?
一致性哈希算法采用的时环形哈希空间的方式,它首先根据ip或者其他信息为机器节点生成一个hash,它投射到一个[0,2^32-1]的圆环中。之后我们可以认为它是一个锚点。当请求进来后,它携带的数据,我们都统一生成一个hash值,这时候我们比对之前的机器节点信息产生的hash值,当遇到第一个大于或者等于该hash值得缓存节点,我们将这个数据便归属于这个机器节点。
如果某台机器挂了怎么办?
传统的hash算法需要重新计算所有数据的hash值,然后重新分配,涉及到的迁移数据将会是全部数据。一致性哈希算法优化的点也是在于这里,如果当前节点挂了,其实需要重新写入的也只有这个节点的数据,当这个节点的数据直接迁移到下一个大于其hash值得机器节点即可。
这里引用dubbo官网文档的图片:
当cache3节点坏掉了,此时原属于cache3的数据将转移到cache4,那么这里的数据影响的范围也只是cache-2到cache-3这一部分。
但是这里还有个问题,如果恰好计算所得hash值的数据过于集中,则会过于集中在某一个节点。
为了避免数据倾斜的问题,一致性哈希算法引入了虚拟节点的方式来解决这个问题。这里其实也是上面所说的四个定义决定了哈希算法的好坏,平衡性也是需要考虑的重要因素之一。
数据倾斜是指,由于节点不够分散,导致大量请求落到了同一个节点上,而其他节点只会接收到了少量请求的情况
怎么解决?
引入虚拟节点。那什么是虚拟节点呢?其实个人的理解如果说实际的节点是通过真实机器的真实信息的一个hash映射,那么虚拟节点无非是在真实机器中划分一个虚拟区域的信息,然后将真实机器的hash映射做一个细分。
举个例子,如果我们按照真实机器的ip进行hash化,从而在哈希环中做了一个节点的投射,那么虚拟节点我们可以采用ip加数据后缀的方式,投射出虚拟节点在哈希环的位置。
加入了虚拟节点,可以让数据的分布更加平衡。
在此通过dubbo官网的图来加深理解:
这里同一个颜色的则是指同一个实际节点。