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

引言

对于哈希算法,相信大家一定不会很陌生,其经常被用在负载均衡、分库分表等场景中,比如我们在做分库分表的时候,最开始根据业务分析,只需要 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. 那么服务器要是没那么充足,这个怎么解决,这个也比较简单,我们可以引入一些虚拟节点。即我们将一个服务器节点拆分成多个虚拟节点,然后数据在映射的时候先将数据映射到虚拟节点上,然后虚拟节点在对应的物理节点进行存储和读取就可以了,有了虚拟节点的接入,数据在分布的时候就会尽可能地分散,然后在增加或者减少服务器数量的时候,受到影响的数据范围也不会有那么多。
相关推荐
编程洪同学16 分钟前
Spring Boot 中实现自定义注解记录接口日志功能
android·java·spring boot·后端
RodrickOMG32 分钟前
【大数据】Hadoop三节点集群搭建
大数据·hadoop·分布式
GraduationDesign1 小时前
基于SpringBoot的蜗牛兼职网的设计与实现
java·spring boot·后端
乄北城以北乀1 小时前
第1章 R语言中的并行处理入门
开发语言·分布式·r语言
颜淡慕潇1 小时前
【K8S问题系列 | 20 】K8S如何删除异常对象(Pod、Namespace、PV、PVC)
后端·云原生·容器·kubernetes
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS安康旅游网站(JAVA毕业设计)
java·vue.js·spring boot·后端·kafka·开源·旅游
搬码后生仔2 小时前
将 ASP.NET Core 应用程序的日志保存到 D 盘的文件中 (如 Serilog)
后端·asp.net
Suwg2092 小时前
《手写Mybatis渐进式源码实践》实践笔记(第七章 SQL执行器的创建和使用)
java·数据库·笔记·后端·sql·mybatis·模板方法模式
凡人的AI工具箱3 小时前
每天40分玩转Django:Django文件上传
开发语言·数据库·后端·python·django
spcodhu4 小时前
在 Ubuntu 上搭建 MinIO 服务器
linux·后端·minio