热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

分布式系统关注点——仅需这一篇,吃透「负载均衡」

一、「负载均衡」是什么正如题图所示的这样,由一个独立的统一入口来收敛流量,再做二次分发的过程就是「负载均衡」,它的本质和「分布式系统」一样

一、「负载均衡」是什么

正如题图所示的这样,由一个独立的统一入口来收敛流量,再做二次分发的过程就是「负载均衡」,它的本质和「分布式系统」一样,是「分治」。如果大家习惯了开车的时候用一些导航软件,我们会发现,导航软件的推荐路线方案会有一个数量的上限,比如3条、5条。因此,其实本质上它也起到了一个类似「负载均衡」的作用,因为如果只能取Top3的通畅路线,自然拥堵严重的路线就无法推荐给你了,使得车流的压力被分摊到了相对空闲的路线上。在软件系统中也是一样的道理,为了避免流量分摊不均,造成局部节点负载过大(如CPU吃紧等),所以引入一个独立的统一入口来做类似上面的“导航”的工作。但是,软件系统中的「负载均衡」与导航的不同在于,导航是一个柔性策略,最终还是需要使用者做选择,而前者则不同。怎么均衡的背后是策略在起作用,而策略的背后是由某些算法或者说逻辑来组成的。比如,导航中的算法属于「路径规划」范畴,在这个范畴内又细分为「静态路径规划」和「动态路径规划」,并且,在不同的分支下还有各种具体计算的算法实现,如Dijikstra、A*等。同样的,在软件系统中的负载均衡,也有很多算法或者说逻辑在支撑着这些策略,巧的是也有静态和动态之分。

二、常用「负载均衡」策略图解

下面来罗列一下日常工作中最常见的5种策略。

01 轮询

  这是最常用也最简单策略,平均分配,人人都有、一人一次。大致的代码如下。


int globalIndex = 0; //注意是全局变量,不是局部变量。

try
{

return servers[globalIndex];

}
finally
{

globalIndex++;
if (globalIndex == 3)globalIndex = 0;

}

02 加权轮询

在轮询的基础上,增加了一个权重的概念。权重是一个泛化后的概念,可以用任意方式来体现,本质上是一个能者多劳思想。比如,可以根据宿主的性能差异配置不同的权重。大致的代码如下。


int matchedIndex = -1;
int total = 0;

