使用负载平衡使应用程序可扩展(2006)

2020-11-24 23:04:33

作为HAProxy负载均衡器的作者,我经常被问到负载均衡架构或负载均衡器之间的选择。由于没有明显的响应,因此有必要列举几种解决方案的优缺点,以及一些应避免的陷阱。我希望很快通过更深入的HTTP分析和体系结构示例来完成本文。您可以与我联系以获取更多信息。该文档现在可以PDF格式提供:最初,Web大部分是静态内容,很快传递给一些用户,这些用户大部分时间都是在很少点击之间阅读。现在,我们看到了真正的应用程序,它们将用户保留了数十分钟或几小时,而单击之间的内容很少,而在服务器上执行的工作却很多。用户经常访问相同的站点,他们非常了解这些站点,并且不会花费很多时间阅读。他们希望立即交付,而无意识地在每次单击时都对服务器造成巨大的负担。这种新的动态对高性能和永久可用性提出了新的要求。由于任何服务器的功能都是有限的,因此Web应用程序必须能够在多台服务器上运行才能接受越来越多的用户。这称为缩放。对于Intranet应用程序,可伸缩性并不是真正的问题,因为用户数量几乎没有增加的机会。但是,在Internet门户上,负载随着宽带Internet访问的可用性而不断增加。站点的维护者必须找到方法,通过应用程序服务器中包含的内部机制,外部组件或架构重新设计,将负载分散到多个服务器上。负载平衡是使多个服务器参与同一服务并执行相同工作的能力。随着服务器数量的增加,任何地方出现故障的风险都会增加,必须予以解决。在任何预定义数量的同时发生的故障期间保持不受影响的服务的能力称为高可用性。负载平衡通常是强制性的,这就是人们经常混淆这两个概念的原因。但是,某些负载平衡技术无法提供高可用性,并且很危险。执行负载平衡的最简单方法是将服务器专用于预定义的用户组。在Intranet服务器上这很容易,但在Internet服务器上却并非如此。通用方法依赖于DNS轮询。如果DNS服务器具有给定主机名的多个条目,它将以循环顺序返回所有这些条目。这样,各个用户将看到相同名称的不同地址,并且能够访问不同的服务器。这在多站点负载平衡中非常常用,但是它要求应用程序不因缺少服务器上下文而受到影响。因此,搜索引擎,POP服务器通常将其用于或传递静态内容。此方法不提供任何可用性方法。它需要采取其他措施来永久检查服务器状态,并将故障服务器的IP切换到另一台服务器。因此,它通常用作补充解决方案,而不是主要解决方案。 $ host -t google.comgoogle.com。地址为64.233.167.99google.com。地址为64.233.187.99google.com。地址为72.14.207.99 $ host -t google.comgoogle.com。地址为72.14.207.99google.com。地址为64.233.167.99google.com。地址为64.233.187.99 $ host -t mail.aol.commail.aol.com。地址为205.188.162.57mail.aol.com。地址为205.188.212.249mail.aol.com。地址为64.12.136.57mail.aol.com。地址为64.12.136.89mail.aol.com。地址为64.12.168.119mail.aol.com。地址为64.12.193.249mail.aol.com。地址为152.163.179.57mail.aol.com。地址为152.163.211.185mail.aol.com。地址为152.163.211.250mail.aol.com。地址为205.188.149.57mail.aol.com。地址为205.188.160.249

图1:DNS轮循:分配给同一名称的多个地址,以轮换顺序返回

一种更常见的方法是将用户群分散到多个服务器上。这涉及用户和服务器之间的负载平衡器。它可以包含在专用前端服务器或应用程序服务器本身上安装的硬件设备或软件中。请注意,通过部署新组件,出现故障的风险会增加,因此通常的做法是让第二个负载均衡器充当主负载均衡器的备份。通常,硬件负载平衡器将在网络数据包级别工作,并使用以下方法之一在路由上起作用:直接路由:负载平衡器通过不同的本地物理服务器(必须位于同一服务器上)路由同一服务地址网段,并且必须共享相同的服务地址。它具有不修改IP级别任何内容的巨大优势,因此服务器可以直接回复用户,而无需再次通过负载平衡器。这称为“直接服务器返回”。由于此方法所需的处理能力很小,因此通常是在流量非常高的站点的前端服务器上使用的处理能力。另一方面,它需要对TCP / IP模型有扎实的知识,才能正确配置包括服务器在内的所有设备。

