一致性哈希算法原理

首先给个总结:

  • 一致性哈希算法是通过将哈希空间分为1-2^32-1的圆环,我们把cache节点和我们的object对象数据hash运算以后分别映射到圆环上,然后会把对象的数据按照顺时针绑定到最近的一个cache节点,实现数据与节点的绑定,这样做的好处就是如果节点发生增删,都只影响临近的那个数据变更,可以最大程度上抑制了键的重新分布(生产中也就是指服务器缓存的重新分布)。
  • 当然一致性哈希会存在哈希倾斜性的问题,可能会导致数据倾斜和缓存雪崩,我们可以引入虚拟节点,让虚拟节点哈希后得到真实节点,来解决这个问题。

背景

在了解一致性Hash算法之前,先来讨论一下Hash本身的特点。普通的Hash函数最大的作用是散列,或者说是将一系列在形式上具有相似性质的数据,打散成随机的、均匀分布的数据。
 

  • 举个例子,我们有三个服务器0、1、2号服务器,Hash以后取余数,就分别存在对应的节点上。(有0是为了取余为0时能识别到)

  • 现在我们有4个redis server节点,20个数据:

  • 取余,分配节点

  • 现在我们生产环境突然发现redis节点不够用了需要新增节点,或者我们发现redis集群负载非常低,我们可以删除一些节点来节省资源。

  • 现在我们增加一个redis节点

  • 我们发现扩容后原先的1、2、3、20四个数据仍然在原节点上,也就是说redis0只有20命中,redis1只有1命中,redis2只有2命中,redis3只有3命中,命中率时4/20=20%。这里由于数据量级太小,不是很明显,具体可以看下面的公式讲解。

一致性哈希

一致性Hash是一种特殊的Hash算法,由于其均衡性、持久性的映射特点,被广泛的应用于负载均衡领域,如nginx和memcached都采用了一致性Hash来作为集群负载均衡的方案。

  • 首先我们来理解一个环形hash空间,通常hash算法都是将value映射到一个32位的key值当中,我们把数轴卷起来变为一个首尾相接的圆环,取值范围0 - 2^32-1,即代表能存放从0 到 2^32-1个数字的位置,然后把对象映射到环形hash空间

  • 我们现在有四个Object对象,Object1、2、3、4,取hash以后映射到hash空间。

  • 然后把cache也映射到同一个hash空间。对于cache的计算。一般可以使用cache机器的IP地址,机器名等作为hash输入,也可以引入更多因子,比如端口号。

  • 已经把cache映射到hash环形空间中了,接下来需要考虑的就是如何把对象映射到cache上面。
  • 在这个环形空间中,比如从key1出发顺时针,碰到的第一个cache节点时key A(也就是cache A),那么key1就要存到蓝色的key A节点中,由于两者hash都是固定的,因此key1存到cache A中是唯一并且确定的,这样就找到一个数据映射cache的方案。

  • 因此key1、2、3、4均顺时针找到cache节点后:

  • 如果我们需要删除或增加一个cache节点,传统的hash算法这种取模的方式对后台服务器造成巨大的冲击,很多缓存都没有命中,如果你的业务代码是穿透型的,那就会穿过cache直击DB,很容易把数据库搞垮。

  • 接下来看看一致性hash算法的精髓,我们如果移除cacheB,那么key 4(Objecy 4)就会顺时针找到cache c,存取在cache c。我们可以看出,移除cache c并不会影响object2、3,影响的是cache c逆时针到object 4这段范围。影响范围很小。并不像上面那种取模方式变动很大。

  • 添加cache的话:也只会影响添加的cache到逆时针的第一个Object:

Hash倾斜性:问题与优化

事实上cache可能分布没有那么均匀,就会导致A的负载很高。

数据倾斜

如果节点的数量很少,而hash环空间很大(一般是 0 ~ 2^32),直接进行一致性hash上去,大部分情况下节点在环上的位置会很不均匀,挤在某个很小的区域。最终对分布式缓存造成的影响就是,集群的每个实例上储存的缓存数据量不一致,会发生严重的数据(hash)倾斜。 

缓存雪崩

如果每个节点在环上只有一个节点,那么可以想象,当某一集群从环中消失时,它原本所负责的任务将全部交由顺时针方向的下一个集群处理。例如,当cache0退出时,它原本所负责的缓存将全部交给cache1处理。这就意味着cache1的访问压力会瞬间增大。设想一下,如果group1因为压力过大而崩溃,那么更大的压力又会向cache2压过去,最终服务压力就像滚雪球一样越滚越大,最终导致雪崩。

    --->    

  • 为了使对象尽可能均匀地映射到所有的缓存实例中(解决缓存实例分布不均匀的问题),引入虚拟节点的概念。虚拟节点其实为真实节点在hash空间中的复制品,一个真实节点可以对应多个虚拟节点。虚拟节点的hash求值可以在真实节点的求值基础上加入编号等信息 hash(realCacheKey#1) 、 hash(realCacheKey#2)。
图片似乎有问题,虚拟节点并不是hash以后得到zhen'shi'jie'dian

  • 通过虚拟节点的原理我们来解决hash倾斜性的问题:

我们对虚拟节点进行hash时,虚拟节点的hash倾斜性怎么解决?

这就要由hash算法来保证了,均匀分布是概率上的均匀,当虚拟节点足够时,就能保证大概均匀了。

缓存命中率及单一热点问题
一致性哈希解决的是某节点宕机后缓存失效的问题,只会导致相邻节点负载增加。但是因为宕机后需要重新从数据库读取,会导致此时缓存命中率下降及db压力增加。
也无法避免单一热点问题。某一数据被海量请求,不论怎么哈希,哈希环多大,数据只存在一个节点,早晚有被打垮的时候。

此时的解决策略是每个节点主备或主主集群。

hash漂移
某个节点失效了,缓存都漂到下个节点了;然后一会它又恢复了,这时候它就有脏数据了。
解决办法一是每个节点引入集群。
不用集群想彻底解决这个问题,可能需要引入第三方健康检查组件,如Consul,发现节点不稳定立即删除下线。

  • 一致性hash算法最大程度上抑制了键的重新分布(服务器缓存的重新分布),而且我们还可以采用虚拟节点的思想,比如我们每个实际节点都配置100-500个虚拟节点,这样就能抑制分布不均匀。

  • 命中率公式:n是服务器台数,m是增加的服务器,因此随着分布式集群不断扩大,命中率会越来越高。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值