理解一致性哈希算法

news2024/11/24 20:01:54

摘要:一致性哈希是什么,使用场景,解决了什么问题?

本文分享自华为云社区《16 张图解 | 一致性哈希算法》,作者:小林coding。

如何分配请求?

大多数网站背后肯定不是只有一台服务器提供服务,因为单机的并发量和数据量都是有限的,所以都会用多台服务器构成集群来对外提供服务。

但是问题来了,现在有那么多个节点(后面统称服务器为节点,因为少一个字),要如何分配客户端的请求呢?

cke_129.png

其实这个问题就是「负载均衡问题」。解决负载均衡问题的算法很多,不同的负载均衡算法,对应的就是不同的分配策略,适应的业务场景也不同。

最简单的方式,引入一个中间的负载均衡层,让它将外界的请求「轮流」的转发给内部的集群。比如集群有 3 个节点,外界请求有 3 个,那么每个节点都会处理 1 个请求,达到了分配请求的目的。

cke_130.png

考虑到每个节点的硬件配置有所区别,我们可以引入权重值,将硬件配置更好的节点的权重值设高,然后根据各个节点的权重值,按照一定比重分配在不同的节点上,让硬件配置更好的节点承担更多的请求,这种算法叫做加权轮询。

加权轮询算法使用场景是建立在每个节点存储的数据都是相同的前提。所以,每次读数据的请求,访问任意一个节点都能得到结果。

但是,加权轮询算法是无法应对「分布式系统」的,因为分布式系统中,每个节点存储的数据是不同的。

当我们想提高系统的容量,就会将数据水平切分到不同的节点来存储,也就是将数据分布到了不同的节点。比如一个分布式 KV(key-valu) 缓存系统,某个 key 应该到哪个或者哪些节点上获得,应该是确定的,不是说任意访问一个节点都可以得到缓存结果的。

因此,我们要想一个能应对分布式系统的负载均衡算法。

使用哈希算法有什么问题?

有的同学可能很快就想到了:哈希算法。因为对同一个关键字进行哈希计算,每次计算都是相同的值,这样就可以将某个 key 确定到一个节点了,可以满足分布式系统的负载均衡需求。

哈希算法最简单的做法就是进行取模运算,比如分布式系统中有 3 个节点,基于 hash(key) % 3 公式对数据进行了映射。

如果客户端要获取指定 key 的数据,通过下面的公式可以定位节点:

hash(key) % 3复制

如果经过上面这个公式计算后得到的值是 0,就说明该 key 需要去第一个节点获取。

但是有一个很致命的问题,如果节点数量发生了变化,也就是在对系统做扩容或者缩容时,必须迁移改变了映射关系的数据,否则会出现查询不到数据的问题。

举个例子,假设我们有一个由 A、B、C 三个节点组成分布式 KV 缓存系统,基于计算公式 hash(key) % 3 将数据进行了映射,每个节点存储了不同的数据:

cke_131.png

现在有 3 个查询 key 的请求,分别查询 key-01,key-02,key-03 的数据,这三个 key 分别经过 hash() 函数计算后的值为 hash( key-01) = 6、hash( key-02) = 7、hash(key-03) = 8,然后再对这些值进行取模运算。

通过这样的哈希算法,每个 key 都可以定位到对应的节点。

cke_132.png

当 3 个节点不能满足业务需求了,这时我们增加了一个节点,节点的数量从 3 变化为 4,意味取模哈希函数中基数的变化,这样会导致大部分映射关系改变,如下图:

cke_133.png

比如,之前的 hash(key-01) % 3 = 0,就变成了 hash(key-01) % 4 = 2,查询 key-01 数据时,寻址到了节点 C,而 key-01 的数据是存储在节点 A 上的,不是在节点 C,所以会查询不到数据。

同样的道理,如果我们对分布式系统进行缩容,比如移除一个节点,也会因为取模哈希函数中基数的变化,可能出现查询不到数据的问题。

要解决这个问题的办法,就需要我们进行迁移数据,比如节点的数量从 3 变化为 4 时,要基于新的计算公式 hash(key) % 4 ,重新对数据和节点做映射。

假设总数据条数为 M,哈希算法在面对节点数量变化时,最坏情况下所有数据都需要迁移,所以它的数据迁移规模是 O(M),这样数据的迁移成本太高了。

所以,我们应该要重新想一个新的算法,来避免分布式系统在扩容或者缩容时,发生过多的数据迁移。

使用一致性哈希算法有什么问题?

一致性哈希算法就很好地解决了分布式系统在扩容或者缩容时,发生过多的数据迁移的问题。

一致哈希算法也用了取模运算,但与哈希算法不同的是,哈希算法是对节点的数量进行取模运算,而一致哈希算法是对 2^32 进行取模运算,是一个固定的值

我们可以把一致哈希算法是对 2^32 进行取模运算的结果值组织成一个圆环,就像钟表一样,钟表的圆可以理解成由 60 个点组成的圆,而此处我们把这个圆想象成由 2^32 个点组成的圆,这个圆环被称为哈希环,如下图:

