文章目录

  • 1.一致性哈希算法的问题
  • 2.哈希算法的应用场景
  • 3.如何分配请求?
  • 4.加权轮询算法解决负载均衡问题
  • 5.哈希算法带来的问题
  • 6.一致性哈希算法带来的问题
  • 7.虚拟节点提高一致性哈希算法的均衡度
  • 8.小结

1.一致性哈希算法的问题

问题描述: 例如手机朋友网有n个服务器,为了方便用户的访问会在服务器上缓存数据,因此用户每次访问的时候最好能保持同一台服务器。

已有的做法是根据ServerIPIndex[QQNUM%n]得到请求的服务器,这种方法很方便将用户分到不同的服务器上去。但是如果一台服务器死掉了,那么n就变为了n-1,那么ServerIPIndex[QQNUM%n]与ServerIPIndex[QQNUM%(n-1)]基本上都不一样了,所以大多数用户的请求都会转到其他服务器,这样会发生大量访问错误。

  • 问: 如何改进或者换一种方法,使得:
    (1) 一台服务器死掉后,不会造成大面积的访问错误,
    (2)原有的访问基本还是停留在同一台服务器上;
    (3)尽量考虑负载均衡。(思路:往分布式一致哈希算法方面考虑。)

2.哈希算法的应用场景

在做服务器负载均衡时候可供选择的负载均衡的算法有很多,包括: 轮循算法(Round Robin)、哈希算法(HASH)、最少连接算法(Least Connection)、响应速度算法(Response Time)、加权法(Weighted )等。其中哈希算法是最为常用的算法。

典型的应用场景是: 有N台服务器提供缓存服务,需要对服务器进行负载均衡,将请求平均分发到每台服务器上,每台机器负责1/N的服务。

常用的算法是对hash结果取余数 (hash() mod N):对机器编号从0到N-1,按照自定义的hash()算法,对每个请求的hash()值按N取模,得到余数i,然后将请求分发到编号为i的机器。

但这样的算法方法存在致命问题,如果某一台机器宕机,那么应该落在该机器的请求就无法得到正确的处理,这时需要将当掉的服务器从算法从去除,此时候会有(N-1)/N的服务器的缓存数据需要重新进行计算;

如果新增一台机器,会有N /(N+1)的服务器的缓存数据需要进行重新计算。对于系统而言,这通常是不可接受的颠簸(因为这意味着大量缓存的失效或者数据需要转移)。

那么,如何设计一个负载均衡策略,使得受到影响的请求尽可能的少呢?

  • 在Memcached、Key-Value Store、Bittorrent DHT、LVS中都采用了Consistent Hashing算法,可以说Consistent Hashing 是分布式系统负载均衡的首选算法。

3.如何分配请求?

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

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

  • 这就是所谓的负载均衡问题

4.加权轮询算法解决负载均衡问题

最简单的方式,引入一个中间的负载均衡层,让它将外界的请求「轮流」的转发给内部的集群。

  • 比如集群有 3 个节点,外界请求有 3 个,那么每个节点都会处理 1 个请求,达到了分配请求的目的。
  • 考虑到每个节点的硬件配置有所区别,我们可以引入权重值,将硬件配置更好的节点的权重值设高,然后根据各个节点的权重值,按照一定比重分配在不同的节点上,让硬件配置更好的节点承担更多的请求,这种算法叫做加权轮询
  • 加权轮询算法使用场景是建立在每个节点存储的数据都是相同的前提。所以,每次读数据的请求,访问任意一个节点都能得到结果。

缺点:

  • 但是,加权轮询算法是无法应对「分布式系统」的,因为分布式系统中,每个节点存储的数据是不同的。
  • 当我们想提高系统的容量,就会将数据水平切分到不同的节点来存储,也就是将数据分布到了不同的节点。
    比如一个分布式 KV(key-valu) 缓存系统,某个 key 应该到哪个或者哪些节点上获得,应该是确定的,不是说任意访问一个节点都可以得到缓存结果的。
  • 因此,我们要想一个能应对分布式系统的负载均衡算法。

5.哈希算法带来的问题

有的同学可能很快就想到了:哈希算法。

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

  • 哈希算法最简单的做法就是进行取模运算,比如分布式系统中有 3 个节点,基于 hash(key) % 3 公式对数据进行了映射。
  • 如果客户端要获取指定 key 的数据,通过下面的公式可以定位节点:
hash(key) % 3
如果经过上面这个公式计算后得到的值是 0,就说明该 key 需要去第一个节点获取
  • 但是有一个很致命的问题,如果节点数量发生了变化,也就是在对系统做扩容或者缩容时,必须迁移改变了映射关系的数据,否则会出现查询不到数据的问题。

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

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

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

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

  • 比如,之前的 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),这样数据的迁移成本太高了。

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