隧道:它的工作原理与直接路由完全相同,不同之处在于,通过在负载均衡器和服务器之间建立隧道,这些服务器可以位于远程网络上。服务器仍然可以直接返回。

IP地址转换(NAT):用户连接到虚拟目标地址,负载平衡器将其转换为服务器的地址之一。乍一看,这很容易部署,因为服务器配置中的麻烦较少。但这需要更严格的编程规则。一个常见错误是应用程序服务器在某些响应中指示其内部地址。同样,这需要在负载平衡器上做更多的工作,负载平衡器必须来回转换地址以维护会话表,并且还要求返回流量也要通过负载平衡器。有时,负载均衡器上的会话超时时间过短会引起称为ACK风暴的副作用。在这种情况下,唯一的解决方案是增加超时,这有可能使负载均衡器的会话表饱和。

相反,我们找到了软件负载平衡器。它们最常充当反向代理的角色,冒充服务器并向其转发流量。这意味着不能直接从用户处访问服务器本身,并且某些协议可能永远无法达到负载平衡。他们需要比网络级别上更多的处理能力,但是由于它们拼接了用户和服务器之间的通信,因此它们仅通过转发他们所了解的内容即可提供第一级安全性。这就是为什么我们经常在这些产品上找到URL过滤功能的原因。要选择服务器,负载均衡器必须知道哪些可用。为此,它将定期向他们发送ping,连接尝试,请求或管理员认为有效的方法来限定其状态。这些测试称为“健康检查”。崩溃的服务器可能会响应ping而不响应TCP连接,而挂起的服务器可能响应TCP连接而不响应HTTP请求。当涉及到多层Web应用程序服务器时,某些HTTP请求将提供即时响应,而另一些HTTP请求将失败。因此,真正有兴趣选择应用程序和负载平衡器允许的最具代表性的测试。一些测试可能会从数据库中检索数据以确保整个链都是有效的。缺点是这些测试将消耗一定数量的服务器资源(CPU,线程等)。它们必须及时间隔开,以避免过多地加载服务器,但仍应足够接近,以快速检测到故障的服务器。运行状况检查是负载平衡中最复杂的方面之一,非常常见的是,在进行了几次测试之后,应用程序开发人员最终会实现一个专门针对负载均衡器的特殊请求,该请求将执行许多内部代表性测试。就此而言,软件负载平衡器是目前为止最灵活的,因为它们通常提供脚本功能,并且如果一项检查需要修改代码,则软件的编辑器通常可以在很短的时间内提供它们。负载均衡器可以通过多种方式分配负载。一个常见的误解是期望它向“第一台要响应的服务器”发送请求。这种做法是错误的,因为如果服务器有任何理由甚至更快地答复,它将通过获取大多数请求来平衡服务器场。第二个想法通常是将请求发送到“负载最少的服务器”。尽管这在会话时间非常长的环境中很有用,但是它不适用于负载在几秒钟内变化两位数的Web服务器。对于同类服务器场,“轮询”方法通常是最好的方法。它依次使用每个服务器。如果服务器的容量不相等,则“加权轮询”算法将根据其配置的相对容量将流量分配给服务器。这些算法存在一个缺点:它们是不确定的。这意味着来自同一用户的两个连续请求将很有可能到达两个不同的服务器。如果用户上下文存储在应用程序服务器上,则它们将在两个连续的请求之间丢失。而且,当发生复杂的会话设置(例如:SSL密钥协商)时,必须在每个连接上一次又一次地执行它。要变通解决此问题,通常涉及一个非常简单的算法:地址哈希。概括地说,将用户的IP地址除以服务器数量,结果将确定该特定用户的正确服务器。只要服务器的数量不变并且用户的IP地址稳定(这并非总是如此),此方法就可以很好地工作。万一服务器发生故障,所有用户将重新平衡并失去会话。通过代理服务器场浏览的用户中,只有少数用户也将无法使用该应用程序(通常为5-10%)。但是,此方法并不总是适用,因为要获得良好的分发,就需要大量的源IP地址。在Internet上确实如此,但在小公司甚至ISP的基础架构中并不总是如此。但是,这非常有效,可以避免过多地重新计算SSL会话密钥。解决上述限制的方法就是使用持久性。持久性是一种确保给定用户对其上下文知道的所有请求,将继续使用同一服务器的方法。常见的廉价解决方案是应用程序使用HTTP 302响应将重定向发送回本地服务器地址。一个主要的缺点是,当服务器发生故障时,用户无法轻松逃脱,并不断尝试访问失效的服务器。与DNS一样,此方法仅在保证传递给用户的地址可访问时才在大型站点上有用。第二种解决方案是让负载均衡器学习用户-服务器关联,最便宜的方法是了解上次哪个用户的IP到达了哪个服务器。通常,这可以解决由于故障而导致服务器场大小变化的问题,但不能解决IP地址可变的用户的问题。那还剩下什么呢?从一开始,我们就表示我们要保证用户在对同一服务器的后续请求中都能找到自己的上下文。服务器如何识别上下文?通过一个cookie。 Cookie正是出于这个目的而发明的:向用户发送信息,他将在以后的访问中将其传递回去,以便我们知道如何处理他。当然,这需要用户支持cookie,但是在需要持久性的应用程序上通常是这种情况。如果负载均衡器可以根据用户提供的cookie识别服务器,则可以解决大多数问题。关于cookie的方法主要有两种:负载均衡器可以学习服务器分配的会话cookie,或者可以插入cookie来标识服务器。 Cookie学习是侵入性最小的解决方案。负载平衡器配置为学习应用程序cookie(例如“ JSESSIONID”)。收到用户的请求时,它将检查它是否包含此cookie和一个已知值。如果不是这种情况,它将根据负载平衡算法将请求定向到任何服务器。然后,它将从响应中提取cookie值,并将其与服务器标识符一起添加到本地表中。当用户再次回来时,负载均衡器将看到cookie,查找表并找到将请求转发到的服务器。此方法尽管易于部署,但有两个较小的缺点,此方法的学习方面暗示了这一点:负载平衡器具有有限的内存,因此可能会饱和,而避免这种情况的唯一解决方案是限制表中的cookie寿命。这意味着,如果用户在Cookie到期后返回,则该用户将被定向到错误的服务器。

