10分钟带你彻底搞懂负载均衡

十分钟搞懂系列

序号标题链接
110分钟带你彻底搞懂企业服务总线https://blog.csdn.net/belongtocode/article/details/119487731
210分钟带你彻底搞懂微内核架构https://blog.csdn.net/belongtocode/article/details/119107837
310分钟带你彻底搞懂服务限流和服务降级https://blog.csdn.net/belongtocode/article/details/119107785
410分钟带你彻底搞懂负载均衡https://blog.csdn.net/belongtocode/article/details/118977839
510分钟带你彻底搞懂集群容错和服务隔离https://blog.csdn.net/belongtocode/article/details/118968771
610分钟带你彻底搞懂注册中心https://blog.csdn.net/belongtocode/article/details/118639474
710分钟带你彻底搞懂RPC架构https://blog.csdn.net/belongtocode/article/details/118639448

我们都知道,在分布式系统中,业务流程的执行会涉及到多个服务实例之间的协同工作。那么为了提高系统的整体效率和吞吐量,就必须要能最大程度地发挥每个节点的作用,而负载均衡就是保证系统运行效率的关键技术,这也正是我们今天所要探讨的主要话题。

那么接下来,我们就先通过一个具体的案例场景,来理解下负载均衡的主要作用吧。

负载均衡是如何保证软件系统的生产部署的?

假如你要设计一个分布式服务系统,这个系统中存在一批能够独立运行的服务,并且在部署上采用了集群模式,也就是把多个服务实例集中在一起,对外提供同一业务功能,这样用户任意的访问请求都可以由集群中的某一个服务实例进行响应,从而防止出现单点故障,以此实现高可用。如下图所示:

img

不过这样问题也就来了:用户的一次访问请求应该由哪个服务实例来响应最为合适呢?这个问题看上去很简单,实际上却要复杂得多,因为它涉及到服务请求的路由机制。

负载均衡就是最为常见的路由机制实现方案,能够根据请求来选择合适的服务实例,也就是可以把请求的流量转发到集群中的各个服务实例中,从而达到流量分摊效果。而支持这个实现过程的技术组件,就叫做负载均衡器。

那么现在,我们来看下负载均衡器的基本结构:

img

你可以看到,来自客户端的请求通过中间的负载均衡器被分发到了各个服务实例当中,然后根据分发策略的不同,会产生不同的分发结果。

这里你可以先停下来考虑一个基础性的问题:负载均衡器想要实现请求分发的前提是什么?

很显然,那就是负载均衡器需要掌握当前各个服务实例的运行时状态,也就是说,它需要持有当前的服务实例列表信息。

img

负载均衡分发策略

那么,当负载均衡器拥有了当前的服务实例列表信息后,具体会怎么分发呢?

请求由谁来分发?

首先要明确的是,请求是由谁来分发?针对这个问题,我们根据服务实例地址列表所存放的位置不同,可以把负载均衡器分成两大类,一类是服务器端负载均衡器,一类是客户端负载均衡器。

服务器端负载均衡器

我们先来看服务器端负载均衡的结构:

img

可以看到,在客户端与服务实例集群之间,存在一个独立的负载均衡服务器,这台负载均衡服务器就负责将接收到的各个请求转发到运行中的某个服务实例上。

提供服务器端负载均衡的工具有很多,比如常见的 Apache、Nginx、HAProxy 等,都实现了基于 HTTP 协议或 TCP 协议的负载均衡模块。基于服务器端的负载均衡机制的实现也比较简单,只需要在客户端与各个服务实例之间,架设集中式的负载均衡器即可。

此外,负载均衡器与各个服务实例之间还需要实现服务诊断以及状态监控,通过动态获取各个服务实例的运行时信息,来决定负载均衡的目标服务。如果负载均衡器检测到某个服务实例已经不可用,就会自动移除该服务实例。

这么一分析,我们就能知道,服务器端的负载均衡器是运行在一台独立的服务器上,它会充当代理(Proxy)的作用,所有的请求都需要通过负载均衡器的转发才能实现服务调用。这是它的特点,但也是一个问题。

因为当服务请求量越来越大时,服务器端负载均衡器就会成为系统的瓶颈。同时,一旦负载均衡器自身出现异常,整个服务的调用过程都会失败。

因此,在分布式架构中,为了避免服务器端这种集中式的负载均衡所带来的这种问题,我们可以采用客户端负载均衡的请求分发模式。

客户端负载均衡

和服务器端负载均衡器部署在服务集群前端的形式不同,在客户端负载均衡器中,服务实例信息是保存在各个客户端的内部。这时候,目标服务实例地址是由客户端自身通过一定的调度算法来决定的,结构如下:

img