6.一致性哈希算法带来的问题

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

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

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

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

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

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

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

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

  • 答案是,映射的结果值往顺时针的方向的找到第一个节点,就是存储该数据的节点。
  • 举个例子,有 3 个节点经过哈希计算,映射到了如下图的位置:
    接着,对要查询的 key-01 进行哈希计算,确定此 key-01 映射在哈希环的位置,然后从这个位置往顺时针的方向找到第一个节点,就是存储该 key-01 数据的节点。

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

    所以,当需要对指定 key 的值进行读写的时候,要通过下面 2 步进行寻址:
  • 首先,对 key 进行哈希计算,确定此 key 在环上的位置;
  • 然后,从这个位置沿着顺时针方向走,遇到的第一节点就是存储 key 的节点。

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

  • 假设节点数量从 3 增加到了 4,新的节点 D 经过哈希计算后映射到了下图中的位置:
    你可以看到,key-01、key-03 都不受影响,只有 key-02 需要被迁移节点 D。

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

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

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

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

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

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

  • 另外,在这种节点分布不均匀的情况下,进行容灾与扩容时,哈希环上的相邻节点容易受到过大影响,容易发生雪崩式的连锁反应。
    比如,上图中如果节点 A 被移除了,当节点 A 宕机后,根据一致性哈希算法的规则,其上数据应该全部迁移到相邻的节点 B 上,这样,节点 B 的数据量、访问量都会迅速增加很多倍,一旦新增的压力超过了节点 B 的处理能力上限,就会导致节点 B 崩溃,进而形成雪崩式的连锁反应。

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

7.虚拟节点提高一致性哈希算法的均衡度

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

  • 但问题是,实际中我们没有那么多节点。所以这个时候我们就加入虚拟节点,也就是对一个真实节点做多个副本。
  • 具体做法是,不再将真实节点映射到哈希环上,而是将虚拟节点映射到哈希环上,并将虚拟节点映射到实际节点,所以这里有「两层」映射关系。

比如对每个节点分别设置 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 倍。

你可以看到,节点数量多了后,节点在哈希环上的分布就相对均匀了。

  • 这时候,如果有访问请求寻址到「A-01」这个虚拟节点,接着再通过「A-01」虚拟节点找到真实节点 A,这样请求就能访问到真实节点 A 了。

  • 上面为了方便你理解,每个真实节点仅包含 3 个虚拟节点,这样能起到的均衡效果其实很有限。

  • 而在实际的工程中,虚拟节点的数量会大很多,比如 Nginx 的一致性哈希算法,每个权重为 1 的真实节点就含有160 个虚拟节点。

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

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

  • 而且,有了虚拟节点后,还可以为硬件配置更好的节点增加权重,比如对权重更高的节点增加更多的虚拟机节点即可。
    因此,带虚拟节点的一致性哈希方法不仅适合硬件配置不同的节点的场景,而且适合节点规模会发生变化的场景。

8.小结

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

轮训这类的策略只能适用与每个节点的数据都是相同的场景,访问任意节点都能请求到数据。

  • 但是不适用分布式系统,因为分布式系统意味着数据水平切分到了不同的节点上,访问数据的时候,一定要寻址存储该数据的节点。

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

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

  • 一致性哈希是指将「存储节点」和「数据」都映射到一个首尾相连的哈希环上,如果增加或者移除一个节点,仅影响该节点在哈希环上顺时针相邻的后继节点,其它数据也不会受到影响。
  • 但是一致性哈希算法不能够均匀的分布节点,会出现大量请求都集中在一个节点的情况,在这种情况下进行容灾与扩容时,容易出现雪崩的连锁反应。

为了解决一致性哈希算法不能够均匀的分布节点的问题,就需要引入虚拟节点,对一个真实节点做多个副本。

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

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

  • 参考:一致性哈希算法,

