谈谈什么一致性hash算法?

Posted felix技术分享

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了谈谈什么一致性hash算法?相关的知识,希望对你有一定的参考价值。

用最通俗易懂的方式来解释下一致性hash算法;

首先我们要明确的是一般的hash算法在取模的时候往往跟实际应用有关!

比如说nginx hash的时候,会根据后台的应用服务器数量进行取模,比如说后台有四台应用,那么hash(key)%4 =(0,1,2,3),就能获取到具体哪一台的标号,这个时候如果后台应用需要扩容,那么hash算法就要换成hash(key)%6 =(0,1,2,3,4,5),分布到六台不同的机器上去请求,看着没什么太大问题,但是如果我们把场景切换为数据库根据业务主键business_no进行hash的的分库分表结构,在切换之后,因为hash算法的改变,原本的数据落在4,但是hash结果为5,肯定查不到原来的数据,这就出现了数据查询错误问题!

而如果上述问题是出现在redis上,因为数据大量不命中,大量的查询降落在底层的数据库上,严重的话发生缓存雪崩问题,导致数据库系统乃至整个系统全部雪崩;

下面详细说下一致性hash算法(以redis存储为例),来解决上面遇到的问题:

一致性hash算法,不管你的应用有多少,都使用2^32(2的32次方)作为取模,并且将0和2^32-1首尾相连,结成一个环,这样所有使用一致性hash算法的数据都大概率均匀的落在这个环上

落在环上面的数据又是怎么落到不同的redis服务器上的呢?我们不管是使用redis服务器的IP也好,域名也好,总之是一个唯一标识,通过计算hash值也落在这个环上(ABCD服务器节点),然后规定把落在环上的数据以顺时针的方向旋转,保存在遇到的第一个节点(服务器)上,这很好理解; 如下图所示:

使用了一致性hash之后,我们服务器的扩展也会变得很容易,如果监控到某个节点(D)压力比较大,则通过计算hash值,在这个节点的逆时针上游加一个服务器E(A和D之间),如下图:

这时候如果有请求进来,在整个环上的数据,只有A到E之间的数据获取不到从而对下层数据库有影响,而其他的所有数据不会有任何影响,由此可见使用一致性hash扩展是十分方便的!

一致性hash存在的问题:

1,雪崩效应:假设我们并没有上面说的类似的监控,或者某个节点(B)的数据激增,在我们的反应之前,这个时候这个节点出现了宕机,那么所有的数据请求将迅速落在A上,A不仅承受自己的数据,还要承受B的,肯定也马上奔溃,最终整个缓存系统发生缓存雪崩效应

2,分布不均匀: 上面的例子对于hash算法过于理想化了,比如ABCD四台服务器的hash值刚好为1,2,3,4也就代表着hash值在(4,2^32-1]这个范围的所有数据将落在一台服务上,这也将是灾难性的。。。

那么我们怎么解决这种数据分布十分不均匀的情况呢?

解决办法:最好的办法就是增加虚拟节点,截图如下: 

ABCD对每个服务器A,B,C,D都新增了一个(也可以是多个)虚拟节点,也就是说现在A节点可以接受B2-A1加上C1到A2的数据,假设A服务宕机了,那么A1的数据将落在C2(也就是C),A2的数据将落在D1(也就是D)上,也就是说随着崩溃的服务器增多,相对应的数据将分散在更多的服务器,从而防止整个缓存系统的持续雪崩效应;

经过上述的案例,我们能看到一致性hash遵循的原则有下列几个: ①,平衡性:数据将尽可能的均匀分布在整个hash环上,

②,单调性:在扩展的时候,将保证原来的数据尽量少的落在新的节点上。

③,分散性:相同的内容尽量避免落在不同的节点上去!

一致性hash原理很简单,但是一致性hash算法广泛的用在了诸如redis集群,数据库分库分表等情景当中,良好解决了数据分布不均,扩展困难的难题,是大规模集群中的优良算法!


以上是关于谈谈什么一致性hash算法?的主要内容,如果未能解决你的问题,请参考以下文章

关于什么是一致性hash算法

架构实践使用 golang 实现一致性Hash算法代码

图解一致性hash算法和实现

Java实现一致性Hash算法深入研究

算法 一致性hash/hash环

算法 一致性hash/hash环