一致性hash
解决hash算法强依赖于slot数量问题. 即slot增减后,造成数据重新hash的问题.
约定
- cache: 缓存服务器
- object: 存储的数据
- 传统分布式hash方案
n
台cache服务器hash(object) % n
平均分布在n
台cache上- 添/删cache
- 所有
object
重新hash
问题:
这样就引发了前面所说的问题了,当增删cache造成大量数据重新hash.
这时我们需要新的算法
- [一致性hash]
一致性hash解决的问题: 当cache增减时,使object尽可能少的实效
hash(object)
和之前的类似hash(cache)
- 将hash后的object映射到cache上 我们通过
hash(cache)
将cache和object放在了同一个hash空间中,然后通过一定的映射规则,映射到对应的cache上.
那么我们的映射规则是怎么样的呢?
如图所示,我们的object和cache都分散到了同一个空间上,
接下来我们从Object1的位置顺时针向前寻找,当碰到第一个cache时,就将object存储在这个cache上,其他Object用同样的方法映射到对应的chache上.
这样当增删cache时就能最大限度上的降低 rehash 的次数.
例如,当cache A从集群中被删除以后,我们只需要 rehash cache A上Object即可,其他则不需要移动.
- 缺陷
虽然我们很大程度上结局了rehash
的次数,但是细心的同学可能已经发现,在这种方案下Object好像并不能均匀的分布在各个cache上,这样应该是会影响集群效率的.
所以接下来我们引入虚节点来解决这个问题.
- 虚拟节点
考量hash函数的一个重要标准是data是否能够均匀的分布在容器内.
我们当然也希望所有的object 落在任一cache上的几率尽量相等.从上面的图中我们可以看出object落在圆环上的任意一点的几率是相等的, 那么落下任一cache上的几率就和圆弧的弧长成正比.
而且, 理论上如果有足够多的object和cache的话是可以均匀分布的. 但是实际情况往往是cache只有少量, 这样就有可能出现部分cache压力巨大, 而其余的cache比较轻松.
为了解决这样的问题,我们引入虚拟节点:
原理很简单, 我们已cache A 和cache C为例, 用cache A1, cache A2代表cache A, cache C1 和 cache C2代表 cache C.
这样我们的映射关系就变成了:
object 1 >>> cache A2 >>> cache A
object 2 >>> cache A1 >>> cache A
object 3 >>> cache C1 >>> cache C
object 4 >>> cache C2 >>> cache C
如此, 我们就可以很大限度上平均了cache 上object 的分布. 平衡性得到了极大的提升.