Http Load Balancing

0 阅读8分钟

Overview

几个机器之间的负载均衡通常被用于优化资源利用,最大化吞吐率,降低延迟,确保容错性

将 HTTP 流量代理到一组服务器

要开始使用 NGINX Plus 或 NGINX 开源版将 HTTP 流量负载均衡到一组服务器上,首先需要使用 upstream 指令定义该组服务器。此指令应放置在 http 上下文(context)中。

服务器组中的服务器使用 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_passmemcached_passscgi_passuwsgi_pass 指令,针对这些协议)中指定组名。在下一个示例中,运行在 NGINX 上的虚拟服务器将所有请求传递给之前定义的 backend upstream组:

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

以下示例结合了上述两个片段,展示了如何将 HTTP 请求代理到后端服务器组。该组由三台服务器组成,其中两台运行相同应用程序的实例,而第三台作为备份服务器。由于upstream block中未指定负载均衡算法,因此 NGINX 使用默认算法“轮询”:

http {
    upstream backend {
        server backend1.example.com;
        server backend2.example.com;
        server 192.0.0.1 backup;
    }

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

Choosing a Load-Balancing Method

NGINX 开源版支持四种负载均衡方法,而 NGINX Plus 添加了两种额外的方法:

1、轮询(Round Robin)

请求均匀分布在服务器之间(可以使用server wrights配置服务器的权重)。这是默认使用的算法(无需启用指令):

upstream backend {
   # no load balancing method is specified for Round Robin
   server backend1.example.com;
   server backend2.example.com;
}

2、 最少连接数(Least Connections)

请求发送到活动连接数最少的服务器,同时考虑服务器权重:

upstream backend {
    least_conn;
    server backend1.example.com;
    server backend2.example.com;
}

3、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;
}

4、泛型哈希(Generic Hash)

根据用户定义的键确定请求发送到的服务器,该键可以是文本字符串、变量或其组合。例如,键可以是源 IP 地址和端口的组合,或者是一个 URI,如下所示:

upstream backend {
    hash $request_uri consistent;
    server backend1.example.com;
    server backend2.example.com;
}

hash 指令的可选参数 consistent 启用了 ketama 一致性哈希负载均衡。请求基于用户定义的哈希键值均匀分布到所有上游服务器。当上游组中添加或移除服务器时,只有少数键会被重新映射,这在负载均衡缓存服务器或其他累积状态的应用程序时最小化了缓存未命中的数量。

5、Random

每个请求将被传递给随机选择的服务器。如果指定了 two 参数,NGINX 首先随机选择两个服务器,考虑服务器权重,然后根据指定的方法选择其中一个服务器:

  • least_conn:活动连接数最少
  • least_time=header(仅限 NGINX Plus):接收响应头的平均时间最短
  • least_time=last_byte(仅限 NGINX Plus):接收完整响应的平均时间最短
upstream backend {
    random two least_time=last_byte;
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com;
    server backend4.example.com;
}

随机负载均衡方法适用于多个负载均衡器将请求传递到同一组后端服务器的分布式环境。对于负载均衡器能够全面查看所有请求的环境,建议使用其他负载均衡方法,如轮询、最少连接数和最小时间。

Note:  当配置任何非轮询的方法时,请将相应的指令(如 haship_hashleast_connleast_timerandom)放在上游块 {} 内的服务器指令列表上方

Server Weight

默认情况下,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 的服务器被标记为备份服务器,只有在其他两台服务器都不可用时才会接收请求。根据这种权重配置,每 6 个请求中有 5 个会被发送到 backend1.example.com,1 个会被发送到 backend2.example.com

Server Slow-Start

服务器慢启动功能防止最近恢复的服务器因连接过多而过载,这可能导致连接超时并使服务器再次被标记为故障。

在 NGINX Plus 中,慢启动允许上游服务器在其恢复或变得可用后逐渐将其权重从 0 恢复到声明的权重值。这可以通过 server 指令的 slow_start 参数来实现:

upstream backend {
    server backend1.example.com slow_start=30s;
    server backend2.example.com;
    server 192.0.0.1 backup;
}

时间值(此处为 30 秒)设置 NGINX Plus 将连接数增加到服务器的最大值所需的时间。

请注意,如果组中只有一台服务器,则 max_failsfail_timeoutslow_start 参数将被忽略,服务器永远不会被认为是不可用的。

配置健康检查(Configuring Health Checks)

NGINX 可以持续测试您的 HTTP upstream servers,避免使用已失败的服务器,并优雅地将恢复的服务器重新加入到负载均衡组中。

有关如何为 HTTP 配置健康检查的详细说明,请参阅 [HTTP 健康检查]

与多个worker process共享数据(Sharing Data with Multiple Worker Processes)

如果upstream block中没有包含 zone 指令,每个工作进程都会保留自己的服务器组配置的副本,并维护自己的一组相关计数器(counter)。这些计数器(counter)包括组(grooup)中每个服务器的当前连接数以及尝试将请求传递给服务器的失败次数。因此,服务器组配置不能动态修改。

当upstream block中包含 zone 指令时,当upstream block的配置被保存在一个所有工作进程(worker process)共享的内存区域中。这种情况下是动态可配置的,因为工作进程访问同一个组配置副本并使用相同的相关计数器(counter)。

zone 指令对于主动健康检查和upstream group的动态重新配置是必需的。然而,上游组的其他功能也可以从使用该指令中受益。

例如,如果组配置没有共享,每个工作进程都会维护自己的计数器,记录尝试将请求传递给服务器的失败次数(由 max_fails 参数设置)。在这种情况下,每个请求只会到达一个工作进程。当选定的工作进程无法将请求传输到服务器时,其他工作进程对此一无所知。虽然某些工作进程可能认为服务器不可用,但其他工作进程仍可能继续向该服务器发送请求。要使服务器被明确认为不可用,必须在 fail_timeout 参数设置的时间段内,失败次数等于 max_fails 乘以工作进程的数量。另一方面,zone 指令保证了预期的行为。

类似地,如果没有 zone 指令,最少连接数(Least Connections)负载均衡方法在低负载下可能无法按预期工作。此方法将请求传递给活动连接数最少的服务器。如果组配置没有共享,每个工作进程都会使用自己的连接数计数器,可能会将请求发送到另一个工作进程刚刚发送请求的同一服务器。然而,可以通过增加请求数来减少这种影响。在高负载下,请求均匀分布到各个工作进程中,最少连接数方法按预期工作。

设置区域大小(Setting the Zone Size)

由于使用模式差异很大,无法推荐理想的内存区域大小。所需的内存量取决于启用了哪些功能(如会话持久性、健康检查或 DNS 重新解析)以及如何标识上游服务器。

例如,使用 sticky_route 会话持久性方法并启用单个健康检查时,256 KB 的区域可以容纳以下数量的上游服务器信息:

  • 128 台服务器(每台定义为 IP 地址:端口对)
  • 88 台服务器(每台定义为主机名:端口对,主机名解析为单个 IP 地址)
  • 12 台服务器(每台定义为主机名:端口对,主机名解析为多个 IP 地址)