3.HTTP负载均衡
跨 Web 或应用程序服务器组对 HTTP 流量进行负载平衡,具有多种算法和高级功能(如慢启动(slow-start)和会话持久性(session persistence))。
概述
跨多个应用程序实例的负载均衡是一种常用的技术,用于优化资源利用率、最大化吞吐量、减少延迟和确保容错配置。
将 HTTP 流量代理到一组服务器
对一组服务器的 HTTP 流量进行负载平衡,首先需要使用 upstream 指令定义该组。该指令放置在 http 上下文中。
组中的服务器是使用 server 指令配置的(不要与定义在NGINX上运行的虚拟服务器的 server块混淆)。
例如,以下配置定义了一个名为 backend 的组,它由三个服务器配置组成(可以在三个以上的实际服务器中解析):
http {
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com;
server 192.0.0.1 backup;
}
}
若要将请求传递到服务器组,请在 proxy_pass 指令(或这些协议的 fastcgi_pass、memcached_pass、scgi_pass 或 uwsgi_pass 指令)中指定组的名称。
在下一个示例中,在 NGINX 上运行的虚拟服务器将所有请求传递到上一示例中定义的后端upstream组:
server {
location / {
proxy_pass http://backend;
}
}
以下示例结合了上面的两个代码段,并演示如何将 HTTP 请求代理到后端服务器组。该组由三台服务器组成,其中两台运行同一应用程序的实例,第三台是备份服务器。由于 upstream块中未指定负载平衡算法,因此NGINX使用默认算法Round Robin:
http {
upstream backend {
server backend1.example.com;
server backend2.example.com;
server 192.0.0.1 backup; #备份服务器使用,backup参数
}
server {
location / {
proxy_pass http://backend;
}
}
}
选择负载平衡方法
NGINX Open Source支持四种负载均衡方法
轮循机制(Round Robin) – 请求在服务器之间均匀分布,并考虑服务器权重。默认情况下使用此方法(没有启用它的指令):
upstream backend {
# no load balancing method is specified for Round Robin
server backend1.example.com;
server backend2.example.com;
}
最少连接(Least Connections) – 将请求发送到活动连接数最少的服务器,再次考虑服务器权重:
upstream backend {
least_conn;
server backend1.example.com;
server backend2.example.com;
}
IP 哈希(IP Hash) – 向其发送请求的服务器由客户端 IP 地址确定。在这种情况下,IPv4 地址的前三个八位字节或整个 IPv6 地址用于计算哈希值。该方法保证来自同一地址的请求到达同一服务器,除非它不可用。
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
}
如果需要从负载平衡轮换中暂时删除其中一个服务器,则 可以使用 down 参数对其进行标记,以保留客户端 IP 地址的当前哈希。此服务器要处理的请求将自动发送到组中的下一台服务器:
upstream backend {
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
}
通用哈希(Generic Hash) – 向其发送请求的服务器由用户定义的键确定,该键可以是文本字符串、变量或组合。例如,密钥可以是配对的源 IP 地址和端口,也可以是 URI,如以下示例所示:
upstream backend {
hash $request_uri consistent;
server backend1.example.com;
server backend2.example.com;
}
hash指令的可选一致性(consistent)参数启用 ketama 一致哈希负载平衡。请求根据用户定义的哈希键值均匀分布在所有upstream服务器上。如果将upstream服务器添加到upstream组或从upstream组中删除,则只会重新映射几个键,从而在负载平衡缓存服务器或其他累积状态的应用程序的情况下最大程度地减少缓存未命中。
注意: 配置轮循机制以外的任何方法时,请将相应的指令(
hash、ip_hash、least_conn)放在 upstream 块中的server指令列表上方中
服务器权重
默认情况下,NGINX 使用循环方法根据请求的权重在组中的服务 器之间分发请求。server指令的权重参数设置服务器的 weight;默认值为 1 :
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com;
server 192.0.0.1 backup;
}
在示例中,backend1.example.com 具有权重 5;其他两台服务器具有默认权重 1,但具有 IP 地址 192.0.0.1的服务器被标记为 backup除非其他两台服务器都不可用,否则不会接收请求的服务器。通过这种权重配置,每 6个请求中 5个都会发送到 backend1.example.com 和 1个发到backend2.example.com。
启用会话持久性(Enabling Session Persistence)
会话持久性意味着NGINX 识别用户会话并将给定会话中的所有请求路由到同一upstream服务器。
开源版NGINX的会话持久性,请使用 hash或 ip_hash。
upstream backend {
least_conn;
server backend1.example.com;
server backend2.example.com;
# 添加用于启用会话持久性的指令
ip_hash;
}
与多个工作进程共享数据(Sharing Data with Multiple Worker Processes)
如果 upstream 块不包含 zone 指令,则每个工作进程都会保留自己的服务器组配置副本,并维护自己的一组相关计数器。计数器包括与组中每台服务器的当前连接数以及将请求传递到服务器的失败尝试次数。因此,无法动态修改服务器组配置。
当 zone指令包含在 upstream块中时,upstream 组的配置将保存在所有工作进程之间共享的内存区域中。此方案是动态可配置的,因为工作进程访问组配置的相同副本并使用相同的相关计数器。
该 zone指令对于upstream组的主动运行状况检查(active health checks)和动态重新配置(dynamic reconfiguration)是必需的。但是,upstream组的其他功能也可以从使用此指令中受益。
例如,如果未共享组的配置,则每个工作进程都会维护自己的计数器,用于尝试将请求传递到服务器(由 max_fails 参数设置)的失败尝试。在这种情况下,每个请求只能到达一个工作进程。当选择用于处理请求的工作进程无法将请求传输到服务器时,其他工作进程对此一无所知。虽然某些工作进程可以认为服务器不可用,但其他工作进程仍可能向此服务器发送请求。对于明确认为不可用的服务器,fail_timeout参数设置的时间范围内失败的 max_fails尝试次数必须等 于工作进程数。另一方面,该 zone指令保证了预期的行为。
同样,如果没有该 zone指令,最少连接数(Least Connections)负载平衡方法可能无法按预期工作,至少在低负载下是这样。此方法将请求传递到活动连接数最少的服务器。如果未共享组的配置,则每个工作进程使用自己的连接数计数器,并可能向另一个工作进程刚刚向其发送请求的同一服务器发送请求。但是,您可以增加请求数以减少此影响。在高负载下,请求在工作进程之间均匀分布,并且 Least Connections该方法按预期工作。
设置区域大小
不可能推荐理想的内存区域大小,因为使用模式差异很大。所需的内存量取决于启用的功能(如会话持久性、运行状况检查或 DNS 重新解析(DNS re‑resolving))以及如何识别upstream服务器。
使用 DNS 配置 HTTP 负载平衡
可以使用 DNS 在运行时修改服务器组的配置。
对于 upstream 组中在服务器 server指令中用域名标识的 server,可以监控相应DNS记录中IP地址列表的更改,并自动将更改应用于 upstream 组的负载平衡,而无需重新启动。这可以通过在 http 块中包含解析器(resolver) 指令以及指令的解析(resolve)参数来完成:
http {
resolver 10.0.0.1 valid=300s ipv6=off;
resolver_timeout 10s;
server {
location / {
proxy_pass http://backend;
}
}
upstream backend {
zone backend 32k; //zone 多个工作进程共享数据
least_conn;
# ...
server backend1.example.com resolve;
server backend2.example.com resolve;
}
}
在该示例中,server指令的 resolve参数告诉NGINX定期重新解析 backend1.example.com和 backend2.example.com 域名为IP地址。
resolver指令定义了NGINX向其发送请求的DNS服务器的IP地址(此处为 10.0.0.1)。默认情况下,NGINX以记录中的生存时间 (time‑to‑live TTL) 指定的频率重新解析 DNS 记录,但您可以使用 valid参数覆盖 TTL 值;在示例中,它是 300s秒或 5分钟。
可选参数 ipv6=off表示仅使用 IPv4 地址进行负载平衡,但默认情况下同时支持 IPv4 和 IPv6 地址的解析。
如果域名解析为多个 IP 地址,这些地址将保存到 upstream 配置并进行负载均衡。在我们的示例中,服务器根据最少连接数负载平衡方法进行负载平衡。如果服务器的IP地址列表已更改,NGINX会立即开始在新地址集之间进行负载平衡。