【算法基础】一致性Hash算法分析与可能性说明

一致性Hash算法背景

一致性哈希算法在1997年由麻省理工学院的Karger等人在解决分布式Cache中提出的,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似。一致性哈希修正了CARP使用的简单哈希算法带来的问题,使得DHT可以在P2P环境中真正得到应用。

假设有 N 个 cache 服务器(后面简称 cache ),那么如何将一个对象 object 映射到 N 个 cache 上呢,你很可能会采用类似下面的通用方法计算 object 的 hash 值,然后均匀的映射到到 N 个 cache

hash(object)%N

一切都非常的正常,假如有一下的两种场景:

  • 一个 cache 服务器 m down 掉了(在实际应用中必须要考虑这种情况),这样所有映射到 cache m 的对象都会失效,这时候,需把 cache m 从 cache 中移除,这时候 cache 是 N-1 台,映射公式变成了 hash(object)%(N-1) ,数据丢失。
  • 由于访问加重,需要添加 cache ,这时候 cache 是 N+1 台,映射公式变成了 hash(object)%(N+1)

注意,此时映射公式的取模模量改变,意味着之前所有的cache都失效了。对于服务器而言,需要对原来所有的cache迁移到新的服务器中。

  • 硬件能力越来越强,可能想让后添加的节点负载多一些,显然上面的 hash 算法完成不了。
    有什么可以改变,Consisten hashing可以解决。
hash算法和单调性

Hash 算法的一个衡量指标是单调性(Monotonicity ),定义如下:

单调性是指如果已经有一些内容通过哈希分派到了相应的服务器中,又有新的服务器加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到新的服务器中去,而不会被映射到添加之前的服务器集合中的其他服务器中。

显然,hash(object)%N无法达到要求。

Consistent Hashing 一致性hash的原理

consistent hashing是一种hash算法,通俗的说,在移除或者是添加一台服务器的时候,使以尽可能小的数据迁移代价去改变原有的key映射关系,从而去满足单调性的要求。
如何做到?先从结构开始谈起。

1.环形hash空间

考虑通常的 hash 算法都是将 value 映射到一个 32 位的 key 值,也即是 0~2^32-1 次方的数值空间。我们就可将其看作为首尾相接的环。如下图1:

在这里插入图片描述

图1 一致性hash算法的环状结构

2.把需要缓存的内容通过hash计算映射到hash空间

假设有四个对象object1~object4,通过hash函数计算的hash值key在环上的分布如图2所示。

实际可能不是这么均匀

在这里插入图片描述

图2 各个对象key映射到环中

3.把服务器(节点)映射到hash空间

Consistent hashing 的基本思想就是将对象和 服务器(节点)都映射到同一个 hash 数值空间中,使用是同种的 hash算法。
假设当前有 A,B 和 C 共 3 台服务器(节点),其映射结果将如图 3 所示,他们在 hash 空间中,以对应的 hash 值排列。
一般可以通过服务器的ip,mac地址…作为hash输入。实际并上不会这么均匀:

hash(M_A) = key A;
hash(M_B) = key B;
hash(M_C) = key C;

在这里插入图片描述

图3 对象映射到节点关系
4.把对应的对象映射到节点

现在服务器(节点)和对象都通过相同的hash算法映射到hash数值空间中。那么,如何将对象映射到服务器(节点)上。
使用的策略是:将当前对象节点,按照顺时针方向出发,第一个遇到的节点,就是当前对象要存储的节点。由于对象和节点的hash值是固定的,所以节点必然是唯一和确定的。上图3所示。

  • 4.1如何实现?

所想可以对所有的节点hash值进行排序,假设还是上面的三个节点,排序之后的序列,我假设为se_M = [m2 , m1 , m3 ] , 通过前端负载的服务器,每个前端的服务器都保存有序列se_M,对每次来临的请求对象进行hash值计算,使用二分法在序列中查找到首个大于或等于当前对象hash值的节点,将对象存储到节点中,就可以实现将对应的对象映射到对应的节点中。

5.服务器(节点)变动情况

文章开始提到通过hash求余计算出节点的最大问题在于无法满足单调性,当节点有所变动时,节点中的数据有可能丢失(节点down),或者是数据迁移代价过高(新增节点),来直接的对后台服务器进行冲击。
consistent hashing如何解决?

  • 5.1 移除节点

假设此时M_B突然down了,根据上面的对象映射到节点的方法,此时受影响的仅仅是沿M_AM_B顺时针路径上的对象。也就是本来应该映射到M_B上的对象。

在这里插入图片描述

图4 M_B被移除之后的映射
  • 5.2 添加节点

考虑添加一台新的节点M_D 的情况,假设在这个环形 hash 空间中, M_D被映射在对象 object3 和object4 之间。这时受影响的将仅是那些沿 M_A 顺时针直到下一个 M_D之间的对象(它们是也本来映射到M_B 上对象的一部分),将这些对象重新映射到 M_D 上即可,如图5.
在这里插入图片描述

图 5 添加 节点D 后的映射关系

上述这个结构还存在非常大的问题。首先,根据hash函数的性质易知样本量在比较大的情况下,才体现出均分的性质,样本量小时并不保证均分。于是上面的环就不可能被均匀的拆分。其次,即使你可以通过某种蜜汁手段来保证开始的时候能够被均分,在节点增减的过程中,均分的结构又被破坏了。
如果能解决上述问题,一致性hash算法就既能做到 数据迁移的代价很低又能够做到 负载均衡.

6. 虚拟节点

虚拟节点技术可以完美的解决上述两个问题。以上述中三个节点M_A,M_B,M_C为例子,摒弃直接以节点中ip,mac等等计算hash值的方法去映射环中的位置。而是给M_A,M_B,M_C分别分配数量比较大的虚拟节点,然后,通过分别计算虚拟节点的hash值,来将各个节点中的虚拟节点分配到环中对应的位置,这样通过比较大的样本量,通过hash函数性质易知,就能够达到每个节点对应的虚拟节点在环中均分的目的。
对于虚拟节点和物理节点的问题,可以利用一个路由表结构,将物理机和虚拟节点一一对应起来,在环中对象映射到虚拟节点时,通过路由表查询到对应的物理节点,对象映射到虚拟节点的操作实质上变成了对象映射到虚拟节点所对应的物理节点上。
这样就解决了在减少或者是增加节点的时候,造成环的不均分问题。

【可能带来的问题】:可能虚拟节点过多,会造成虚拟节点重叠问题。
小概率事件

参考博文:
百度百科_)一致性哈希
https://www.cnblogs.com/lpfuture/p/5796398.html
http://www.zsythink.net/archives/1182

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值