用五分钟的时间告诉你,一致性哈希算法是什么?

引言

对于哈希算法,相信大家一定不会很陌生,其经常被用在负载均衡、分库分表等场景中,比如我们在做分库分表的时候,最开始根据业务分析,只需要 128 张表就可以满足数据量的要求了,但是是这个时候如果你要插入或者查询一条记录的时候,我们就会先把分表键,如 buyer_id 进行 Hash 运算,然后将运算结果对 128 取模,最后就可以得到 0 -127 之间的数字,这样就可以唯一定位到一个分表。

但是随着业务的扩展,128 张表可能已经不够用了,这个时候就需要重新分表了,比如增加一张新的表,这个时候如果采用 Hash 或者取模的方式,就会导致 128 + 1 张表的数据需要重新进行分配,成本非常得高。

而一致性哈希算法就是专门解决这类问题的算法,其可以有效地解决分布式系统中增加或者删除节点时的失效问题。

一致性哈希(Consistent Hashing)是一种用于分布式系统中数据分片和负载均衡的算法。它的目标是在节点的动态增加或者删除的时候,尽可能地减少数据迁移和重新分布的成本。


一致性哈希算法原理

实现一致性哈希算法首先需要构造一个哈希环,然后把他划分为固定数量的虚拟节点,一般都是 。那么他的节点编号就是,如下图所示:

接下来,我们将 128 张表作为节点映射到这些虚拟节点上,每个节点在哈希环上面都有一个对应的虚拟节点:

Hash(table_0000) % 、Hash(table_0001)% 、Hash(table_0002)% 、········

Hash(table_0127) % (如下图所示,将哈希后的虚拟节点分布到哈希环上)

然后将这些表做好 Hash 映射之后,我们就需要存储数据了,现在我们要把一些需要分表的数据也根据同样的算法进行 Hash,并且也将其映射到哈希环上面。

Hash(buyer_id) %

Hash(12321)% 、Hash(34432)% 、Hash(54543)% 、········ Hash(767676) %

经过以上步骤,在这个 Hash 环上面的虚拟节点就包含两部分数据的映射了,一部分是存储数据的分表的映射,一部分是真实要存储的数据的映射。

现在我们思考一个问题,我们最终目的是将这些数据存储到数据库分表中,那么做好哈希之后,这些数据又要保存在哪个数据库表节点中呢?

这个其实很简单就,就是按照数据的位置,沿着顺时针的方向进行查找,找到的第一个接地就是数据要存放的数据库表节点:

因为要存储的数据,以及存储这些数据的数据库分表, Hash 后的值都是固定的,所以在数据库数量不变的情况下,下次想要进行分数据插入或者查询的时候,只需要按照同样的算法去计算一次就能找到对应的分表了。

以上,就是一致性 Hash 算法的原理了,那么现在回到开头那个问题,如果我们要增加一个分表要怎么进行处理?

接下来我们来讨论一下:

一致性 Hash 算法在节点扩容中的应用

我们首先将要增加的表通过一致性 Hash 算法映射到哈希环的虚拟节点中:

这样的话,就会有一部分数据因为节点数量的改变,其顺时针第一个遇到的分表也随之发生了改变。

相比于普通的 Hash 算法,一致性 Hash 算法可以做到在增加服务器之后,影响到的数据范围最小,只影响小范围的数据,然后其他的数据都不需要进行调整。

以上就是一致性哈希算法的原理以及骑在节点扩容中的应用了,现在我们来进行一个小总结。

一致性哈希算法总结

一致性哈希算法其就是将整个哈希空间视为一个环形结构,然后将节点和数据都映射到这个哈希环上面。每一个节点通过计算节点的哈希值,将节点映射到哈希环上的一个位置。然后数据也通过计算出来的哈希值,将数据映射到哈希环上的一个位置。

当有新的数据需要存储时,首先计算数据的哈希值,然后顺时针或逆时针在环上找到最近的节点,将数据存储在这个节点上。当需要查找数据时,同样计算数据的哈希值,然后顺时针或逆时针在环上找到最近的节点,从该节点获取数据。

一致性哈希算法的优缺点:

优点:

  1. 数据均衡:在增加或者删除节点的时候,一致性哈希算法只会影响到少量的数据迁移,保持了数据的均衡性。
  2. 高扩展性:当节点数目发生变化的时候,对于已经存在的数据,只有部分数据需要重新分布,不会影响到整体的数据结构。

但是,作为一个算法,其有优点的同时,一定会有他的缺点:

  1. Hash 倾斜:在节点数较少的情况下,由于哈希空间是有限的,节点的分布可能不够均匀,导致数据倾斜。
  2. 节点的频繁变更: 如果频繁添加或删除节点,可能会导致大量的数据迁移,从而造成系统压力。

Hash 倾斜的解决方法

其实,从图中可以看出, Hash 倾斜的主要问题就是如果数据过于集中,就会导致在节点数量发生变化的时候,会有大量数据发生迁移,从而导致的数据迁移的成本过高,那么对于这个问题,有什么好的解决方法吗?

答案是肯定的,如果没有的话就没有这最后一个小结了,现在我们就来探究一下解决的方法:

  1. 在服务器节点充足的情况下,可以最大程度地增加服务器节点,然后尽可能地分散节点,使得数据分布较为均匀。
  2. 那么服务器要是没那么充足,这个怎么解决,这个也比较简单,我们可以引入一些虚拟节点。即我们将一个服务器节点拆分成多个虚拟节点,然后数据在映射的时候先将数据映射到虚拟节点上,然后虚拟节点在对应的物理节点进行存储和读取就可以了,有了虚拟节点的接入,数据在分布的时候就会尽可能地分散,然后在增加或者减少服务器数量的时候,受到影响的数据范围也不会有那么多。
相关推荐
芊言芊语12 分钟前
分布式缓存服务Redis版解析与配置方式
redis·分布式·缓存
计算机学姐2 小时前
基于python+django+vue的影视推荐系统
开发语言·vue.js·后端·python·mysql·django·intellij-idea
JustinNeil2 小时前
简化Java对象转换:高效实现大对象的Entity、VO、DTO互转与代码优化
后端
青灯文案12 小时前
SpringBoot 项目统一 API 响应结果封装示例
java·spring boot·后端
微尘83 小时前
C语言存储类型 auto,register,static,extern
服务器·c语言·开发语言·c++·后端
计算机学姐3 小时前
基于PHP的电脑线上销售系统
开发语言·vscode·后端·mysql·编辑器·php·phpstorm
月夜星辉雪4 小时前
【RabbitMQ 项目】服务端:路由交换模块
分布式·rabbitmq
super_journey4 小时前
RabbitMq中交换机(Exchange)、队列(Queue)和路由键(Routing Key)
分布式·中间件·rabbitmq
码拉松4 小时前
千万不要错过,优惠券设计与思考初探
后端·面试·架构
白总Server5 小时前
MongoDB解说
开发语言·数据库·后端·mongodb·golang·rust·php