如果负载平衡器失效并且其备份接管,它将不知道任何关联,并将再次将用户定向到错误的服务器。当然,也不能以主动-主动组合方式使用负载均衡器。一种解决方案是实时会话同步,这很难保证。

这些缺点的解决方法通常是在可能的情况下选择确定性负载平衡算法,例如用户的地址哈希。这样,如果cookie在负载均衡器上丢失,则至少具有固定IP地址的用户将保留在其服务器上。

如果用户支持cookie,为什么不添加另一个带有固定文本的cookie?此方法称为“ cookie插入”,在于将服务器的标识符插入添加到响应中的cookie中。这样,负载均衡器无需学习,它将简单地重用用户提供的值来选择合适的服务器。这解决了cookie学习的两个问题:内存限制和负载平衡器接管。但是,它需要负载平衡器付出更多的努力,该负载平衡器必须打开流插入数据。这不容易做到,特别是在基于ASIC的负载平衡器上,TCP / HTTP知识非常有限。它还要求用户代理接受多个cookie。例如,在小型移动终端上并非总是如此,小型移动终端有时仅限于一个cookie。然后,可以应用有关此概念的多种变体,例如cookie修改,其中包括在已经存在的cookie之前加服务器标识符。还应在负载平衡器上特别注意响应的可缓存性:前端缓存可能会存储负载平衡器cookie,并将其传递给所有请求索引页面的用户,例如,这将导致所有用户都被定向到同一服务器。我们已经审查了涉及监听用户服务器交换的方法,有时甚至涉及修改。但是,随着越来越多的应用程序依靠SSL来确保其安全性,负载平衡器将无法始终访问HTTP内容。因此,我们看到越来越多的软件负载平衡器提供对SSL的支持。原理很简单:负载均衡器充当反向代理并充当SSL服务器端。它保存服务器的证书,解密请求,访问内容并将请求定向到服务器(明文或稍加重新加密)。这为不再需要管理SSL的应用程序服务器带来了新的性能提升。但是,负载平衡器成为瓶颈:单个基于软件的负载平衡器处理SSL的速度不会比拥有八台服务器的服务器场快。由于此体系结构错误,负载均衡器将在应用程序服务器之前达到饱和,唯一的补救方法是在其前面放置另一级负载均衡器,并添加更多负载均衡器以处理SSL负载。显然,这是错误的。维护一组负载均衡器非常困难,并且所有这些负载均衡器发送的运行状况检查将导致服务器明显负载。正确的解决方案是拥有专用的SSL服务器场。当应用程序需要SSL时,最具可扩展性的解决方案就是专门针对此问题使用反向代理服务器群。此解决方案仅具有优点:SSL反向代理非常便宜但功能强大。任何人都可以花费不到1000美元构建功能强大的基于Apache的SSL反向代理。这必须与相同性能的启用了SSL的负载均衡器(超过15000美元)的成本以及用于该应用程序的多处理器服务器的成本进行比较,而不必再为使用SSL而浪费。

