🗒️一文快速搞懂负载均衡
00 min
2023-7-18
2024-3-1
type
status
date
slug
summary
tags
category
icon
password

场景引入

现在,请假设你是一家电商公司的技术负责人,双11要来了,你需要为公司的网站做好充分的准备,以应对即将到来的流量高峰。看了我上篇文章(垂直扩展与水平扩展)的你,满怀信心,决定使用“横向扩展”来应对,你兴高采烈地加了几台服务器。然而,此时的你并不知道怎么把请求流量均匀地分发到每台服务器上;你也不知道,如果其中有服务器挂了,怎么让请求不再打到宕掉的机器上。然后……然后就没有然后了。 —— 面对类似这样的问题,我们可以考虑在系统中加入“负载均衡”。

何为负载均衡?

负载均衡,正如其字面意思,是一种将请求分配到多个服务器上,以均摊掉负载的技术。你可以说它是中介,也可以说它是代理,它连接的是客户端发出的请求与处理请求的服务器,做转发的工作。
类比: 你可以把负载均衡想象成是派活的老板。客户给老板提需求,只关心自己的需求能被满足,并不关心到底是谁来做;老板接到需求后,自然会根据需求和员工的情况去分发任务,而他自己只做任务的派发。

负载均衡器

一个合格的负载均衡器,除了可以在多个服务器间有效地分发请求,还可以感知服务器的健康状态,仅向正常工作的服务器转发请求,也可以支持分发流量给新加入的服务器。
那么,负载均衡器是如何感知有哪些服务器可供转发的呢?
  1. 手动配置:管理员可以手动配置负载均衡器的服务器列表,以便将请求分配到这些服务器上。
  1. 动态注册:服务器可以在启动时向负载均衡器注册自己的信息,让负载均衡器知道自己。
  1. 自动发现:负载均衡器可以通过专门的自动发现服务来获取服务器列表。例如,可以使用DNS或其他服务发现机制来自动获取服务器列表。
无论是自己维护还是向别人拿,负载均衡器都是可以拿到一个服务器列表的。
那负载均衡器又是如何感知服务器的健康状态的呢?
使用心跳机制。负载均衡器会定时给服务器列表中的服务器发送心跳包来检测服务器的状态,如果服务器一段时间内都没有响应心跳包,或者返回的信息中表明了服务器出现故障,负载均衡器会将该故障服务器从服务器列表中移除或者标记,并将请求分配到其他正常的服务器上。
需要注意的是,心跳机制的频率和响应的超时时间需要进行合理的设置。如果心跳机制的频率过低或超时时间过长,可能会导致故障没法及时被发现;频率过高或超时时间过短,可能会加重系统负载的压力或者产生故障的误报。最好是在具体的场景中进行测试和调优,来找到最优的参数值。
心跳机制可以通过多种方式来实现,例如:TCP连接检测、ICMP ping检测、HTTP请求检测等。不同的实现方式有不同的适用场景和优缺点,需要根据具体情况进行选择。
现在,负载均衡器有了服务器列表和感知健康状态的能力后,该如何进行转发呢?

负载均衡算法

  1. 轮询法
如字面意思,就是给每台可用机器轮流分发。主打的就是雨露均沾,也是使用的最广的方法。
但是,如果集群中机器的性能很不均衡怎么办呢?对于性能比较差的机器是很不公平的。
  1. 加权轮询法
还是轮询,但是给每台服务器加了权重,配置好的服务器权重就分配大一点,权重大的就按比例分配多发几次。主打的就是一个公平,能者多劳,适合集群性能不均的情况下使用。
但是,这样的方式也比较固定,缺乏对实际情况的感知能力,实际现场中肯定更复杂。比如说:
  1. 请求也分轻重的,一个请求可能消耗很多机器资源,如拉全量数据、做大批量计算等
  1. 服务可能刚好在做GC,请求也没办法被及时响应
  1. 服务也可能受制于他人,如:下游、宿主机等因素的影响
📌
所以,尽量保证请求数在每个实例上均等的目标,在微服务架构下可能并不是最优解。
  1. 最少响应时间法
把前面提到的“心跳机制”利用起来,根据响应情况来感知现场,自适应地把请求转发给响应最快的机器,使系统负载均衡。
但是,你以为万事大吉了吗?并没有。这种方式仍然可能会导致服务器过载,在高并发的情况下,短时间内所有请求都打到响应时间最短的服务器上,这个服务器可能会因为负载过重而崩溃;而且处理能力强的服务器,可能位于较远的位置,响应时间就比较长,就会导致饥饿问题,负载仍然不均。
  1. 其他方法
  • 最小连接数优先
  • 最小请求数优先
  • 最小CPU/MEM/带宽利用率优先
  • Hash法
    • ip
    • url
    • Ring Hash(一致性hash)
  • 随机法/随机加权法
  • 路径选择法(eg.读写分离)
  1. 组合
每种方式都有优缺点,我们可以对它们进行一定程度地组合,放大优点,弥补缺点,做出一个组合的加权公式,比如:(只是举个例子)
📌
我相信上面的方法,已经可以保证大多数业务场景下的负载均衡了,但是仅保证负载均衡是不够的,比如一个福建用户点击商品,对商品图片资源发出请求时,该请求可能因为负载均衡被转发到河北的机房去了,这对用户的体验来说并不好。该如何解决呢?

补充

我们经常看到的x层负载均衡,是相对网络OSI 7层模型来说的。
  • 二层负载:基于MAC层来实现请求分发,一般采用虚拟MAC的方式实现,服务器收到请求后,通过动态分配后端服务的实际Mac地址进行响应从而实现负载均衡。
  • 三层负载:基于IP层来实现请求分发,一般通过虚拟IP的方式实现,外部请求访问虚拟IP,服务器收到请求后根据后端实际IP地址进行转发。
  • 四层负载:基于传输层来实现请求分发,一般通过请求报文中的目标地址和端口进行负载均衡,Nginx、F5、LVS等都可以实现四层负载;但无法识别应用层协议,因此无法进行更细粒度的负载均衡。
  • 七层负载:基于应用层来实现请求分发,一般根据特定于应用程序的数据(例如 HTTP 标头、Cookie)或应用程序消息本身中的数据(例如特定参数的值)进一步分发请求,粒度可以做得更细,相对四层负载也更复杂。
💡
你可以有多个负载均衡器,它们各自有着不同的服务器选择策略!此外,如果你的系统是一个非常大的高流量系统,你或许需要 负载均衡器的负载均衡器…… 最终,你需要不断地往系统中添加组件,直到系统的性能适应了你的需求(你的需求可能看起来平缓,或者随时间缓慢上升,或者容易出现峰值)。