服务器负载均衡算法之哈希算法相关推荐

  1. java 一致性hash算法 均衡分发_负载均衡-基础-一致性哈希算法及java实现

    1 /** 2 * 一致性hash 的java 实现3 *@authorluoqiang4 * @data 2016/11/085 */ 6 public classConsistencyHash { ...

  2. 服务器负载均衡的基本功能和实现原理

    负载均衡设备作为纵跨网络2-7层协议的设备,往往放置在网络设备和应用设备的连接处,对工程师在网络和应用基本知识方面的要求远高于其他设备,所以我们要在基本功能的理解上下更多的功夫.负载均衡设备还有另外一 ...

  3. 算法:哈希算法的应用场景

    什么是哈希算法 将任意长度的二进制值串映射为固定长度的二进制值串,这个映射的规则就是哈希算法,而通过原始数据映射之后得到的二进制值串就是哈希值. 一个优秀的哈希算法应该满足下面几个条件: 从哈希值不能 ...

  4. LVS详解及基于LVS实现web服务器负载均衡

    前言 LVS(Linux Virtual Server)Linux虚拟服务器,是一个虚拟的服务器集群系统.本项目在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一.通过LVS提供的 ...

  5. 多链路及服务器负载均衡原理与设备构建方案

    随着互联网的飞速发展,越来越多的商务活动通过互联网完成,网络性能却越来越不能满足日益增多互联网需求.随着因特网用户的急剧增多,用户越来越感受到应答时间延迟和带宽的不足.为了解决这些问题,用户为优化网络 ...

  6. 实现服务器负载均衡常见的四种技术

    为了提高服务器的性能和工作负载能力,企业通常会使用DNS服务器.网络地址转换等技术来实现多服务器负载均衡,特别是目前企业对外的互联网Web网站,许多都是通过几台服务器来完成服务器访问的负载均衡. 目前 ...

  7. 服务器负载均衡 链路负载均衡 《CDN技术详解》

    1. 服务器负载均衡 服务器负载均衡是将客户端请求在集群中的服务器上实现均衡分发的技术.按照位于七层网络协议栈的不同层的划分,服务器负载均衡可以分为四层(L4)负载均衡和七层(L7)负载均衡两种. 1 ...

  8. 服务器负载均衡解决方案

    企业网络应用服务器存在的问题:1.网络应用服务器的可靠性较差: 应用服务器由于服务器硬件的稳定性.流量压力超载.网络***等情况经常会出现意外宕机的情况,从而无法保证网络应用的7x24 小时的持续性服 ...

  9. f5服务器负载均衡性能指标,服务器负载均衡f5

    服务器负载均衡f5 内容精选 换一换 创建私网类型的负载均衡器.创建成功后,该接口会返回创建的负载均衡器的ID.所属子网ID.负载均衡器内网IP等详细信息.若要创建公网类型的负载均衡器,还需调用创建弹 ...

最新文章

  1. R语言使用ggplot2包使用geom_violin函数绘制分组小提琴图(分组颜色配置、位置配置)实战
  2. 转 sessionid如何产生?由谁产生?保存在哪里?
  3. springboot怎么替代jsp_如何在SpringBoot中使用JSP ?但强烈不推荐,果断改Themeleaf吧...
  4. android相册拍照剪切上传封装,安卓,图片裁剪上传真机测试好使,打包后显示:无法保存裁剪的图像...
  5. 看懂云计算、虚拟化和容器,这一篇就够啦!
  6. java list 取几个字段组装成map_java.util.concurrent 并发包诸类概览
  7. 多线程条件通行工具——Semaphore
  8. dataframe scala 修改值_【Spark学习笔记】 Scala DataFrame操作大全
  9. 苹果春季发布会:库克绝不玩别人玩剩下的!
  10. 2021 浏览器edge改 ie11 模式
  11. java学习笔记----Mybatis-Plus
  12. 我得意地笑: 搞定了, 哈哈 如何读取Thermo Scientific Nicolet Omnic *.spa二进制格式的谱图文件中的数据
  13. [SOC]clock与reset设计
  14. 用python画几个东西怎么画_一步一步教你如何用Python画一个滑稽
  15. 重庆大学明月科创班课程记录2.1大一下定量工程设计-定倾角船舶设计(Matlab)
  16. Oracle任意字符串转换成拼音首字母简写
  17. 男生停止长高的迹象是真的吗?
  18. 最新彩色文字方格广告位代码
  19. 魅族mx3升级到android6.0,升级安卓4.4!魅族MX3 Flyme 3.6.1A发布
  20. 学校办公用计算机配备情况,学校办公电脑管理制度

热门文章

  1. PDF怎么在手机编辑签名?这个方法感觉掌握下
  2. 用c语言编写流水灯的思路原理,花样流水灯 单片机设课设.doc
  3. 医药之家:CXO行业2022年度业绩出炉,多家公司净利润增幅超100%
  4. 系统定制封装-windows
  5. 想不想知道,使用360安全卫士,网上购物有没有保障?
  6. 以面试官的角度来看 React 工作面试
  7. 简网APP工场-服务介绍
  8. DreamSpark
  9. 2020C#程序设计及应用教程复习总结
  10. FPGA经验谈系列文章——FPGA开发方向以及算法开发模型