cke_134.png

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

  • 第一步:对存储节点进行哈希计算,也就是对存储节点做哈希映射,比如根据节点的 IP 地址进行哈希;
  • 第二步:当对数据进行存储或访问时,对数据进行哈希映射;

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

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

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

举个例子,有 3 个节点经过哈希计算,映射到了如下图的位置:

cke_135.png

接着,对要查询的 key-01 进行哈希计算,确定此 key-01 映射在哈希环的位置,然后从这个位置往顺时针的方向找到第一个节点,就是存储该 key-01 数据的节点。

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

cke_136.png

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

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

知道了一致哈希寻址的方式,我们来看看,如果增加一个节点或者减少一个节点会发生大量的数据迁移吗?

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

cke_137.png

你可以看到,key-01、key-03 都不受影响,只有 key-02 需要被迁移节点 D。

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

cke_138.png

你可以看到,key-02 和 key-03 不会受到影响,只有 key-01 需要被迁移节点 B。

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

上面这些图中 3 个节点映射在哈希环还是比较分散的,所以看起来请求都会「均衡」到每个节点。

但是一致性哈希算法并不保证节点能够在哈希环上分布均匀,这样就会带来一个问题,会有大量的请求集中在一个节点上。

比如,下图中 3 个节点的映射位置都在哈希环的右半边:

cke_139.png

这时候有一半以上的数据的寻址都会找节点 A,也就是访问请求主要集中的节点 A 上,这肯定不行的呀,说好的负载均衡呢,这种情况一点都不均衡。

另外,在这种节点分布不均匀的情况下,进行容灾与扩容时,哈希环上的相邻节点容易受到过大影响,容易发生雪崩式的连锁反应。

比如,上图中如果节点 A 被移除了,当节点 A 宕机后,根据一致性哈希算法的规则,其上数据应该全部迁移到相邻的节点 B 上,这样,节点 B 的数据量、访问量都会迅速增加很多倍,一旦新增的压力超过了节点 B 的处理能力上限,就会导致节点 B 崩溃,进而形成雪崩式的连锁反应。

所以,一致性哈希算法虽然减少了数据迁移量,但是存在节点分布不均匀的问题

如何通过虚拟节点提高均衡度?

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

但问题是,实际中我们没有那么多节点。所以这个时候我们就加入虚拟节点,也就是对一个真实节点做多个副本。

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

比如对每个节点分别设置 3 个虚拟节点:

  • 对节点 A 加上编号来作为虚拟节点:A-01、A-02、A-03
  • 对节点 B 加上编号来作为虚拟节点:B-01、B-02、B-03
  • 对节点 C 加上编号来作为虚拟节点:C-01、C-02、C-03

引入虚拟节点后,原本哈希环上只有 3 个节点的情况,就会变成有 9 个虚拟节点映射到哈希环上,哈希环上的节点数量多了 3 倍。

cke_140.png

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

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

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

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

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

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

