博客 | NGINX

选择 NGINX Plus 负载均衡技术

NGINX-F5-horiz-black-type-RGB 的一部分
Tony Mauro 缩略图
托尼·毛罗
2015 年 10 月 29 日发布

我们已经写了很多关于如何使用 NGINX Plus 和 NGINX Open Source 来平衡您的网站和应用程序的负载,以实现最佳可用性和可靠性的文章。 负载平衡提高应用程序性能大规模交付应用程序以及部署容器和微服务的基本工具。

我们之前已经解释过如何在数据中心(可能与传统的应用交付控制器一起)、容器和云环境(包括Amazon Web Services (AWS)、 Google Cloud PlatformMicrosoft Azure )中部署 NGINX Plus。

在这篇文章中,我们将重点介绍 NGINX Plus 和 NGINX 中的负载平衡技术(也称为负载平衡方法算法),并提供一些如何针对不同用例选择正确方法的建议。 NGINX 提供了四种负载平衡技术(循环哈希IP 哈希最少连接),而 NGINX Plus 又增加了一种(最少时间)。 除 IP Hash 外,所有用于 HTTP 流量的方法也适用于 TCP(以及 NGINX Plus Release 9 及更高版本中的 UDP)。

[编辑器- NGINX Plus R16NGINX Open Source 1.15.1引入了“两种选择的随机数”作为附加的负载平衡算法。 有关讨论,请参阅我们博客上的NGINX 和“两种选择的力量”负载平衡算法。]

回顾负载平衡技术

我们假设您了解如何配置负载均衡的基础知识,但如果您想复习一下,可以查看以下资源:

  • NGINX Plus 管理指南中的文章提供了完整的概述。
  • 高性能负载平衡链接到有关 NGINX Plus 中增强功能的详细讨论,这些功能可以进一步提高负载平衡方法的效率。
  • 使用 NGINX 和 NGINX Plus 进行负载平衡第 1 部分第 2 部分是一个演练,它使用 NGINX Plus 的增强功能将简单的反向代理构建为全面的负载平衡解决方案。
  • 负载平衡解决方案页面链接到其他资源,包括电子书、网络研讨会和白皮书。

为了简单起见,我们将重点关注您在http上下文中配置的 HTTP 负载均衡。 TCP 负载均衡是在上下文中配置的(就像 NGINX Plus Release 9 及更高版本中的 UDP 负载均衡一样)。 尽管 HTTP 和 TCP/UDP 负载均衡器具有相同的功能,但由于协议之间固有的差异,可用的指令和参数略有不同;有关详细信息,请参阅有关HTTPTCP/UDP上游模块的文档。

您可以使用两个配置块启用负载均衡,我们将以它们的基本形式展示它们,没有可选参数或任何辅助功能:

  • 服务器块定义一个虚拟服务器,该虚拟服务器监听具有您定义的特征的流量,并将其代理到指定的上游服务器组。 在我们的示例中,虚拟服务器在默认端口 (80) 上侦听发送到www.example.com的 HTTP 流量,并将其代理到名为backend的上游服务器组。 在我们所有的示例中,这个块都是相同的。

    服务器 { server_name www.example.com;
    
    位置 / {
    proxy_pass http://backend;
    }
    }

    (NGINX Plus 和 NGINX 还可以对 FastCGI、memcached、SCGI 和 uwsgi 后端服务器进行负载平衡。 用适当的指令替换proxy_passfastcgi_passmemcached_passscgi_passuwsgi_pass 。)

  • 上游块命名上游组并列出属于该组的服务器,通过主机名、IP 地址或 UNIX 域套接字路径标识。 在我们的示例中,名为backend的上游组包括三台服务器: web1web2web3

    上游块是您指定负载平衡技术的地方,因此我们将在后面的部分中重点介绍这一点。 举个例子,下面是默认方法 Round Robin 的块:

    上游后端 { 服务器 web1;
    服务器 web2;
    服务器 web3;
    }

循环赛

