什么是一致性哈希

什么是一致性哈希

    概要

    一个设计良好的分布式哈希方案应该具有良好的单调性,即服务节点的增减不会造成大量哈希重定位。一致性哈希算法就是这样一种哈希方案。

    一致性哈希是一种用于分布式系统中数据分片和负载均衡的算法。在节点增减的时候,只需要重新分配少量的数据,来高效的实现系统扩容或者缩容。

    、背景

    1.  负载均衡

    在具体介绍一致性哈希算法之前,先问一个问题:为什么需要一致性哈希算法?下面我们通过一个案例来回答这个问题。

    假设有这么一种场景:我们有三台缓存服务器分别为:node1、node2、node3,有3000万个缓存数据需要存储在这三台服务器组成的集群中,希望可以将这些数据均匀的缓存到三台机器上,你会想到什么方案呢?

    我们可能首先想到的方案是:

    node_number = hash(key) % N 

    即:对缓存数据的key进行hash运算后取模,N是机器的数量;运算后的结果映射对应集群中的节点。具体如下图所示:

    下图描绘了多节点系统中的传统的哈希取模算法,基于该算法可以实现简单的负载均衡。

     

    当集群中节点的数量N发生变化时,之前的映射规则就可能发生变化。如果集群中每个机器提供的服务没有差别,这不会有什么影响。但对于分布式缓存这种的系统而言,映射规则失效就意味着之前缓存的失效,若同一时刻出现大量的缓存失效,则可能会出现 “缓存雪崩”,这将会造成灾难性的后果。

    要解决此问题,我们必须在其余节点上重新分配所有现有键,这可能是非常昂贵的操作,并且可能对正在运行的系统产生不利影响。当然除了重新分配所有现有键的方案之外,还有另一种更好的方案即使用一致性哈希算法。

    二、一致性哈希算法

    一致性哈希算法就很好地解决了分布式系统在扩容或者缩容时,发生过多的数据迁移的问题。一致性哈希同样使用了取模的方式,不同的是对 2^32 这个固定的值进行取模运算。

    1.  哈希环

    首先,我们把全量的缓存空间当做一个环形存储结构。环形空间总共分成2^32个缓存区。通过对 2^32 进行取模运算的结果值虚拟成一个圆环,环上的刻度对应一个 0~2^32 - 1 之间的数值。如下图:

         

 

    2.  节点入环

    一致性哈希要进行两步哈希:

    第一步:对存储节点进行哈希计算,也就是对存储节点做哈希映射,比如根据节点的 IP 地址进行哈希;

    第二步:当对数据进行存储或访问时,对数据进行哈希映射;

    所以,一致性哈希是指将「存储节点」和「数据」都映射到一个首尾相连的哈希环上。

    问题来了,对「数据」进行哈希映射得到一个结果要怎么找到存储该数据的节点呢?

    答案是,映射的结果值往顺时针的方向的找到第一个节点,就是存储该数据的节点。

    如下图:

       

    图中的 key-01 映射的位置,往顺时针的方向找到第一个节点就是节点 A。

    所以,当需要对指定 key 的值进行读写的时候,要通过下面 2 步进行寻址:

  •   首先,对 key 进行哈希计算,确定此 key 在环上的位置;
  •   然后,从这个位置沿着顺时针方向走,遇到的第一节点就是存储 key 的节点。 

    3. 节点动态变化

     当缓存集群的节点有所增加/减少的时候,普通哈希算法会导致原有哈希映射大面积失效。而一致性哈希整个环形空间的映射仍然会保持顺时针规则,只有一小部分key的归属会受到影响。

     1)增加节点

     假设节点数量从 3 增加到了 4,新的节点 D 经过哈希计算后映射到了下图中的位置:

      

     可以看到,key-1、key-3 都不受影响,只有 key-2 需要被迁移节点 D。 

     2)删除节点

     假设节点数量从 3 减少到了 2,比如将节点 A 移除:

   

     可以看到,key-2 和 key-3 不会受到影响,只有 key-1 需要被迁移节点 B。

     3)节点动态变化产生的影响

     在一致哈希算法中,如果增加或者移除一个节点,仅影响该节点在哈希环上顺时针相邻的后继节点,其它数据也不会受到影响。

     三、数据倾斜与虚拟节点 

     1.  什么是数据倾斜?

     由于哈希计算的随机性,导致一致性哈希算法存在一个致命问题:数据倾斜。

     主要体现在两个方面:

  •   服务器的哈希值在环上可能不会均匀分布
  •   key 的哈希值可能集中在某个服务器周围

     如下图:

      

     也就是说大多数访问请求都会集中少量几个节点的情况。特别是节点太少情况下,容易因为节点分布不均匀造成数据访问的冷热不均。这就失去了集群和负载均衡的意义。另外,在这种节点分布不均匀的情况下,进行容灾与扩容时,哈希环上的相邻节点容易受到过大影响,容易发生雪崩式的连锁反应。    

     2.  如何解决数据倾斜?

    要想解决节点在哈希环上分配不均匀的问题,就是要有大量的节点,节点数越多,哈希环上的节点分布的就越均匀。

    但问题是,实际中我们没有那么多节点。为了优化这种节点太少而产生的不均衡情况,一致性哈希算法引入了「虚拟节点」的概念。也就是对一个真实节点做多个副本。

    具体做法是,不再将真实节点映射到哈希环上,而是将虚拟节点映射到哈希环上,并将虚拟节点映射到实际节点,所以这里有「两层」映射关系。

    如下图:

   

     可以看到,节点数量多了后,节点在哈希环上的分布就相对均匀了。这时候,如果有访问请求寻址到「A-01」这个虚拟节点,接着再通过「A-01」虚拟节点找到真实节点 A,这样请求就能访问到真实节点 A 了。

     上图中,为了方便理解,每个真实节点仅包含 3 个虚拟节点,这样能起到的均衡效果其实很有限。而在实际的工程中,虚拟节点的数量会大很多,比如 Nginx 的一致性哈希算法,每个权重为 1 的真实节点就含有160 个虚拟节点。

     另外,虚拟节点除了会提高节点的均衡度,还会提高系统的稳定性。当节点变化时,会有不同的节点共同分担系统的变化,因此稳定性更高。

     比如,当某个节点被移除时,对应该节点的多个虚拟节点均会移除,而这些虚拟节点按顺时针方向的下一个虚拟节点,可能会对应不同的真实节点,即这些不同的真实节点共同分担了节点变化导致的压力。

     而且,有了虚拟节点后,还可以为硬件配置更好的节点增加权重,比如对权重更高的节点增加更多的虚拟机节点即可。

     因此,带虚拟节点的一致性哈希方法不仅适合硬件配置不同的节点的场景,而且适合节点规模会发生变化的场景

     四、一致性哈希算法应用场景

     一致性哈希算法在分布式系统中具有广泛的应用场景,以下是一些常见的应用场景:

     1.  缓存系统

    一致性哈希算法被广泛用于分布式缓存系统,例如分布式内存缓存(如 Memcached)或分布式键值存储(如 Redis)。通过将数据根据哈希值映射到缓存节点,可以实现负载均衡和数据分布的优化;

      实际应用中,相比较传统的关系型数据库,一致性哈希算法更多地应用于分布式缓存系统,由于分布式缓存系统的节点部署变化更频繁,而传统关系型数据库的分库分表相对稳定。不过说到mysql,在水平分库分表的过程中, 仍然可以采用一致性哈希的思想。虽然这样的处理逻辑会复杂一些,却可以避免动态水平扩展时候的问题。

     2.  分布式文件系统

     一致性哈希算法可用于分布式文件系统中的数据分片和数据块的分配。它可以将文件块映射到不同的存储节点上,实现数据的分散存储和高吞吐量的访问;

     3.  负载均衡器

     一致性哈希算法可以用于负载均衡器(如反向代理或负载均衡服务器)的请求路由。它可以将请求路由到后端服务器集群中的不同节点,实现负载均衡和故障恢复;

     4.  分布式数据库

    一致性哈希算法可以用于分布式数据库系统中的数据分片和数据复制。它可以将数据均匀地分布在多个节点,并确保数据的可用性和一致性;

     5.  分布式哈希表

     一致性哈希算法可以用于实现分布式哈希表,使得数据可以分布在多个节点上,并提供高效的键值查找和存储;

     6.  分布式消息队列

    一致性哈希算法可用于分布式消息队列中的消息路由和分发。它可以确保消息被正确地路由到相应的消费者节点上,实现高吞吐量和可靠的消息传递。

    、总结

    1.  不同的负载均衡算法适用的业务场景也是不同的

    轮询这类的策略只能适用与每个节点的数据都是相同的场景,访问任意节点都能请求到数据。但是不适用分布式系统,因为分布式系统意味着数据水平切分到了不同的节点上,访问数据的时候,一定要寻址存储该数据的节点。

    哈希算法虽然能建立数据和节点的映射关系,但是每次在节点数量发生变化的时候,最坏情况下所有数据都需要迁移,这样太麻烦了,所以不适用节点数量变化的场景。

    2.  为了减少迁移的数据量,就出现了一致性哈希算法

    一致性哈希是指将「存储节点」和「数据」都映射到一个首尾相连的哈希环上,如果增加或者移除一个节点,仅影响该节点在哈希环上顺时针相邻的后继节点,其它数据也不会受到影响。

    但是一致性哈希算法并不保证节点能够在哈希环上分布均匀,可能会出现大量请求都集中在一个节点的情况,在这种情况下进行容灾与扩容时,容易出现雪崩的连锁反应。

    3. 虚拟节点

    为了解决一致性哈希算法不能够均匀的分布节点的问题,就需要引入虚拟节点,对一个真实节点做多个副本。不再将真实节点映射到哈希环上,而是将虚拟节点映射到哈希环上,并将虚拟节点映射到实际节点,所以这里有「两层」映射关系。

    引入虚拟节点后,可以会提高节点的均衡度,还会提高系统的稳定性。所以,带虚拟节点的一致性哈希算法不仅适合硬件配置不同的节点的场景,而且适合节点规模会发生变化的场景。

     

    参考链接:https://www.xiaolincoding.com

posted @ 2024-04-06 22:21  欢乐豆123  阅读(24)  评论(0编辑  收藏  举报