上周更新了一篇文章《一致性Hash算法与虚拟节点》,阅读和收藏人数挺多的。
今天有朋友问了我一个问题,虚拟节点如何保证均匀分布?
我不假思索的回答,
不需要保证虚拟节点的均匀分布,
虚拟节点用以保证相对的均匀靠得是量变产生质变,
就像我文末提到的,在实际场景中,虚拟节点的个数只有3个是远远不够的。
例如Dubbo中用到一致性hash算法时,默认的虚拟节点个数是160个,
假设我们有四个服务节点需要创建虚拟节点,那就会有 4 * 160 = 640 个虚拟节点,
在这样大量的基数下,必然他们的分布就会呈一种相对均匀的状态。
回答完我感觉很满意,不愧是我!
可转念一想,再想,三想,
好像不是这么一回事,
别说是有640个节点了,就算有6400个,64000个节点又如何呢?
在极小极小的概率下,如果hash算法不能保证映射的均匀性,
他们依然可能落在十分聚集的一小块区域中。
反推一下,既然一致性hash算法作为一个成熟并拥有很多应用场景的算法,
不可能如此不严谨,所以hash算法本身应该是可以保证映射的一致性的。
“应该”?这么不确定可不行,我得好好补补空白,确实之前没有去了解过hash算法到底实现了个啥。
东查西查,终于有了答案。
百度百科对Hash的名次解释如下:
Hash,一般翻译做散列、杂凑,或音译为哈希,是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。
哦,原来就是散列函数啊!
那就简单了,散列函数我本科学过啊!
脑海一番搜索,糟糕,我真的学过吗?唯一的印象就是学过。
没事,学过忘了没关系,再学就完事了。
以下是干货,
一个合格的散列函数包含三个特征:
- 单向性:容易计算输入的散列结果,但是从散列结果无法倒推出输入;
- 抗冲突性:很难找到两个不同的输入散列结果相同;
- 映射分布均匀性和差分分布均匀性:散列结果中 bit 位上的 0 和 1 的数量应当大致相等;改变输入内容的 1 个 bit 信息会导致散列结果一半以上的 bit 位变化(雪崩效应)。
真刺激,到这是不是就完事了,散列函数保证了映射的分布均匀性。
我劝你要不要再回去看两遍映射分布均匀性和差分分布均匀性的内容。
看完了吗?
再想想《一致性Hash算法与虚拟节点》中的hash环,
有没有顿时反应过来,这边又TM不严谨了。
说好的散列结果中bit位上 0 和 1 的数量大致相等,这要是映射到hash环上,
最小值岂不是 00000000000000001111111111111111,
最大值岂不是 11111111111111110000000000000000,
(别数数字,我随便打的,你懂我意思吧)
那在hash环上不就出现了一段真空地带了吗?
虽然实际上真空地带比图上的还小,只有 65536/4294967295 约等于 百万分之十五,
但这微小的缺口无疑将带来无法估计的灾难,尤其是在实际生产环境中,
你永远不知道一个微小的漏洞可能会造成多大的后果。