总结

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

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

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

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

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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1068489.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2021年03月 Python(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python编程(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 对于字典infor {“name”:“tom”, “age”:13, “sex”:“male”},删除"age":13键值对的操作正确的…

06_Node.js服务器开发

1 服务器开发的基本概念 1.1 为什么学习服务器开发 Node.js开发属于服务器开发,那么作为一名前端工程师为什么需要学习服务器开发呢? 为什么学习服务器开发? 能够和后端程序员更加紧密配合网站业务逻辑前置扩宽知识视野 1.2 服务器开发可…

强制删除文件?正确操作方法分享!

“我昨天在删除文件时有个文件一直删除不掉。想用强制删除的方法来把它删掉,应该怎么操作呢?谁能教教我呀?” 在使用电脑的过程中,我们有时候可能会发现文件无论怎么删除都无法删掉,如果我们想要强制删除文件但不知道怎…

selenium-webdriver-Chrome新驱动地址(Chrome115及以上版本)

Chrome115、Chrome116、Chrome117,在旧的链接并没有 新地址:https://googlechromelabs.github.io/chrome-for-testing/ 参考学习链接(我也是根据这个老师的链接学到的):https://www.cnblogs.com/wuxianfeng023/p/1765…

JVM完整图文学习笔记(含拓展知识广度学习)第一章:内存结构

目录 内存结构 程序计数器 概述: 为什么私有化? 性能优化 安全性高 成本较低 为什么程序计数器不会存在内存溢出? 虚拟机栈 概述: 问题辨析: 垃圾回收是否涉及栈内存? 栈内存分配越大越好吗&#xf…

mariadb 错误日志中报错:Incorrect definition of table mysql.column_stats:

数据库错误日志出现此错误原因是因为系统表中字段类型或者数据结构有变动导致,一般是因为升级数据库版本后未同步升级系统表结构。 解决方法: 1.如果错误日志过大,直接删除。 2.执行 mysql_upgrade -u[用户名] -p[密码];,这一步…

计算机考研 | 2017年 | 计算机组成原理真题

文章目录 【计算机组成原理2017年真题43题-13分】【第一步:信息提取】【第二步:具体解答】 【计算机组成原理2017年真题44题-10分】【第一步:信息提取】【第二步:具体解答】 【计算机组成原理2017年真题43题-13分】 (1…

南美巴西市场最全分析开发攻略,收藏一篇就够了

巴西位于南美洲东部,是南美洲资源最丰富,经济活力和经济实力最强的国家。巴西作为拉丁美洲的出口大国,一直是一个比较有潜力的市场,亦是我国外贸公司和独立外贸人集群的地方。中国长期是巴西主要的合作伙伴,2022年占巴…

探究IO多路复用select/poll/epoll的实现原理及优缺点

IO多路复用 多路指多个文件描述符,复用指使用一个线程。 IO多路复用通俗的理解就是一个线程监视多个文件描述符****,一旦某个文件描述符就绪,就通知应用程序对其进行读写操作。 select select会将三个fd_set文件描述符集合(bitMap),即读集…

java 汽车修理厂修配厂-接单-处理收款 日常经营管理系统 汽车修理信息管理

实现修配厂一体化管理,从业务各个环节整体管理,包括接待,维修,采购,质检,交车,收款等业务操作环节,全方位,闭环管理,精细化管理。充费利用信息技术资源&#…

coreldraw和ai哪个好用?有哪些区别

CorelDRAW和Illustrator是两款常被比较的矢量绘图软件,它们在功能上各具特色,在绘图领域中都有一席之地。大多数效果都可以在这两款软件上完成,因此它们在功能上差异不大。 然而,就操作而言,我必须承认CorelDRAW更加便…

蓝牙资讯|三星发布Galaxy SmartTag 2,苹果Find My引领防丢市场

三星发布新品 —— Galaxy SmartTag 2 防丢器,该产品售价 29.99 美元。外观方面,Galaxy SmartTag 2 采用了全新的椭圆设计取代上代 SmartTag 的菱形设计,钥匙孔也比上代更大,并升级采用金属圆环以防止磨损,新品提供黑色…

Kafka在企业级应用中的实践

前言 前面说了很多Kafka的性能优点,有些童鞋要说了,这Kafka在企业开发或者企业级应用中要怎么用呢?今天咱们就来简单探究一下。 1、 使用 Kafka 进行消息的异步处理 Kafka 提供了一个可靠的消息传递机制,使得企业能够将不同组件…

[UUCTF 2022 新生赛]ezpop - 反序列化+字符串逃逸【***】

[UUCTF 2022 新生赛]ezpop 一、解题过程二、其他WP三、总结反思 一、解题过程 题目代码&#xff1a; <?php //flag in flag.php error_reporting(0); class UUCTF{public $name,$key,$basedata,$ob;function __construct($str){$this->name$str;}function __wakeup(){i…

Vue Router(二)

目录 一、嵌套路由 1、路由定义 2、代码例子 3、重定向 二、懒加载 1、缘由 2、代码例子 三、导航守卫 1、全局前置守卫 2、全局后置守卫 3、meta元信息 四、生命周期 1、解释 2、执行顺序 3、例子 五、keep-alive组件缓存&#xff08;保活&#xff09; 1、介…

AT2659S——L1频段卫星导航射频前端低噪声放大器芯片

AT2659S芯片采用2.9 mm 2.8mm 1.1 mm的6 pin SOT23-6封装。 应用领域&#xff1a; 导航天线 集成导航功能的手机 自动导航 定位功能移动设备 个人导航仪 笔记本/PAD AT2659S 是一款具有低功耗、高增益、低噪声系数的低噪声放大器&#xff08;LNA&#xff09;芯片&#x…

32、Flink table api和SQL 之用户自定义 Sources Sinks实现及详细示例

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

虚拟机Ubuntu18.04安装对应ROS版本详细教程!(含错误提示解决)

参考链接&#xff1a; Ubuntu18.04安装Ros(最新最详细亲测)_向日葵骑士Faraday的博客-CSDN博客 1.4 ROS的安装与配置_哔哩哔哩_bilibili ROS官网&#xff1a;http://wiki.ros.org/melodic/Installation/Ubuntu 一、检查cmake 安装ROS时会自动安装旧版的Cmake3.10.2。所以在…

Thingsboard二次开发---5.在Thingsboard中增加解决方案管理功能

前言 在使用Thingsboard的过程中发现TB虽然非常灵活&#xff0c;但实际的最终用户更希望是针对特定场景的成熟解决方案&#xff0c;页面都做好&#xff0c;不需要再进行配置&#xff0c;所以在原来的基础上增加了解决方案的功能&#xff0c;此方案比较适合给用户提供SaaS化的解…

【Hugging Face】如何从hub中下载文件

huggingface_hub库提供了从存储在Hub上的仓库中下载文件的功能。您可以独立使用这些函数或将它们集成到您自己的库中&#xff0c;使您的用户更方便地与Hub交互。本指南将向您展示如何&#xff1a; 下载并缓存单个文件。下载并缓存整个代码库。将文件下载到本地文件夹。 下载单…