第一次与consistent hash (以下简称CH)见面是在网络原理一书,他应用在PEER-TO-PEER的网络,主要解决了分布存储资源的问题。当时还不是很清楚他的应用范围和中文名字,PS 网络原理一书是英文版的,当然也没有出现CH的字样。
第二次见面是在使用memcache的时候,在高人的指导下用CH来实现扩展需求。
CH能做什么,解决了什么问题?
答:存储平均的问题
让我们先来看下CH的原理吧:
CH先是将一个圆环分成2的N次方个节点,每个节点是一个数值V(i),然后将存储的节点根据一个哈希函数F取哈希值,这个值落在圆环内。
存储一个值A的时候,用同一哈希函数F取A的哈希值,这个值必定落在圆环内,但不一定是V(i)的值。这时,顺时针查找下一个V(i)的节点,这个节点就是A的存储节点。
这样的算法使得存储值很平均,且能保证一致性的问题--一个值只在一个节点上。
到此,我们会发现其实这个hash函数至关重要。
现在我们来看余数式哈希函数,也就是说上文中的hash函数F是跟节点数有关系的。那么每增加一台服务器,就必须做牵库处理。这个结果是我们所不愿看到的。
使用一致性哈希是否能解决增加节点所带来的问题呢?答案显然不是的,不过使用一致性hash能降低移库所带来的成本。也就是说一致性hash后的键值是很平均的。
让我们来看看到底一致性hash到底是什么东西?
这些都是纯数学的东西,看得我还是头晕的,不做什么解释了(也解释不出来什么),放个地址大家参考下吧
一般的hash 函数算法 : http://www.partow.net/programming/hashfunctions/
以下是我对一致性hash函数增加节点而不移库的一些想法(未经测试):
这个想法是来源于基数排序的想法---空间换时间,具体内容如下:
假如我们的圆环O上有4个节点A,B,C,D,即 O-A-B-C-D-O,此时4节点上都有一定的数据。
我们插入节点E,并且插入到D-O之间: O-A-B-C-D-E-O
此时我们原本要做的是要将键值在D-E 之间的数据从O上移到E上,但是我们如果用空间换时间的话就不需要这么做:
我们只需要记录下在某个时间段T,某个键值K对应的某台服务器,数学表示就是SERVER = f(T , K).
那么我们查询某个键值为K1的值的时候,假使这个值原本在O上,但是时间点T1后,因为增加节点的原因,它已经落到了E上。
根据时间T1和键值K1我们就能很快的查出它的值。但是这样的做法浪费了很多的空间去存储这些META DATA。
如果节点无限制的增加,这些冗余的信息就会无限的增多,最终还是要移库。
是否这样做还是取决于我们系统对实时性的要求,如果实时性不高,那么下面的做法也未尝不可:
假如我们的圆环O上有4个节点A,B,C,D,即 O-A-B-C-D-O,此时4节点上都有一定的数据。
我们插入节点E,并且插入到D-O之间: O-A-B-C-D-E-O
此时我们原本要做的是要将键值在D-E 之间的数据从O上移到E上,但是我们如果用空间换时间的话就不需要这么做:
当我们查询某个键值为K2的时候,此值原本在O上,时间T2后,就落在E上,如果在E节点上查不到就顺时针去E的下个节点找,以此类推。
这种情况下,如果我们无限制的增加节点,那么最终将导致某段键值对应的值要遍历整个增加的节点环。
n为增加的节点数
最坏的时间度为O(n)
平均的时间度为O(n*n)