vlambda博客
学习文章列表

轻松搞懂一致性哈希算法

一致性哈希算法在1997年由麻省理工学院提出,是一种特殊的哈希算法,在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系。


在分布式系统中也是一种常用的分片算法或数据库分表分库算法。



我们先来了解下常用的一种路由方案,再来研究一致性哈希算法,通过对比更能理解一致性哈希算法的优点。



普通哈希算法


假设一个我们有三台用于文件存储的服务器,为了能够将文件均匀地存储到这三台服务器上,我们需要使用某种规则来进行路由,一般使用如下公式:


hash(文件名) % 服务器数量


首先我们对文件服务器进行编号,分别为0、1、2;


再使用文件名的哈希值模3,得到的结果正好也是这三个编号,使用这种方式将每个文件存储到对应的服务器上;


需要读取文件时,也使用相同的方式计算出对应的服务器编号。


这是一种比较常见的路由方式,但是这种方式有一个比较大的缺陷:当服务器数量变化时,原先缓存的数据将大范围失效,产生雪崩现象。


比如在系统运行一段时间后由于存储的文件过多,导致需要扩充服务器数量,由原先的三台增加到四台,按照这个计算方式,服务器数量发生改变,公式的计算结果也会跟着改变,那么原先三台服务器上的文件绝大部分将无法命中,需要进行大量的数据迁移工作。


那么一致性哈希算法是如何来解决这个问题的呢?



一致性哈希算法


一致性哈希算法其实也是通过取余的方式,只是不是对服务器数量取余,而是对2^32取余。


首先我们构建一个圆环,圆环上有2^32个点,每个点编号为0~2^32-1,可以理解为一个首尾相接的链表;

我们把这个由2^32个点组成的圆环就称为哈希环。


那么这个看似简单的哈希环怎么解决刚刚我们提到的雪崩问题呢?


首先我们使用如下规则将三台服务器分别映射到哈希环上的某个点;


hash(主机名或IP) % 2^32


假设三台服务器分别叫A、B、C,映射后的结果如下图所示:

轻松搞懂一致性哈希算法

再将需要存储或读取的文件与哈希环进行映射,聪明的你是不是已经想到映射规则了?没错就是下面这个:


hash(文件名) % 2^32


映射后的结果如下图所示:

轻松搞懂一致性哈希算法

好了,现在我们已经将服务器和文件都是映射到哈希环上了,那么我们如何确定到底该使用哪台服务器呢?


很简单,只要从文件映射的位置开始顺时针进行查找,查找到的第一台服务器就是我们需要使用的服务器,也就是A服务器;

轻松搞懂一致性哈希算法

多个文件进行查找时,如下图所示,对应关系分别为:1->A, 2->B, 3->C, 4->A;

轻松搞懂一致性哈希算法


现在我们来简单总结下整个执行过程:

  1. 构建哈希环;

  2. 将服务器映射到哈希环;

  3. 将文件映射到哈希环;

  4. 顺时针查找服务器;



优点


现在我们已经知道了一致性哈希算法的基本原理,那么它能解决我们文章开头提到的问题吗?我们使用一致性哈希算法来简单模拟下之前提到的场景。


当我们将服务器由三台增加到四台时,服务器在哈希环的映射关系将会是下面情况:

轻松搞懂一致性哈希算法

那么按照之前的文件映射关系进行查找服务器,文件与服务器的对应关系分别为:1->A, 2->B, 3->C, 4->D;

轻松搞懂一致性哈希算法

其中只有文件4受到了影响,确切的说应该是哈希环上C和D之间的这些点位的文件受到影响,其他文件并没有任何变化,这就是一致性哈希算法的优点,服务器数量发生变化时(增加或减少),能够尽量保证对系统较低的影响性。



虚拟节点


刚刚我们有一个重要的步骤就是将服务器映射到哈希环上,刚刚我们举的例子中,服务器在哈希环上分散的比较均匀,但是实际执行起来并不一定能够做到均匀分布,可能出现下图中的情况,服务器映射的位置相对集中,导致服务器负载不均衡,甚至有些服务器根本没有负载,这种情况我们称之为哈希环的倾斜;

轻松搞懂一致性哈希算法

为了应对这种情况,我们可以将实际存在的三台服务器复制一份,再映射到哈希环上,这些复制出来的节点就称之为虚拟节点,用来解决哈希环的倾斜问题。

引入虚拟节点的概念后,各个服务器的负载基本就均衡了。



往期阅读


都看到这里了,为什么不点个关注呢?