SSL反向代理几乎总是提供缓存,有时甚至提供压缩。大多数电子商务应用程序的可缓存率在80%到90%之间,这意味着这些反向代理缓存将使服务器的负载至少减少80%。

再加上SSL代理可以在多个应用程序之间共享的事实,总体收益减少了对大型应用服务器的需求,这也影响了维护和许可成本。

SSL场可以随着流量的增长而增长,而无需升级负载平衡器或更换负载均衡器。只要正确设计了架构,负载均衡器的容量通常就可以满足大多数站点的要求。

代理的第一层通过过滤无效请求提供了非常好的安全性,并且经常提供为已知攻击添加URL过滤器的能力。

如果发现非常具体的需求(例如,强身份验证),则很容易更换SSL场中涉及的产品。相反,由于不同的运行状况检查方法,负载平衡算法和持久性手段,为此替换启用SSL的负载平衡器可能会对应用程序的行为产生可怕的影响。

负载均衡器的选择将仅基于负载均衡功能,而不是基于其SSL性能。它会比一站式解决方案更加适应且便宜得多。

SSL-proxy-cache服务器场由一组相同的服务器组成,它们几乎始终运行任何形式的Apache + ModSSL(即使在伪装的商业解决方案中也是如此),这些服务器可以通过外部网络负载平衡器或内部软件进行负载平衡负载平衡器,例如Linux下的LVS。这些服务器几乎不需要维护,因为它们的唯一任务是将HTTPS流量转换为HTTP,检查缓存并将不可缓存的请求转发到由负载均衡器和应用程序服务器代表的应用程序服务器场。有趣的是,反向代理和应用程序服务器之间可以共享同一负载均衡器。尽管所有解决方案似乎都可以完成所有工作,但事实并非如此。基本上,选择负载均衡器需要考虑三个方面:性能至关重要,因为当负载均衡器成为瓶颈时,什么也做不了。可靠性非常重要,因为负载均衡器会处理所有流量,因此就可用性以及处理质量而言,其可靠性必须比服务器高几个数量级。功能决定选择解决方案,但并不关键。这取决于在更改应用程序服务器时可以接受哪些折衷。在将基于硬件的负载平衡器与基于代理的负载平衡器进行比较时,最常见的问题之一是为什么之间存在这样的差距

......