相比服务器端负载均衡,客户端负载均衡机制的主要优势就是不会出现集中式负载均衡所产生的瓶颈问题,因为每个客户端都有自己的负载均衡器,即使单个负载均衡器失效,也不会造成严重的后果。

不过客户端负载均衡也同样存在一个缺陷,就是由于所有服务实例运行时信息,都需要在多个负载均衡器之间进行传递,因此会在一定程度上加重网络流量负载。

好了,现在你应该就清楚“请求由谁来分发”这个问题的答案了吧。这个核心问题实际上也引出了一个新的概念,就是用于执行负载均衡的调度算法,这也是我们要讨论的第二个问题:“请求分发到哪去?”

请求分发到哪去?

要知道,无论是使用服务器端负载均衡还是客户端负载均衡,运行时的分发策略都决定了负载均衡的最终效果。

分发策略在软件负载均衡中的实现形式是一组调度算法,我们俗称为“负载均衡算法”。

负载均衡算法有静态和动态之分,它们之间的区别就在于是否依赖于当前服务的运行时状态,这些状态信息包括服务过去一段时间的平均调用时延和所承接的连接数等。

img

静态负载均衡算法

我们先来看静态负载均衡算法,这类算法中具有代表性的是各种随机(Random)和轮询(Round Robin)算法。

所谓的随机算法,就是在集群中随机选择一个服务实例,它的特点是负载均衡的结果相对比较平均。随机算法的实现也比较简单,我们使用 JDK 自带的 Random 工具类,就可以来指定服务实例的地址。

举个例子,这是来自客户端的 9 个请求,分别被分发到了服务 A 集群中的 3 个服务实例当中,它的分发策略就是随机选择的,而不是一个固定的规则。

img

你可能也会用到随机算法的升级版:加权随机(Weight Random)算法。

在集群中可能存在部分性能较优的服务器,为了使这些服务器响应更多请求,就可以通过加权随机算法提升这些服务器的权重。比如这张图(图 8)中实例 2 的权重设置的最大,所以对应的处理请求数可能也就最多。

img

讲完随机算法,我们再来看看轮询算法。

所谓轮询,就是按一定顺序循环遍历整个服务实例列表,并在循环过程中为请求指定某一个服务实例。如果循环过程到达上限,那么就从零开始继续顺序循环,直到找到下一个服务实例。

我还是给你举个例子。

可以看到在这个示意图中,第一个请求被分发到了实例 1,第二个请求被分发到了实例 2,第三个请求被分发到了实例 3,然后第四个请求再次被分发到了实例 1,以此类推。当然,轮询的时候每个服务实例也可以具有特定的权重,构成加权轮询算法。

img

动态负载均衡算法

事实上,所有涉及到权重的静态算法都可以转变为动态算法,因为权重可以在运行过程中动态更新。比如在动态轮询算法中,权重值会基于对各个服务器的持续监控并不断更新。另外,基于服务器的实时性能分配请求也是常见的动态策略。

典型的动态算法包括最少连接数算法、服务调用时延算法等。

最少连接数 (Least Connection) 算法,是指根据集群中各个服务的当前打开连接数,来确定目标服务实例,连接数最少的服务实例会优先响应请求。当执行分发策略时,系统会根据在某一个特定的时间点下服务实例的最新连接数,来判断是否执行客户端请求。而在下一个时间点时,服务实例的连接数一般都会发生相应的变化,对应的请求处理也会做相应的调整。

img

与最少连接数类似,服务调用时延(Service Invoke Delay)算法是根据服务实例的调用时延来决定负载均衡的结果,服务器也可以根据服务调用和平均时延的差值动态来调整权重。

img

另外,在现实中,有时候我们也会使用源地址哈希(Source IP Hash)算法,这个算法的具体实现是请求 IP 粘滞(Sticky)连接,以此尽可能地让来自同一 IP 的地址访问到同一个服务实例。

这是一种有状态机制,因而我们也可以把它归为动态负载均衡算法。

img

在 Spring Cloud 中实现的核心负载均衡算法,包括了随机、轮询、加权响应时间、并发量最小优先等,而 Dubbo 中则提供了随机、轮询、最少活跃调用数和一致性哈希等算法。

所以你可以发现,这两个框架中都实现了前面介绍的一些主流算法,但它们也根据框架自身的特点,提供了一些比较有特色的策略。当然,这两个框架也都提供了开发入口,供开发人员实现自定义的负载均衡算法。

总结
以上就是这节课的全部内容,为了让你更好地理解,我做了一张思维导图,供你参考:

img

最后,我想给你留一道思考题:如果想把随机、轮询等静态负载均衡算法转化为动态算法,你有什么思路?你可以在评论区留下你的答案,和我讨论。

参考文章:
整理于极客时间每日一课对应文章

  • 17
    点赞
  • 103
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Apple_Web

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值