for (int i = 0; i {

servers[i].cur_weight += servers[i].weight;//①每次循环的时候做自增(步长=权重值)total += servers[i].weight;//②将每个节点的权重值累加到汇总值中if (matchedIndex == -1 || servers[matchedIndex].cur_weight 当前待返回节点的自增数,则覆盖。{matchedIndex = i;}

}

servers[matchedIndex].cur_weight -= total;//④被选取的节点减去②的汇总值,以降低下一次被选举时的初始权重值。
return servers[matchedIndex];

这段代码的过程如下图的表格。"()"中的数字就是自增数,代码中的cur_weight。

值得注意的是,加权轮询本身还有不同的实现方式,虽说最终的比例都是2:1:2。但是在请求送达的先后顺序上可以所有不同。比如「5-4,3,2-1」和上面的案例相比,最终比例是一样的,但是效果不同。「5-4,3,2-1」更容易产生并发问题,导致服务端拥塞,且这个问题随着权重数字越大越严重。例子:10:5:3的结果是「18-17-16-15-14-13-12-11-10-9,8-7-6-5-4,3-2-1」

03 最少连接数

这是一种根据实时的负载情况,进行动态负载均衡的方式。维护好活动中的连接数量,然后取最小的返回即可。大致的代码如下。

var matchedServer = servers.orderBy(e => e.active_conns).first();

matchedServer.active_conns += 1;

return matchedServer;

//在连接关闭时还需对active_conns做减1的动作。

04 最快响应

这也是一种动态负载均衡策略,它的本质是根据每个节点对过去一段时间内的响应情况来分配,响应越快分配的越多。具体的运作方式也有很多,上图的这种可以理解为,将最近一段时间的请求耗时的平均值记录下来,结合前面的「加权轮询」来处理,所以等价于2:1:3的加权轮询。题外话:一般来说,同机房下的延迟基本没什么差异,响应时间的差异主要在服务的处理能力上。如果在跨地域(例:浙江->上海,还是浙江->北京)的一些请求处理中运用,大多数情况会使用定时「ping」的方式来获取延迟情况,因为是OSI的L3转发,数据更干净,准确性更高。

05 Hash法

hash法的负载均衡与之前的几种不同在于,它的结果是由客户端决定的。通过客户端带来的某个标识经过一个标准化的散列函数进行打散分摊。上图中的散列函数运用的是最简单粗暴的「取余法」。题外话:散列函数除了取余之外,还有诸如「变基」、「折叠」、「平方取中法」等等,此处不做展开,有兴趣的小伙伴可自行查阅资料。另外,被求余的参数其实可以是任意的,只要最终转化成一个整数参与运算即可。最常用的应该是用来源ip地址作为参数,这样可以确保相同的客户端请求尽可能落在同一台服务器上。

三、常用「负载均衡」策略优缺点和适用场景

我们知道,没有完美的事物,负载均衡策略也是一样。上面列举的这些最常用的策略也有各自的优缺点和适用场景,我稍作了整理,如下。

这些负载均衡算法之所以常用也是因为简单,想要更优的效果,必然就需要更高的复杂度。比如,可以将简单的策略组合使用、或者通过更多维度的数据采样来综合评估、甚至是基于进行数据挖掘后的预测算法来做。

四、用「健康探测」来保障高可用

不管是什么样的策略,难免会遇到机器故障或者程序故障的情况。所以要确保负载均衡能更好的起到效果,还需要结合一些「健康探测」机制。定时的去探测服务端是不是还能连上,响应是不是超出预期的慢。如果节点属于“不可用”的状态的话,需要将这个节点临时从待选取列表中移除,以提高可用性。一般常用的「健康探测」方式有3种。

此我向大家推荐一个Java学习交流群。交流学习群号:874811168 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,一起学习,一起进步,目前受益良多。

01 HTTP探测

使用Get/Post的方式请求服务端的某个固定的URL,判断返回的内容是否符合预期。一般使用Http状态码、response中的内容来判断。

02 TCP探测

基于Tcp的三次握手机制来探测指定的IP + 端口。最佳实践可以借鉴阿里云的SLB机制,如下图。

▲图片来源于阿里云,版权归原作者所有

值得注意的是,为了尽早释放连接,在三次握手结束后立马跟上RST来中断TCP连接。

03 UDP探测

可能有部分应用使用的UDP协议。在此协议下可以通过报文来进行探测指定的IP + 端口。最佳实践同样可以借鉴阿里云的SLB机制,如下图。

▲图片来源于阿里云,版权归原作者所有

结果的判定方式是:在服务端没有返回任何信息的情况下,默认正常状态。否则会返回一个ICMP的报错信息。

五、结语

用一句话来概括负载均衡的本质是:将请求或者说流量,以期望的规则分摊到多个操作单元上进行执行。通过它可以实现横向扩展(scale out),将冗余的作用发挥为「高可用」。另外,还可以物尽其用,提升资源使用率。



推荐阅读
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • LVS实现负载均衡的原理LVS负载均衡负载均衡集群是LoadBalance集群。是一种将网络上的访问流量分布于各个节点,以降低服务器压力,更好的向客户端 ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文详细介绍了解决全栈跨域问题的方法及步骤,包括添加权限、设置Access-Control-Allow-Origin、白名单等。通过这些操作,可以实现在不同服务器上的数据访问,并解决后台报错问题。同时,还提供了解决second页面访问数据的方法。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 单页面应用 VS 多页面应用的区别和适用场景
    本文主要介绍了单页面应用(SPA)和多页面应用(MPA)的区别和适用场景。单页面应用只有一个主页面,所有内容都包含在主页面中,页面切换快但需要做相关的调优;多页面应用有多个独立的页面,每个页面都要加载相关资源,页面切换慢但适用于对SEO要求较高的应用。文章还提到了两者在资源加载、过渡动画、路由模式和数据传递方面的差异。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
author-avatar
aadsasdass_998_268
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有