哈希算法是根据hash值将不同的value映射到相应的位置的过程。

那么在分布式中,【比如memcached】,需要将不同的缓存对象按照相应的hash算法映射到相应的机器上去,那么当添加一台机器或者是其中某一台机器宕机之后,如果按照最原始的key%n的形式来做hash的话,需要将缓存清空,然后重新将内容映射到所有的机器上,这样的代价是巨大的。

于是粗线了一致性哈希。简单来说,一致性哈希将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0~2^32-1,如下图所示:

整个空间按顺时针方向组织。0和232-1在零点中方向重合。

下一步将服务器使用H【hash算法】进行哈希(具体可以选择服务器的ip或主机名作为关键字进行哈希),映射到哈希环上的某个位置,这里假设将三台服务器使用ip地址哈希后在环空间的位置如下

1349781404_3472.png

服务器布置好之后,就要映射数据了。

使用如下算法映射数据到相应服务器:将数据key使用相同的函数H【hash算法】计算出哈希值h【根据h确定此数据在环上的位置】。从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该映射到的服务器。

例如我们有A、B、C、D四个数据对象,经过哈希计算后,在环空间上的位置如下:

1349781518_6489.png

根据一致性哈希算法,数据A会被定为到Server 1上,D被定为到Server 3上,而B、C分别被定为到Server 2上。

------------------------------------------混个混个----------------------------------------------

上面是讲一致性哈希的服务器布置和key-value的映射过程。

下面说一致性哈希的扩展性和容错性。

现假设Server 3宕机了:

1349781638_5744.png

可以看到此时A、C、B不会受到影响,只有D节点被重定位到Server 2【这在分布式中是很好定位的,比如说server3宕机了,那么根据一致性哈希算反,查找的时候,会发现D在server2上,但是在server3刚刚宕机的时候,server2上并没有D,此时应用会把数据缓存到server2上,此时,D就被hash到server2上了】。

下面考虑另外一种情况,如果我们在系统中增加一台服务器Memcached Server 4:

1349781817_7613.png

此时,B不会去server2查找数据了,而会在server4上查找,如果B此时不存在于server4上,那么会缓存从数据库取回来的B在server4上。而server2上的数据,会因为时间太久没有被访问或者是因为超时而被memcached清理掉了。综上所述,一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。

一致性哈希的缺点

当然,万物都是有两面性的。

一致性哈希算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题。例如我们的系统中有两台服务器,其环分布如下:

1349781953_4428.png

那么此时数据大部分会存到server1中,而2中会因为距离1太近而有很少的数据。为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希【具体可以这么做:根据服务器的名字或者是ip计算节点hash的时候,可以加上编号,然后再计算哈希值】,在每个计算的结果位置都放置一个服务节点,称为虚拟节点。这样,数据再被存储的时候,就不会因为服务器在环上的间距太大而导致“数据倾斜”了。

至于Memcached 的分布式,则完全由客户端实现。这种分布式是Memcached最大的特点。

目前一致性哈希是分布式的标准配置。