hash算法
大学期间大家对hash这个词语肯定最熟悉不过了
最简单的hash就是余数hash
在分布式系统中,分布式hash是为了解决因特网中的热点(Hot Spot)问题,初衷和CARP十分相似。一致性Hash修正了CARP使用的简单哈希算法带来的问题,使得分布式哈希(DHT)可以在P2P环境中真正得到应用。
一致性Hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义:
1、平衡性(Balance):平衡性是指哈希的结果能够尽可能分布在所有的缓冲(Cache)中去,这样可以使得所有的缓冲空间得到利用。很多哈希算法都能够满足这一条件。
2、单调性(Monotonicity):单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应该能够保证原有已分配的内容可以被映射到原有的或者新的缓冲中去,而不会映射到旧的缓冲集合中的其他缓冲区。
3、分散性(Spread):在分布式环境中,终端有可能看不到所有的缓冲,而只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上去,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应该能够尽量避免不一致的情况发生,也就是尽量降低分散性。
4、负载(Load):负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射到不同的内容。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低缓冲的负荷
先来看看一致性 Hash 算法的一些特点:
- 构造一个
0 ~ 2^32-1
大小的环。 - 服务节点经过 hash 之后将自身存放到环中的下标中。
- 客户端根据自身的某些数据 hash 之后也定位到这个环中。
- 通过顺时针找到离他最近的一个节点,也就是这次路由的服务节点。
- 考虑到服务节点的个数以及 hash 算法的问题导致环中的数据分布不均匀时引入了虚拟节点。
根据上面的描述,我们来简单分析一下,服务节点经过 hash也放在环中是为了解决分散性,单调性。极端情况下还会出现某几个服务节点承担着大部分符合,这时候出现负载不平衡情况,这时候就要引入虚拟节点了。将节点映射多个虚拟机点放在环上。
通过分析我们来试着实现这样一个一致性hash算法:
这样我们的流程如下:
- 初始化一个长度为 N 的数组。
- 将服务节点通过 hash 算法得到的正整数,同时将节点自身的数据(hashcode、ip、端口等)存放在这里。
- 完成节点存放后将整个数组进行排序(排序算法有多种)。
- 客户端获取路由节点时,将自身进行 hash 也得到一个正整数;
- 遍历这个数组直到找到一个数据大于等于当前客户端的 hash 值,就将当前节点作为该客户端所路由的节点。
- 如果没有发现比客户端大的数据就返回第一个节点(满足环的特性)。
先不考虑排序所消耗的时间,单看这个路由的时间复杂度:
- 最好是第一次就找到,时间复杂度为
O(1)
。 - 最差为遍历完数组后才找到,时间复杂度为
O(N)
。