|
| 1 | + |
| 2 | +## 负载均衡与代理 |
| 3 | + |
| 4 | +在讨论负载均衡时,"负载均衡器"(Load Balancer)和"代理"(Proxy)这两个术语常被混用。严格来说,并非所有代理都属于负载均衡器,但大多数代理的核心功能都涵盖负载均衡。为了简化表述,本文将这两个术语视为大致等同,不作严格区分。 |
| 5 | + |
| 6 | +展示了负载均衡高层架构图,客户端(Client)的请求通过负载均衡器(Load Balancer)转发至某个后端服务器(Backend)。从整体架构来看,负载均衡器承担以下职责: |
| 7 | + |
| 8 | +- **服务发现**:识别系统中可用的后端服务器,并获取它们的地址,以便与后端进行通信。 |
| 9 | +- **健康检查**:监测后端服务器的状态,确保只有健康的服务器能够接收请求。 |
| 10 | +- **负载均衡**:根据适合的分配算法,将请求均匀分配到健康的后端服务器上,提高系统的整体性能与可靠性 |
| 11 | +![[balancer-BXimvOkh.svg]] |
| 12 | +合理使用负载均衡能为分布式系统带来多方面的好处: |
| 13 | + |
| 14 | +- **命名抽象**:客户端通过统一的访问机制(如 DNS 或内置库)连接到负载均衡器,无需关心后端服务器的拓扑结构或配置细节。 |
| 15 | +- **容错能力**:通过健康检查和负载均衡算法,将请求分配至正常运行的后端服务器。故障服务器会被自动移出负载均衡池,为运维人员提供足够的修复窗口。 |
| 16 | +- **成本和性能收益**:后端服务器通常分布在多个网络区域(Zone/Region),负载均衡器根据策略将请求保持在同一网络区域内,从而提高服务性能(减少延迟)并降低资源成本(减少跨区域带宽费用)。 |
| 17 | + |
| 18 | +从网络层次的角度来看,所有负载均衡器可以分为两类:四层负载均衡和七层负载均衡,分别对应 OSI 模型的第四层(传输层)和第七层(应用层)。 |
| 19 | + |
| 20 | +### 1 四层负载均衡 |
| 21 | +需要注意的是,所谓的“四层负载均衡”并非严格限定于 OSI 模型的第四层(传输层)。实际上,它的工作模式涉及多个网络层次: |
| 22 | + |
| 23 | +- **第二层**(数据链路层):通过修改帧头中的 MAC 地址,将请求从一个物理网络节点转发到另一个节点。这种方式通常用于同一广播域内的转发,例如交换机或桥接设备完成的二层转发操作。 |
| 24 | +- **第三层**(网络层):通过修改 IP 地址,实现跨子网的请求路由和转发。这是路由器的核心功能,通过修改数据包的源或目的 IP 地址,实现子网之间的通信和流量转发。 |
| 25 | +- **第四层**(传输层):通过修改 TCP/UDP 端口号或连接的目标地址,利用网络地址转换(NAT)技术隐藏内部网络结构,将请求从一个入口转发至多个后端服务。 |
| 26 | + |
| 27 | +如图所示,上述各个网络层次的共同特点是维持了传输层协议(如 TCP、UDP)的连接特性。如果读者在其他资料中看到“二层负载均衡”或“三层负载均衡”的说法,应该理解到这是负载均衡器在不同网络层次上的工作模式。 |
| 28 | +![[balancer4-BX8pNsW3.svg]] |
| 29 | +典型情况下,四层负载均衡器处理的是 TCP、UDP 等连接协议,它并不关心传输字节所代表的具体应用内容,这些字节可能来自 Web 应用、数据库服务或其他网络服务。因此,四层负载均衡器具有广泛的应用范围,能够适应各种不同类型的网络服务。 |
| 30 | + |
| 31 | +由于建立连接的开销较大(例如 TCP 三次握手,尤其在启用 TLS 加密时),许多网络协议(如 TCP、HTTP/2、QUIC 和 WebSockets)在演进过程中逐步引入了“多路复用”(multiplexing)和“连接保持”(connection keep-alive)等特性,也就是将同一连接或会话的流量始终转发到相同的后端服务器,从而避免频繁的连接建立过程。 |
| 32 | + |
| 33 | +不过,这种“连接保持”机制也存在潜在问题。以下是一个示例场景: |
| 34 | + |
| 35 | +- Client A 和 Client B 两个 HTTP/2 客户端通过四层负载均衡器和后端服务器建立持久连接。。 |
| 36 | +- Client A 的 TCP 连接每分钟发送 40 个 HTTP 请求,而 Client B 的 TCP 连接每秒发送 1 个 HTTP 请求。 |
| 37 | + |
| 38 | +四层负载均衡器将 Client A 的所有 TCP 请求转发至同一台服务器,导致该服务器过载,而其他服务器则处于闲置状态。这种资源利用不均的问题在电气工程领域被称为“阻抗不匹配”现象。 |
| 39 | +![[l4-connection-v2-C4TnReeL.svg]] |
| 40 | +随着用户规模扩大,四层负载均衡器面临的“阻抗不匹配”问题将变得更加明显。 |
| 41 | + |
| 42 | +不过也不要担心,引用一句计算机领域内流传颇广的俚语“计算机科学中的所有问题都可以通过增加一个间接层来解决。如果不够,那就再加一层”。因此,我们在四层负载均衡器之上添加了一个二级分发器 —— 七层负载均衡: |
| 43 | + |
| 44 | +- 四层负载均衡器工作在传输层,根据连接特性完成初步的请求转发; |
| 45 | +- 七层负载均衡器工作在应用层,根据请求内容进一步优化请求转发。 |
| 46 | + |
| 47 | +通过两次分发,请求的“阻抗不匹配”问题就消失了。 |
| 48 | + |
| 49 | +### 2 七层负载均衡 |
| 50 | + |
| 51 | +七层负载均衡器工作在应用层,这意味着负载均衡器必须与后端服务器建立新的传输层连接,并将客户端的请求代理到后端服务器。 |
| 52 | + |
| 53 | +七层负载均衡器的工作原理。当客户端发送 HTTP 请求(stream)时: |
| 54 | + |
| 55 | +- 请求 1(stream1)被代理至第一个后端服务器; |
| 56 | +- 请求 2(stream2)被代理至第二个后端服务器 |
| 57 | +![[balancer7-DqdAZUri.svg]] |
| 58 | + |
| 59 | +七层负载均衡器能够处理更复杂的操作,原因在于它工作在应用层,能够检测和处理请求内容,具体包括: |
| 60 | + |
| 61 | +- 安全层 TLS 协议:TLS 的归属层次在网络领域存在争议,本文为便于讨论假设属于应用层。 |
| 62 | +- 物理 HTTP 协议:涵盖 HTTP/1、HTTP/2、HTTP/3 等版本。 |
| 63 | +- 逻辑 HTTP 协议:包括请求的头部、主体和尾部数据。 |
| 64 | +- 消息协议:如 gRPC、RESTful API、SOAP、AMQP、MQTT 等。 |
| 65 | + |
| 66 | +因此,七层负载均衡能够根据应用层信息做出更精细的路由决策,并支持内容缓存、压缩、TLS/SSL 卸载等高级功能 |
| 67 | + |
| 68 | + |
| 69 | +## 负载均衡器总体功能 |
| 70 | + |
| 71 | +现代负载均衡器的功能已远超其初衷。本节将简要介绍负载均衡器的常见功能,以帮助读者对其有个整体性的认识。 |
| 72 | + |
| 73 | +### 1 服务发现 |
| 74 | + |
| 75 | +服务发现是负载均衡器识别后端服务器的一种机制,不同的实现方式差异较大,以下是几种常见的实现方式: |
| 76 | + |
| 77 | +- **静态配置文件**:通过手动维护配置来实现基础的服务发现。 |
| 78 | +- **DNS**:将后端服务器的 IP 地址以 SRV 记录或 A 记录形式注册到 DNS 服务器,客户端查询 DNS 记录来获取后端服务器的 IP 地址。 |
| 79 | +- **服务注册中心**(如 Zookeeper、Etcd、Consul 等):后端服务器启动时将服务名称、地址、端口及健康检查信息注册到这些系统中。客户端通过查询 API 获取服务信息。这些系统通常内置健康检查机制,定期监控服务状态,并自动更新服务列表。 |
| 80 | +- **服务网格领域的数据平面 API**:提供标准化的数据平面接口(xDS 协议),支持跨平台、跨环境的服务发现。 |
| 81 | + |
| 82 | +### 2 健康检查 |
| 83 | + |
| 84 | +健康检查用于评估后端服务器是否能够正常处理请求,识别不可用的服务器并将流量重新分配。健康检查有两种方式: |
| 85 | + |
| 86 | +- **主动健康检查**:负载均衡器定期向后端发送健康探测请求,根据响应状态判断后端服务器是否健康。例如,某些七层负载均衡器会请求特定的健康检查路径(如 /health 或 /status),通过 HTTP 状态码来判断后端服务的健康状态。 |
| 87 | +- **被动健康检查**:负载均衡器通过持续监控请求、响应和连接的状态,分析异常情况来判断后端服务器的健康状态。如果在一段时间内发现某个后端出现多次连接失败或超时等问题,负载均衡器会将该后端标记为不健康。 |
| 88 | +### 3 粘性会话 |
| 89 | + |
| 90 | +对于某些特定应用,确保属于同一会话的请求被路由到相同的后端服务器至关重要。 |
| 91 | + |
| 92 | +会话的定义因业务而异,可能基于 HTTP cookies、客户端地址、请求头或其他相关属性来确定。大部分七层负载均衡器支持通过配置 HTTP cookies 或 IP 哈希来实现“粘性会话”(sticky session)。 |
| 93 | + |
| 94 | +值得注意的是,粘性会话涉及缓存、临时状态管理,实现粘性会话的设计通常很脆弱(赖于特定服务器、无法动态扩展、不可预测的负载分配问题等)。一旦处理会话的后端出现故障,整个服务都会受到影响。因此,设计具有该特性的系统时,需要格外谨慎! |
| 95 | + |
| 96 | +### 4 TLS 卸载 |
| 97 | + |
| 98 | +TLS 卸载(TLS Termination)是指将 TLS 加密/解密、证书管理等操作由负载均衡器统一处理。这样做的好处是: |
| 99 | + |
| 100 | +- **减轻后端负载**:后端服务器无需处理加密/解密操作,可以专注于业务逻辑处理。 |
| 101 | +- **减少运维负担**:负载均衡器集中管理 SSL 证书的配置和更新,避免每个后端服务器单独管理证书。 |
| 102 | +- **提升请求效率**:负载均衡器通常具备硬件加速能力,并经过优化,能更高效地处理 TLS 连接(详见本书第二章 2.5.2 节)。 |
| 103 | + |
| 104 | +### 5 安全和 DDoS 防御 |
| 105 | + |
| 106 | +作为集群的唯一入口,负载均衡器不仅是流量的调度中心,也是系统安全的第一道防线。 |
| 107 | + |
| 108 | +负载均衡器可以作为访问控制点,拦截来自不受信任的来源的请求,防止恶意流量进入内部系统。此外,负载均衡器可以通过部署 IP 黑/白名单、流量限速、请求鉴权等功能,强化对外部攻击的防护能力。 |
| 109 | + |
| 110 | +另一方面,负载均衡器通过支持高级安全功能(如 SSL/TLS 终端加密和 Web 应用防火墙)进一步增强了系统的安全性。在面临 DDoS 攻击时,负载均衡器能够通过流量分散、智能限速等手段,有效减轻攻击压力,保护内部资源不受影响。 |
| 111 | + |
| 112 | +### 6 可观测性 |
| 113 | + |
| 114 | +从基本的统计信息(如流量、连接数和错误率)到与微服务架构集成的调用链追踪,不同层次的负载均衡器输出的可观测性数据各异: |
| 115 | + |
| 116 | +- 四层负载均衡器的观测数据集中在连接、流量、延迟等网络层面的分析。 |
| 117 | +- 七层负载均衡器的观测数据集中在 HTTP 请求、HTTP 错误码、会话保持、路由分配等应用层面的分析。 |
| 118 | + |
| 119 | +需要注意的是,输出可观测性数据并非没有代价,负载均衡器需要进行额外处理来生成这些数据,但所带来的收益远超过那一点性能损失。 |
| 120 | + |
| 121 | +### 7 负载均衡 |
| 122 | + |
| 123 | +负载均衡器字面意思是,给到一组健康的后端,选择谁来处理用户请求?也就是负载均衡器的调度算法。 |
| 124 | + |
| 125 | +负载均衡调度算法是一个相对活跃的研究领域,从简单的随机选择,到更复杂的考虑各种延迟和后端负载状态的算法,笔者无法逐一展开,这里仅从功能和应用的角度简要介绍一些常见的负载均衡算法。 |
| 126 | + |
| 127 | +- **轮询均衡算法**(Round-Robin):按依次循环的方式将请求调度到不同的服务器上,该算法最大的特点是实现简单。轮询算法假设所有的服务器处理请求的能力都一样,调度器会将所有的请求平均分配给每个真实服务器。 |
| 128 | + |
| 129 | +- **最小连接均衡算法**(Least-Connection):该算法中调度器需要记录各个服务器已建立连接的数量,然后把新的连接请求分配到当前连接数最小的服务器。 |
| 130 | + |
| 131 | + 最小连接均衡算法特别适合于服务器处理时间不一致的场景。例如,当某些请求可能占用较长时间,而另一些请求很快就会完成时,最小连接算法可以有效避免某些服务器因处理大量复杂请求而过载。 |
| 132 | + |
| 133 | +- **一致性哈希均衡算法**(Consistency Hash):将请求中的某些特征数据(例如 IP、MAC 或者更上层应用的某些信息)作为特征值来计算需要落在的节点。一致性哈希算法会保证同一个特征值的请求每一次都会落在相同的服务器上。 |
| 134 | + |
| 135 | +- **随机均衡算法**(Random):此种负载均衡算法类似于轮询调度,不过在分配处理请求时是随机的过程。由概率论可以得知,随着客户端调用服务端的次数增多,其实际效果趋近于平均分配请求到服务端的每一台服务器,也就是达到轮询的效果。 |
| 136 | + |
| 137 | + |
| 138 | +以上算法假设的是所有服务器处理能力均相等,并不管服务器的负荷和响应速度。如果集群内各个服务器处理能力不一致呢?如服务器 A 每秒可处理 10 个请求,服务器 B 每秒可处理 100 个请求,不考虑服务器的处理能力的负载均衡算法,实际上是一种“伪均衡”算法。 |
| 139 | + |
| 140 | +考虑各个服务器的处理能力存在差异,负载均衡算法又有了对服务器“**加权**”的补充。 |
| 141 | + |
| 142 | +加权负载均衡算法通过按权值高低分配请求,使权重较高的服务器处理更多连接,从而保证集群内后端服务器的负荷整体均衡。常用的加权负载均衡算法有加权轮询(Weighted Round Robin)、加权最小连接(Weighted Least-Connection)和加权随机(Weighted Random)等等,笔者就不再逐一介绍了。 |
| 143 | + |
0 commit comments