面试必备:一致性hash算法

为什么要用一致性hash算法?

在学习一致性hash算法之前,首先要考虑下为什么要使用它,使用它能解决什么样的问题。带着问题去学习相信理解起来会更容易。

大家都知道我们在使用redis分片技术,mycat对数据库进行分库分表时都会面临数据操作规则的问题;比如我们把一条记录存入redis3服务器,那么我们获取的时候如果不指定规则就会根据key在所有的redis服务器中进行遍历查找,显然这种情况是我们不想看到的。所以这时候我们就需要引入一些规则来确保数据放入某个redis服务器,取的时候直接去对应的服务器进行查询,而不需要遍历多台服务器。常用的规则有根据hash值来决定存放位置。比如存入一个记录时,我们根据key进行hash运算再用hash值与服务器的数量进行取模:hash(key)/3=X;得出的结果就是记录存放的服务器位置,查询的时候按照相同的公式进行计算,这样就不会遍历所有的服务器,从而大大提供了性能。

虽然使用hash算法可以提高性能,但是也会有一些缺陷,主要体现在服务器数量发生变化(增加/减少)时,所有缓存的位置都会发生改变。例如我们要增加一台缓存服务器(之前三台),hash算法如下hash(key)/4=X;这种情况带来的结果就是服务器数量发生变化时会造成缓存失效,此时请求会发往后端数据库,可能导致缓存雪崩问题。我们不允许这种现象发生,但是利用hash值取模进行缓存时这种情况无法避免,为了解决这些问题,hash一致性算法诞生了。

一致性hash算法背景

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

一致性hash算法:

一致性hash算法也是使用取模的方法,只是上述hash算法是对服务器数量记性取模运算,而一致性hash是对2^32取模。也就是说一致性hash算法将整个hash空间组织成一个圆环:

计算一致性hash步骤如下:

1 首先根据缓存服务器的ip,端口等信息算出哈希值,并将其配置到个数为2的32次方的圆上。

2 然后同样的方法算出存储数据的键的哈希值,并映射到相同的圆上。

3 从数据存储位置开始顺时针查找,将数据保存到找到的第一个服务器上,如果超过2的32次方仍然找不到服务器就会保存在第一台服务器上;取值操作完全相同。

整个环按照顺时针方向进行组织。然后可以用服务器ip,port作为key进行hash从而确定在环中的位置,对数据进行存储时也进行相同的hash算法对key运算确定数据在此环上的位置,从此位置沿顺时针开始遇到的第一个服务器就是数据存放的服务器:

 

当添加一台redis缓存服务器时,只有增加服务器的位置和逆时针方向第一台服务器之间的键会受影响:

一致性hash算法对于节点的增减都只需要重定位环空间中的一小部分数据,具有良好的容错性和可扩展性。

hash环的数据倾斜问题:

一致性hash算法在服务节点太少的情况下容易因为节点部分不均匀造成数据倾斜问题(数据大部分集中在一台缓存服务器);

为了解决这种数据倾斜问题,hash算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个结果未知都放置一个此服务节点,称为虚拟节点,数据定位算法不变,只是多了一个虚拟节点到实际节点的映射,例如定位到NodeA#1,2,3三个虚拟节点的数据均定位到NodeA节点,这样就解决了服务节点少时的数据倾斜问题。在实际应用中,通常将虚拟节点数设置为32甚至更大,这样即使很少的服务节点也能做到相对均匀的数据分布。

一致性hash特性说明:

平衡性(balance)

平衡性是指hash的结果能够尽可能分布有缓存中去,这样可以使得所有的缓存空间都得到利用,当数据出现负载不均时,则采用虚拟节点平衡数据。

单调性(monotonicity)

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

分散性(spread)

在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。

负载(load)

负载问题实际上是从另一个角度看待分散性问题,终端有可能看不到所有的缓冲从而导致不同的key 保存到了相同的位置。

 

现在一致性hash算法在分布式系统中得到了广泛应用,例如memcached,redis等分布式缓存数据库,要注意的是服务端本身不提供分布式cache的一致性,而是由客户端提供的。一致性hash算法是分布式组件负载均衡的首选算法,它即可在客户端实现,也可以在中间件上实现:其应用有:

分布式散列表(DHT)设计;

分布式关系数据库(mysql),分库分表时计算数据与节点的映射关系;

分布式缓存;

RPC框架dubbo,用来选择服务提供者;

Guess you like

Origin blog.csdn.net/u011821510/article/details/89321822