一致性Hash算法是个经典算法,Hash环的引入是为解决单调性(Monotonicity)的问题;虚拟节点的引入是为了解决平衡性(Balance)问题。
一致性Hash算法的原理主要分为两步:
首先,对存储节点的哈希值进行计算,其将存储空间抽象为一个环,将存储节点配置到环上。环上所有的节点都有一个值。其次,对数据进行哈希计算,按顺时针方向将其映射到离其最近的节点上去。
当有节点出现故障离线时,按照算法的映射方法,受影响的仅仅为环上故障节点开始逆时针方向至下一个节点之间区间的数据对象,而这些对象本身就是映射到故障节点之上的。
当有节点增加时,比如,在节点A和B之间重新添加一个节点H,受影响的也仅仅是节点H逆时针遍历直到B之间的数据对象,将这些重新映射到H上即可,因此,当有节点出现变动时,不会使得整个存储空间上的数据都进行重新映射,解决了简单哈希算法增删节点,重新映射所有数据带来的效率低下的问题
在分布式集群中,对机器的添加删除,或者机器故障后自动脱离集群这些操作是分布式集群管理最基本的功能。如果采用常用的hash(object)%N算法,那么在有机器添加或者删除后,很多原有的数据就无法找到了,这样严重的违反了单调性原则。
一致性hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义:
使用常见的hash算法可以把一个key值哈希到一个具有232个桶的空间中。也可以理解成,将key值哈希到 [0, 232) 的一个数字空间中。 我们假设这个是个首尾连接的环形空间。
若我们现在有4个key值,分别为k1、k2、k3、k4,通过一定的Hash算法将Hash到这个环形的Hash空间上,如下图所示:
同样假设我们有三台节点机器分别为node1、node2、node3,我们依然将其Hash到这个环形空间中:
接下来就是数据如何存储到服务器上了,key值哈希之后的结果顺时针找上述环形hash空间中,距离自己最近的机器节点,然后将数据存储到上面, 如上图所示,k1 和 k4 存储到 node3 上, k3存储到node1上, k2存储在node2上。用图表示如下:
若node1节点宕机,这时候就需要将node1从集群中摘除,那么之前存储在node1上的key就需要顺时针寻找距离自己最近的节点,如下图所示,原先存储在node1上的k3将会存储到node2上:
有时候需要添加节点,在添加节点之后,只有在添加节点和其前一个节点之前的数据需要变动:
面的简单的一致性hash的方案在某些情况下但依旧存在问题: 一个节点宕机之后,数据需要落到距离他最近的节点上,会导致下个节点的压力突然增大,可能导致雪崩,整个服务挂掉。如下图所示若node3宕机,其数据将会全部转移到node1,若node1无法承受突如其来的大量数据也有可能挂掉:
“虚拟节点”( virtual node )是实际节点(机器)在 hash 空间的复制品( replica ),一实际个节点(机器)对应了若干个“虚拟节点”,这个对应个数也成为“复制个数”,“虚拟节点”在 hash 空间中以hash值排列。
若其中node1节点挂掉,那么数据将有以下变动:
这样做的好处显而易见,不再是由一台机器完全接受数据,雪崩的可能性大大减小