700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 一致性Hash算法与虚拟节点

一致性Hash算法与虚拟节点

时间:2018-12-09 12:25:12

相关推荐

一致性Hash算法与虚拟节点

缘起

今天我们来说说“一致性Hash”算法,以及虚拟节点。

这并不是一个难理解的概念,希望一篇文章下来,你能完全吃透。

在网站系统发展初期,前辈工程师探索出了数据库这一系统核心组件,

数据的持久化被与系统本身解耦开,独立发展且愈加可靠。

时间往后推移,随着互联网的普及,一个系统需要承载的用户数量指数级增长,

开发者不得不横向扩展服务器,通过负载均衡技术,使用户分散到各个服务器上。

随着服务器的增多,可靠的数据库系统也不堪重负,

开发者不得不将数据库中的数据通过“分库分表”技术,切分到不同的数据库中,

减轻单一数据库系统的压力。

那么问题来了,如何知道我们需要的数据在哪个数据库中?

没错。hash!

正如我们在 HashMap 中做的一样,对参数取 hash 值,再对 hash 值取模,

就可以既均匀切分存储数据,又知道数据在哪个库中。

简单hash

举个例子,现在有A,B,C,D共4个库,和参数为1,2,3……9,10共10个数据。

我们简化hash算法为乘以1,

即 (1*1)%4=1,参数为1的数据落在A库中。

即 (2*1)%4=2,参数为2的数据落在B库中。

即 (3*1)%4=3,参数为3的数据落在C库中。

即 (4*1)%4=0,参数为4的数据落在D库中。

……

嗯!我很满意,一切井然有序。

当系统需要参数为2的数据时,只需要通过定位算法 (2*1)%4=2 便知道数据存在B库中。

当系统需要参数为9的数据时,只需要通过定位算法 (9*1)%4=1 便知道数据存在A库中。

可好景不长,正当系统稳定健康运行的时候,

B库不知道出现什么问题,失去了连接,系统中只剩下A,C,D共3个库。

这可真糟糕,但是我们还不知道会发生什么事情,对系统的影响有多大。

让我们先把目光聚集到局部上面来分析一下,

参数为2,6和10的数据存在B库上,影响应该是最大的,

如果现在系统需要参数为2的数据,那么它会通过定位算法 (2*1)%3=2 找到C库上。

但很遗憾,C上并没有存储参数为2的数据。

值得庆幸的是,原来数据是有副本的,失去连接的B库数据并没有丢失,而是在一个更大的主库中,

只要给系统一些时间,主库中对应B库的数据,就会根据定位算法被重新分配到A,C,D库中。

分配如下,

即 (2*1)%3=2,参数为2的数据落在C库中。

即 (6*1)%3=0,参数为6的数据落在D库中。

即 (10*1)%3=1,参数为10的数据落在A库中。

好了,现在原来B库中的数据被重新分配到A,C,D库。

当系统需要取数据的时候,只需要通过参数根据定位算法,

到对应的库中读取即可。

如果现在你以为万事大吉,那可就太早了。

别忘了我们刚刚是聚焦到局部来分析状况的。

当我们目光拉远时,我们发现,

不止是参数为2,6,10的数据被重新分配,

几乎所有的数据都被重新分配了!

因为,

(1*1)%3=1,参数为1的数据落在A库中。

(2*1)%3=2,参数为2的数据落在C库中。

(3*1)%3=0,参数为3的数据落在D库中。

……

真是糟糕透顶!

原本是想节约提高性能,结果凭空需要浪费这么多计算资源在重新分配数据上。

该怎么办呢?

诶,对,一致性Hash算法要大显身手了!

一致性Hash算法

一致性Hash算法通过一个 Hash 环,巧妙的让影响降到很低。

假设存在一个 Hash 环,它一圈的范围是 0 到 2^32-1,

先对数据库A,B,C和D的标识做 hash 运算,即上面的定位算法,

确定4个库在 Hash 环上的位置,

再通过定位算法将得出参数为1,2,3……9,10共10个数据在 Hash环上的位置,

这边我们不展示过程,只展示结果。

一致性Hash算法规定我们将数据存在定位到的 Hash 环上位置顺时针遇到的第一个节点(数据库)。

即,

参数为1,4和8的数据存在数据库A中,

参数为5的数据存在数据库B中,

参数为3和7的数据存在数据库C中,

参数为2,6,9和10的数据存在数据库D中。

此时,其实我们已经不惧怕数据库宕机的情况了,

假设我们的数据库B又一次失去连接。

会发生什么情况呢?

影响十分有限,只有数据库A和B在 Hash 环上的位置之间的数据,才受到了影响。

如图,参数为5的数据,需要重新从主库中复制到数据库C中,以保证系统需要参数为5的数据时可以顺利读取到。

而对于其他参数值的数据,并没有受到影响。

以上描述的是节点减少的情况,实际上在节点增加的时候,

一致性Hash算法依然可以保持大部分节点的稳定,不需要改变。

在这里我不做赘述,但你参考上面,独立思考一下。

一致性 Hash 算法如果只是到这里,实际上还引入了一个新的问题——数据倾斜。

即我们假设数据落在 Hash 环上每个位置的概率是一致的,

但实际上,每个节点覆盖的 Hash 环上的大小并不相等,

甚至可能有几倍的差距。

例如,在上面A,C,D库的基础上,我们添加了一个节点——数据库E。

它的位置如图所示。

因为它(数据库E)与上一个节点(数据库D)距离太近,导致没有任何一个数据落到它上面,

而正是与他相近特别近的上一个节点(数据库D),却存储了4个数据,

这就是数据倾斜,有些节点承载了很重的任务,有些节点却悠闲悠闲。

虚拟节点

为了解决数据倾斜的问题,我们还需要加入虚拟节点这一策略。

即,将每个数据库都通过定位算法生成几个在 Hash 环上的位置,

每个位置都承担上面节点的功能,

区别在于原来每个数据库对应一个节点,

现在每个数据库会对应若干个节点,

这就是虚拟节点。

为了避免图过于混乱,这边我标出 E 数据库的 3 个虚拟节点,

可以从图中看出,现在

E#1有 0 个数据,

E#2有 1 个数据(参数为5的数据),

E#3有 2 个数据(参数为6和9的数据)。

而实际上,不管数据定位后归属与E#1、E#2还是E#3,

在实际的数据存储和读取时,都是在数据库 E。

不难发现,在添加了虚拟节点的策略之后,

数据倾斜的情况得到了改善。

这就是完整的一致性Hash算法与虚拟节点啦!

记住,在实际应用中,3个虚拟节点是不够的,你需要更多的虚拟节点,以保证节点的负载更加均衡。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。