我经常看到 Web 应用程序架构在一堆应用服务器前面有一个 SLB/反向代理。
当 SLB 的连接数需要太多资源时会发生什么情况?单身的有效处理 SLB 需要多少时间?举一个具体但夸张的例子,考虑 200 万个持续 HTTP 连接。显然单身的SLB 无法处理这个问题。
扩展的推荐配置是什么出去SLB?
创建 LB 组/集群是否很常见?如果是,客户端负载如何在 LB 组之间分配?
答案1
负载均衡器无法轻易地被其他负载均衡器扩展,因为链上必然会有一个负载均衡器在某处维护连接。也就是说,LVS 或 HAProxy 等均衡器在 Gbps 范围内具有荒谬的容量。一旦超出了单个负载均衡器(软件、硬件等)的能力,您就需要转向其他技术,例如循环 DNS。
答案2
好的,已经有了一个可以接受的答案,但是还有一些需要补充。 扩展负载均衡器层的最常见“经典”方法是(无特定顺序):
DNS 循环公开域的多个 IP 地址。对于每个 IP 地址,实施高可用性服务器对(2 个服务器协作以始终保持一个 IP 地址正常工作)。每个 IP 对应一个负载平衡器集群,可以使用设备或带有负载平衡软件的服务器。根据需要通过添加更多负载平衡器对进行水平扩展。
路由或防火墙调整将负载分散到多个负载均衡器。让前端路由器或前端防火墙将传入连接分散到多个 IP 地址(每个 IP 地址代表一个负载均衡器对),方法是对源 IP 地址进行哈希处理,具有到负载均衡器的多个等价路由,或类似路由。
一层IP 级负载均衡器在 HTTP 级别负载均衡器之前。IP 层负载平衡可以在 ASIC/硅片中实现,并且在某些情况下可以非常快。因此,单个 IP 负载平衡器对通常可以“跟上”几个 HTTP/HTTPS 级别的负载平衡器,并提供多千兆位性能级别,同时保持架构简洁。
深入阐述上述不同方法需要很长的回答。但总的来说,扩展负载均衡器层并不难,扩展应用服务器层,特别是数据库层变得更加困难。
无论您选择设备规格(F5、Cisco、A10)还是通用服务器(Windows / Linux + 软件),都不太重要。扩展负载均衡器层时的主要考虑因素是:
- 全状态与无状态。您是否绝对需要粘性会话,或者没有粘性会话也可以?不保留状态会让一切变得更简单。
- “硬件”(ASIC)与“软件”(通用服务器)用于负载平衡。每种方法都有其优缺点,请参阅上面链接的 HAProxy 概述文档。
- L3/4 (IP / TCP/IP) 负载平衡与 L7 (HTTP)负载平衡。同样,优点和缺点,HAProxy 文档提供了很好的概述。
- SSL 终止,其中,在 Web 节点上或在负载均衡器上。
一般来说,在你的网站获得非常规模大——一台配备 fx nginx 的现代服务器每秒将处理数万个普通 HTTP 请求。因此,不要过早进行优化,不要在迫不得已之前处理这个问题。
答案3
扩展 HTTP 负载平衡层的关键是先添加另一层较低级别的(IP 或 TCP)负载平衡。此层可以完全使用开源软件构建,但如果您拥有现代路由器,效果会更好。
流量(TCP 会话)应该哈希使用诸如源/目标 IP 和 TCP 端口之类的标头来决定它们要转到哪个前端。您还需要一种机制来确保当前端死机时,它不再被使用。
有各种策略,我将概述一些我在为数百万用户提供服务的网站上使用过的策略,以便您了解这些策略。详细解释所有内容会很长,但我希望这个答案能为您提供足够的信息/指示,让您开始使用。为了实施这些解决方案,您需要一个真正了解网络的人。
诚然,我在这里描述的比其他答案中描述的更难实现,但如果你有一个流量很大的网站,并且存在很大的可扩展性问题,并且可用性要求超过 99.9%,那么这确实是最先进的。假设你已经有一名网络工程师,那么它的安装和运行成本(包括资本支出和运营支出)比负载平衡器设备要低,而且它几乎不需要额外成本就可以进一步扩展(相比之下,当你的当前型号不够用时,需要购买新的、甚至更昂贵的设备)。
第一个策略:使用防火墙
假设您有几台路由器,您的 ISP 上行链路连接到这些路由器上。您的 ISP 提供 2 条链路(主动/被动,使用 VRRP)。在您的路由器上,您还使用 VRRP,并将流向公共网络的流量路由到防火墙。防火墙(FW 1
及FW 2
以下)也是主动/被动的,将过滤流量并将每个流发送到健康的前端服务器(您的 HTTP 负载平衡器FE 1
及FE 2
以下)。
+--------------+ +--------------+ | ISP 路由器 A | | ISP 路由器 B | +--------------+ +--------------+ | | ==#========================#==(公网) | | +---------------+ +---------------+ | 您的路由器 A | | 您的路由器 B | +---------------+ +---------------+ | | ==#=====#============#=====#==(RFC 1918 私有网络) | | | | +------+ +------+ +------+ +------+ +------+ | FW 1 | | FE 1 | | FE 2 | | FW 2 | +------+ +------+ +------+ +------+ +------+
目标是使流程看起来如下:
- ISP 将发往您的 IP 的流量路由至您的活动路由器。
- 您的路由器将流量路由到使用RFC 1918地址。此 VIP 由活动防火墙拥有,与 VRRP 非常相似。如果您使用 OpenBSD 满足防火墙需求,那么您可以使用鲤鱼,VRRP/HSRP 的无专利替代方案。
- 您的防火墙应用了过滤器(例如“仅允许 80/tcp 和 443/tcp 进入这个特定的 IP 地址”)。
- 您的防火墙还可以充当路由器,并将数据包转发到健康的前端。
- 您的前端终止 TCP 连接。
现在奇迹发生在步骤 4 和步骤 5 中,所以让我们更详细地看看它们做了什么。
您的防火墙知道前端列表(FE 1
和FE 2
),它会根据流量的特定方面(例如通过散列源 IP 和端口以及其他标头)选择其中一个。但它还需要确保它将流量转发到健康的前端,否则您将黑洞流量。例如,如果您使用 OpenBSD,则可以使用relayd
。它relayd
的作用很简单:它会对所有前端进行健康检查(例如,通过向它们发送探测 HTTP 请求),并且每当前端健康时,它都会将其添加到防火墙用来选择给定流的数据包的下一跳的表中。如果前端未通过健康检查,它将从表中删除,并且不再向其发送任何数据包。当将数据包转发到前端时,防火墙所做的就是将数据包的目标 MAC 地址交换为所选前端的 MAC 地址。
在步骤 5 中,负载均衡器(无论是 Varnish、nginx 还是其他)接收来自用户的数据包。此时,数据包仍发往您的公共 IP 地址,因此您需要在环回接口上为您的 VIP 设置别名。这称为直接反射式(直接服务器返回),因为您的前端终止 TCP 连接,中间的防火墙仅看到单工流量(仅传入数据包)。您的路由器将直接将传出数据包路由回 ISP 的路由器。这对于 HTTP 流量尤其有用,因为请求往往小于响应,有时甚至小得多。需要明确的是:这不是 OpenBSD 特有的东西,在高流量网站中广泛使用。
陷阱:
- 由于您使用 DSR,最终用户将直接连接到您的前端服务器。也许已经是这种情况了,但如果不是,您需要确保它们得到充分保护。
- 如果您使用 OpenBSD,请注意内核是单线程的,因此单个 CPU 核心的性能将限制防火墙的吞吐量。这可能是一个问题,具体取决于您的 NIC 类型和您看到的数据包速率。有多种方法可以解决此问题(下文将详细介绍)。
第二种策略:不使用防火墙
此策略效率更高,但设置起来更困难,因为它更多地取决于您拥有的路由器的具体情况。其理念是绕过上面的防火墙,让路由器完成防火墙所做的所有工作。
您需要支持每端口 L3/L4 ACL 的路由器,边界网关协议和等价路由协议, 和基于策略的路由(PBR)。只有高端路由器才支持这些功能,而且它们通常需要支付额外的许可费用才能使用 BGP。这通常比硬件负载平衡器更便宜,而且扩展起来也容易得多。这些高端路由器的好处是它们往往是线速的(例如,它们总是可以最大化链路,即使在 10GbE 接口上也是如此,因为它们做出的所有决策都是由 ASIC 在硬件中完成的)。
在您拥有 ISP 上行链路的端口上,应用防火墙上的 ACL(例如“仅允许 80/tcp 和 443/tcp 进入此特定 IP 地址”)。然后让每个前端都与您的路由器保持 BGP 会话。您可以使用出色的开放BGPD(如果你的前端在 OpenBSD 上)或斑驴。您的路由器将 ECMP 流量发送到健康的前端(因为它们正在维护其 BGP 会话)。路由器还将使用 PBR 适当地路由流量。
改进
- 使用防火墙配对解决方案,如果您可以跨防火墙同步 TCP 状态,那么当一个防火墙发生故障时,一切都可以顺利地转移到另一个防火墙,那就太好了。您可以使用
pfsync
。- 请记住,这
pfsync
通常会使防火墙的数据包速率加倍。 - HTTP 是一种无状态协议,因此如果您在防火墙故障转移期间重置所有连接,这并不是世界末日,因为您不使用
pfsync
。
- 请记住,这
- 如果单个防火墙不够用,您可以在路由器上使用 ECMP 将流量路由到多对防火墙。
- 如果您使用多对防火墙,最好将它们全部设置为主动/主动。您可以通过让防火墙与路由器保持 BGP 会话来实现这一点,就像在没有防火墙的第二种设计中前端需要保持会话一样。
示例relayd
配置
另请参阅 HOWTOhttps://calomel.org/relayd.html
vip="1.2.3.4" # 你的公网 IP 地址 #(你可以有多个,但不需要) fe1="10.1.2.101" fe2="10.1.2.102" fe3="10.1.2.103" fe4="10.1.2.104" # 您可以拥有任意数量的前端。 int_if="em0" 表 <fe> { $fe1 重试 2, $fe2 重试 2, $fe3 重试 2, $fe4 重试 2 } 表 <fallback> { 127.0.0.1 } 重定向网络流量 { 监听 $vip 端口 80 会话超时 60 路由到 <fe> 检查 http "/healthcheck.html" 摘要 "(healthcheck.html 的 sha1sum)" 接口 $int_if }
答案4
或许,您不需要不断地保持这么多的开放连接来发送回复,而是以这样的方式编写应用程序,以便客户端可以根据需要定期轮询您的服务器?
您正在执行的操作是否实际上需要在这一毫秒内做出响应,或者客户端是否可以等待 15/20 秒直到下一个轮询期?