我们把2~32次方想成一个环,比如钟表上有60个分针点组成一个圆,那么hash环就是由2~32个点组成的圆。第一个点是0,最后一个点是2~32-1,我们把这2~32个点组成的环称之为HASH环。
将memcached物理机节点通过Hash算法虚拟到一个虚拟闭环上(由0到2~32构成),key请求的时候通过Hash算法计算出Hash值然后对2~32取模,定位到环上顺时针方向最接近的虚拟物理节点就是要找到的缓存服务器。
假设有ABC三台缓存服务器:
我们使用这三台服务器各自的IP进行hash计算然后对2~32取模即:
***Hash(服务器IP)%2~32***
复制代码
计算出来的结果是0到2~32-1的一个整数,那么Hash环上必有一个点与之对应。比如:
现在缓存服务器已经落到了Hash环上,接下来我们就看我们的数据是怎么放到缓存服务器的?
我们可以同样对Object取Hash值然后对2~32取模,比如落到了接近A的一个点上:
那么这个数据理应存到A这个缓存服务器节点上
所以,在缓存服务器节点数量不变的情况下,缓存的落点是不会变的。
但是如果B挂掉了呢?
按照hash且取模的算法,图中3这个Object理应就分配到了C这个节点上去了,所以就会到C上找缓存数据,结果当然是找不到,进而从DB读取数据重新放到了C上。
但是对于编号为1,2的Object还是落到A,编号为4的Object还是落到C,B宕机所影响的仅仅是3这个Object。这就是一致性Hash算法的优点。
前面我们理想化的把三台memcache机器均匀分到了Hash环上:
但是现实情况可能是:
如果Hash环倾斜,即缓存服务器过于集中将会导致大量缓存数据被分配到了同一个服务器上。比如编号1,2,3,4,6的Object都被存到了A,5被存到B,而C上竟然一个数据都没有,这将造成内存空间的浪费。
为了解决这个问题,一致性Hash算法中使用“虚拟节点”解决。
“虚拟节点”是“实际节点”在hash环上的复制品,一个实际节点可能对应多个虚拟节点。这样就可以将ABC三台服务器相对均匀分配到Hash环上,以减少Hash环倾斜的影响,使得缓存被均匀分配到hash环上。
平衡性指的是hash的结果尽可能分布到所有的缓存中去,这样可以使得所有的缓存空间都可以得到利用。但是hash算法不保证绝对的平衡性,为了解决这个问题一致性hash引入了“虚拟节点”的概念。虚拟节点”( virtual node )是实际节点在 hash 空间的复制品( replica ),一实际个节点对应了若干个“虚拟节点”,这个对应个数也成为“复制个数”,“虚拟节点”在 hash 空间中以 hash 值排列。“虚拟节点”的hash计算可以采用对应节点的IP地址加数字后缀的方式。
例如假设cache A的IP地址为202.168.14.241。
复制代码
引入“虚拟节点”前,计算 cache A 的 hash 值:
Hash(“202.168.14.241”);
复制代码
引入“虚拟节点”后,计算“虚拟节”点 cache A1 和 cache A2 的 hash 值:
Hash(“202.168.14.241#1”);// cache A1
复制代码
Hash(“202.168.14.241#2”);// cache A2
复制代码
这样只要是命中cacheA1和cacheA2节点,就相当于命中了cacheA的缓存。这样平衡性就得到了提高。