循环是 NGINX Plus 和 NGINX 的默认负载平衡技术。负载平衡器按顺序遍历上游服务器列表,并依次将下一个连接请求分配给每个服务器。

给定以下后端上游组的示例配置,负载均衡器按顺序将前三个连接请求发送到web1web2web3 ,第四个连接请求发送到web1 ,第五个连接请求发送到web2 ,依此类推。

上游后端 { 服务器 web1;
服务器 web2;
服务器 web3;
}

服务器 {
server_name www.example.com;

location / {
proxy_pass http://backend;
}
}

哈希

使用 Hash 方法,对于每个请求,负载均衡器都会根据您指定的文本和NGINX 变量的组合计算一个哈希值,并将该哈希值与其中一个服务器关联起来。 它将所有带有该哈希值的请求发送到该服务器,因此此方法建立了一种基本类型的会话持久性

在以下示例中, hash指令使用方案( httphttps )和请求的完整 URI 作为哈希的基础:

上游后端 { hash $scheme$request_uri; 服务器 web1; 服务器 web2; 服务器 web3; } 服务器 { server_name www.example.com; location / { proxy_pass http://backend; } }

IP 哈希

IP Hash(仅适用于 HTTP)是 Hash 方法的预定义变体,其中哈希基于客户端的 IP 地址。 您可以使用ip_hash指令来设置它。

上游后端 { ip_hash ; 服务器 web1; 服务器 web2; 服务器 web3; } 服务器 { server_name www.example.com; location / { proxy_pass http://backend; } }

如果客户端具有 IPv6 地址,则哈希基于整个地址。 如果它具有 IPv4 地址,则哈希仅基于该地址的前三个八位字节。 这是为了针对从子网 (/24) 范围动态分配 IP 地址的 ISP 客户端进行优化。 在重启或重新连接的情况下,客户端的地址通常会更改为 /24 网络范围内的其他地址,但连接仍然代表同一个客户端,因此没有理由更改到服务器的映射。

但是,如果您网站的大部分流量来自同一个 /24 网络上的客户端,则 IP Hash 就没有意义了,因为它会将所有客户端映射到同一个服务器。 在这种情况下(或者如果您因为其他原因想要对所有四个八位字节进行散列),请改用带有$remote_addr变量的 Hash 方法。

哈希$remote_addr;

最少连接

使用最少连接方法,负载均衡器将比较当前与每个服务器的活动连接数,并将请求发送到连接数最少的服务器。 您可以使用least_conn指令对其进行配置。

上游后端 { least_conn ; 服务器 web1; 服务器 web2; 服务器 web3; } 服务器 { server_name www.example.com; location / { proxy_pass http://backend; } }

最少时间

使用最短时间方法(仅在 NGINX Plus 中可用),负载均衡器以数学方式组合每个服务器的两个指标——当前活动连接数和过去请求的加权平均响应时间——并将请求发送到具有最低值的服务器。

您在least_time指令上选择的参数控制跟踪两个响应时间中的哪一个:接收响应头( header )的时间或接收完整响应( last_byte )的时间。

上游后端 { least_time (header | last_byte) ;服务器 web1;服务器 web2; 服务器 web3; } 服务器 { server_name www.example.com; location / { proxy_pass http://backend; } }

笔记:

  • 对于 TCP 和 UDP 负载均衡(在上下文中),您可以使用以下参数从三种类型的响应时间中选择least_time指令:

    • connect – 连接上游服务器的时间
    • first_byte – 接收响应数据第一个字节的时间
    • last_byte – 接收响应数据的最后一个字节的时间
  • 对于 HTTP 和 TCP/UDP 流量,在NGINX Plus R12及更高版本中添加inflight参数以在每个指标中包含不完整的连接;早期版本中默认包含此类连接。

选择负载平衡技术

那么,您如何知道哪种负载平衡技术最适合您的网站或应用程序?

站点之间的流量模式差异很大 - 甚至在一天中的不同时间,单个站点内的流量模式也存在很大差异 - 因此,基于单一特征(例如突发流量与稳定流量、短暂连接与长寿命连接等等)来选择负载平衡技术是没有意义的。 话虽如此,我们会考虑每种方法的优缺点,以帮助您缩小考虑的选择范围。

运行测试来比较方法

无论您考虑哪种负载平衡方法,我们都鼓励您对其进行测试,以确定哪种方法最适合您的流量。 “最佳”通常意味着在最短的时间内向客户提供答复,但您可能有不同的标准。

application性能管理工具对于此类测试非常方便——您可以为上游组中的每个服务器创建带有图表的自定义屏幕,从而可以在测试期间值发生变化时实时比较它们。 一些 APM 为 NGINX Plus 和 NGINX 提供自定义插件,包括AppDynamicsDatadogDynatraceNew Relic

如果所有服务器具有相同的容量,则测试最为简单。 如果没有,则需要设置服务器权重,以便容量更大的机器接收更多请求。 请参阅下面的当服务器不相同时设置权重

测试期间要检查的一些指标包括:

  • CPU 和内存负载——查看 CPU 和内存的总容量使用百分比。 如果所有服务器的负载不均等,流量就无法有效分配。
  • 服务器响应时间——如果某些服务器的响应时间始终高于其他服务器,那么“更重”的请求(需要更多计算或调用数据库或其他服务)就会以不平衡的方式定向到这些服务器。 尝试调整权重,因为不平衡可能是由不正确的权重而不是负载平衡技术问题引起的。
  • 响应客户端的总时间——同样,某些服务器的响应时间持续较长,表明它们接收到的耗时请求份额不成比例。 您可以再次尝试调整重量,看看是否能消除问题。
  • 错误和失败的请求——您需要确保测试期间失败的请求和其他错误的数量不超过您的网站的正常数量。 否则,您是根据错误情况而不是实际流量来做出决定的。 对于某些错误,服务器可以比请求成功时更快地发送响应。 对于 HTTP 响应代码404找到文件),例如,服务器返回错误的速度可能比传送实际文件(如果存在)的速度要快得多。 采用最少连接和最少时间负载平衡算法,可能会导致负载平衡器偏向实际上运行不佳的服务器。

优点、缺点和用例

现在让我们看看每种负载平衡技术的优点和缺点,并描述一些特别适合它们的用例。 我们将按照对大多数用例的适用性的增加的顺序来讨论它们。 快速预览:我们认为最少连接(以及对于 NGINX Plus,最少时间)是最广泛用例的最佳选择。

哈希和 IP 哈希

Hash 和 IP Hash 负载平衡技术在给定类型的客户端请求(在哈希值中捕获)和特定服务器之间建立固定关联。 您可能会将其识别为会话持久性——具有给定哈希值的所有请求始终发送到同一台服务器。

这些方法的最大缺点是它们不能保证在各个服务器上分配相同数量的请求,更不用说均匀地平衡负载了。 哈希算法将所有可能的哈希值集合均匀地划分为“存储桶”,上游组中的每个服务器一个存储桶,但无法预测实际发生的请求是否具有均匀分布的哈希值。 例如,假设有十个客户端正在访问某个站点,而 IP 哈希算法恰好将其中七个 IP 地址的哈希与web1关联,一个与web2关联,两个与web3关联。 web1服务器最终接收的请求数是其他服务器总请求数的两倍多。

Hash 和 IP Hash 负载平衡技术可能会导致负载分配不均

因此,当维持会话的好处大于不平衡负载可能带来的不良影响时,使用 Hash 或 IP Hash 是有意义的。 它们是 NGINX 中唯一可用的会话持久形式。NGINX Plus 提供了另外三种会话持久机制,这些机制更为复杂,可与实际负载均衡结合使用(您可以使用sticky指令对其进行配置)。 但即使使用 NGINX Plus,您也可能选择 Hash 或 IP Hash,因为这三种机制在以下情况下不起作用:

  • 浏览器或客户端应用程序不接受 cookie,并且应用无法在没有 cookie 的情况下使用会话持久机制。 使用 IP Hash 方法将每个客户端(特别是其 IP 地址)与特定服务器关联。

  • 您希望每次都将针对给定 URL 的请求发送到同一台服务器,以利用服务器本身的缓存功能。 使用带有$request_uri变量的 Hash 方法每次从同一台服务器获取文件。

    例如,假设您知道提供某个.php文件需要几次耗时的数据库调用,但获取的数据不会经常更改,因此是可缓存的。 如果将文件的所有请求发送到同一台服务器,则只有第一个客户端会因为数据库调用而遇到较长的延迟。 对于所有后续客户端,都可以从缓存中快速检索数据。 另一个优点是只有一台服务器必须缓存特定的数据集。 因为您不需要在每台服务器上重复缓存相同的数据,所以您可以使用较小的缓存。

有几种情况下 IP 哈希(以及当客户端 IP 地址在密钥中时的哈希)不起作用:

  • 当客户端的 IP 地址在会话期间发生变化时,例如当移动客户端从 WiFi 网络切换到蜂窝网络时。
  • 当大量客户端的请求都通过正向代理时,因为代理的 IP 地址用于所有客户端的请求。

哈希是确定性的(哈希算法每次都会产生相同的结果)。 这有几个积极的副作用:部署中的所有 NGINX Plus 或 NGINX 实例都以完全相同的方式对请求进行负载平衡,并且哈希到服务器的映射在负载平衡器重新启动后仍然有效。 (重启后实际上会重新计算,但由于结果始终相同,因此它实际上会持续存在。)

另一方面,改变上游服务器集通常会强制重新计算至少一些映射,从而破坏会话持久性。 您可以稍微减少重新计算映射的次数:

  • 对于 Hash 方法,将一致参数包含在hash指令中;NGINX Plus 使用ketama哈希算法,从而减少重新映射。
  • 对于 IP Hash 方法,在暂时从上游组中删除服务器之前,请将down参数添加到其服务器指令中,如下例中的web2 。 假设服务器很快就会恢复服务,那么就不会重新计算映射。

    上游后端 { ip_hash; 服务器 web1; 服务器 web2关闭; 服务器 web3; }

循环赛

如前所述,Round Robin 是 NGINX Plus 和 NGINX 中的默认负载平衡方法。这无疑使其成为最容易选择的方法——您无需配置上游组本身以外的任何内容。

普遍的共识是,当服务器和请求的特性不太可能导致某些服务器相对于其他服务器过载时,循环算法效果最佳。 部分条件如下:

  • 所有服务器的容量大致相同。 如果服务器之间的差异可以通过服务器权重准确表示,则此要求就不那么重要。
  • 所有服务器都托管相同的内容。
  • 请求所需的时间或处理能力非常相似。 如果请求权重差异很大,服务器可能会超载,因为负载均衡器会连续快速地向其发送大量重量级请求。
  • 流量并不足以经常推动服务器接近满负荷状态。 如果服务器负载已经很重,那么 Round Robin 对请求的机械分配很可能会将某些服务器推入超载的边缘,如上一条所述。

循环调度特别适合测试场景,因为它可以确保请求分布在所有服务器上,并且数量相等(或按适当的权重比例)。 其他一些方法在流量较低时并不总是均匀分配流量,这可能会扭曲测试结果。

分布的均匀性还可以揭示缓存是否运行良好且满负荷:因为循环无法将给定文件的请求发送到同一台服务器,所以每台服务器都可能最终提供和缓存各种文件(并且通常与对等服务器的许多文件相同),这使得缓存更容易被填满。

最后,均匀的初始分布有助于发现 NGINX Plus 中的会话持久性问题(使用sticky指令配置)。

最少连接和最少时间

正如我们上面提到的,最少连接是最适用于最广泛用例的负载平衡技术,特别是对于生产流量。 我们客户的轶事证据支持了这一点。 其性能稳定且可预测。

最少连接还可以根据服务器的容量有效地分配工作负载。 功能更强大的服务器可以更快地满足请求,因此在任何给定时刻,与容量较小的服务器相比,它仍有可能处理更少的连接(甚至等待处理开始)。 最少连接将每个请求发送到当前连接数最少的服务器,因此更有可能将请求发送到功能强大的服务器。 (但是,设置权重仍然会导致更高效的请求分配,如下面当服务器不相同时设置权重中所述。)

您可以将最少时间(仅限 NGINX Plus)视为最少连接的更敏感版本。 通过包含平均响应时间,它考虑了服务器的近期性能历史记录(它实际上是一个指数加权移动平均值,因此较旧的响应时间对平均值的影响比较近的响应时间要小)。

当上游服务器的平均响应时间差异很大时,最短时间尤其适用。 例如,如果为了实现灾难恢复,您在不同的数据中心拥有服务器,则最短时间倾向于向本地服务器发送更多请求,因为它们的响应速度更快。 另一个用例是云环境,其中服务器性能通常非常难以预测。

最少时间是 NGINX Plus 中的负载平衡技术之一

当服务器不相同时设置权重

我们已经多次提到,当上游组中的服务器具有不同容量时设置服务器权重的重要性。 对于循环负载均衡器来说,这一点尤为重要,否则它会向每台服务器发送相同数量的请求。 这可能会导致性能较弱的服务器超载,而性能较强的服务器则处于部分空闲状态。

要设置权重,请在上游块中的一个或多个服务器指令中包含权重参数。 默认值为 1。

您可以按照以下方式考虑为不同的负载平衡技术设置权重的效果。 请记住,这些描述在概念上是正确的,但 NGINX Plus 代码中的实现不一定使用所指示的数学运算。 以下是我们示例的上游组:

上游后端 { 服务器 web1 权重=6;
服务器 web2 权重=3;
服务器 web3;
}
  • 循环调度——每台服务器获得的传入请求百分比等于其权重除以权重总和。 在我们的示例中,每十个请求中, web1获得六个(60%), web2获得三个(30%), web3获得一个(10%)。

  • 哈希IP 哈希——回想一下,如果没有权重,哈希算法会将所有可能的哈希值集合均匀地分成“桶”,每个桶对应上游组中的每个服务器。 对于权重,它会对权重求和,将可能的哈希值集合划分到该数量的桶中,并将每个服务器与等于其权重的桶数相关联。

    在我们的示例中,有 10 个桶,每个桶包含 10% 的可能哈希值。 六个存储桶(占可能哈希值的 60%)与web1关联,三个存储桶(占 30%)与web2关联,一个存储桶(占 10%)与web3关联。

  • 最少连接最少时间——我们之前提到过,即使没有权重,这些算法也能非常有效地根据服务器容量在服务器之间分配工作负载。 设置权重可以进一步提高他们在这方面的表现。

    回想一下,最少连接和最少时间将每个请求发送到具有最低“分数”(连接数,或连接数和时间的数学组合)的服务器。 当您分配权重时,负载均衡器会将每个服务器的分数除以其权重,然后再次将请求发送到具有最低值的服务器。

    下面是一个带有样本权重和指示的活动连接数的最少连接示例: web1的得分为 100,是最低的,尽管它的连接数为 600,是web2的 1.5 倍,是web3的 4 倍多,但它仍然获得请求。

    • web1 – 600 个活动连接 ÷ 6 = 100
    • web2 – 400 个活跃连接 ÷ 3 = 133
    • web3 – 125 个活跃连接 ÷ 1 = 125

概括

在回顾了 NGINX Plus 和 NGINX 中可用的负载平衡技术的优缺点之后,我们认为最少连接(对于 NGINX Plus,还有最少时间)最适合最广泛的用例。 但在部署中测试几种方法非常重要,因为其独特的流量和服务器特性组合可能会使另一种方法更适合您。

要亲自尝试 NGINX Plus 负载均衡,请立即开始30 天免费试用,或联系我们讨论您的用例。

我们很乐意听到您在不同用例中使用负载均衡的经验。 请将它们添加到下面的评论部分。


“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”