在大型web应用中,缓存可算是当今的一个标准开发配置了。在大规模的缓存应用中,应运而生了分布式缓存系统。
比如有N个cache服务器,那如何讲一个对象映射到N个cache上去,最常规的方式莫过于:hash(object)%N。
但是,如果有一台cache服务器down了,这时我们需要将此cache服务器移除,cache从而变为N-1台,映射公式变为:
hash(object)%(N-1);另外,如果访问负担加重,需要添加cache,此时公式变为hash(object)%(N+1).
这两种情况意味着几乎所有cache全部失效,此时大量的访问都会涌向后台的服务器。
这里介绍一些概念:单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到新的缓冲中去,而不会被映射到旧的缓冲集合中的其他缓冲区。所以我们需要保证单调性要求。
一致性hash,他是用来保证添加或者删除cache时,要尽可能小的改变已经存在的key映射关系,保证单调性的要求。
通常的hash算法是将value映射到一个32位的key值。这里,我们考虑4个对象o1, o2, o3, o4,通过hash函数计算出的key
的分布情况如图:
我们的一致性hash算法是将对象和cache都映射到同一个hash数值空间中,并且使用相同的hash算法。
假设当前有A, B, C 3台cache,那么其映射结果如图所示:
对于cache的hash计算,一般是采用cache的服务器的IP地址或机器名作为hash的输入。
然后,我们就需要将对象映射到cache,在上述的环形空间中,如果沿着顺时针方向从对象的key值出发,直到遇到第一个cache,
我们就将次对象存贮在这个cache上,以此方法将所有的对象映射到顺时针方向最近的一个cache上,根据上述方法,得到的结果:
o1到cacheA上,o2和o3对应到cache C, o4对应到cache B上。
考虑当移除一台cache服务器B时,o4受到了影响,即重新映射到cacheC上了,其他的映射关系保持不变;
当添加一台cache服务器D时,假设D映射到o2和o3之间,此时受影响的仅是o2,其映射到了cacheD上,效果如下图:
另外,考量hash算法的另一个标准是平衡性,即哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间
都得到利用。我们的算法并不能保证平衡性,我们引入了虚拟节点来解决这种问题。
“虚拟节点”( virtual node )是实际节点在 hash 空间的复制品( replica ),一实际个节点对应了若干个“虚拟节点”,这个对应
个数也成为“复制个数”,“虚拟节点”在 hash 空间中以 hash 值排列。
引入“虚拟节点”后,映射关系就从 { 对象 -> 节点 } 转换到了 { 对象 -> 虚拟节点 } 。查询物体所在 cache 时的映射关系如图所示:
“虚拟节点”的 hash 计算可以采用对应节点的 IP 地址加数字后缀的方式。例如假设 cache A 的 IP 地址为 202.168.14.241 。