NGINX.COM
Web Server Load Balancing with NGINX Plus

在《使用 NGINX 和 NGINX Plus 实现负载均衡(第 1 部分)》中,我们设置了一个简单的 HTTP 代理来跨多台 Web 服务器对流量进行负载均衡。本文将介绍 NGINX Plus 具备的一些其他功能:通过 keepalives健康检查会话保持重定向内容重写来优化性能。

有关 NGINX 和 NGINX Plus 负载均衡功能的详细信息,请参阅《NGINX Plus 管理指南》。

编者按 — NGINX Plus Release 5 及更高版本还可以对基于 TCP 的应用进行负载均衡。Release 6 通过增添健康检查、动态重新配置、SSL 终止等功能,显著扩展了 TCP 负载均衡。在 NGINX Plus Release 7 及更高版本中,TCP 负载均衡器具备与 HTTP 负载均衡器一样的功能。Release 9 中引入了对 UDP 负载均衡的支持。

您可以在 stream 上下文(而非 http 上下文)中配置 TCP 和 UDP 负载均衡。由于 HTTP 和 TCP/UDP 之间的固有差异,可用指令和参数略有不同;详情请参阅 HTTPTCP/UDP 上游模块文档。

 

快速回顾

回顾一下,这是我们在上一篇文章中创建的配置:

server {
    listen 80;

    location / {
        proxy_pass http://backend;

        # 将“Host”请求头重写为客户端请求中的值
        # 或主服务器名称
        proxy_set_header Host $host;

        # 或者,将值写入配置:
        # proxy_set_header Host www.example.com;
    } 
}

upstream backend {
    zone backend 64k;  # 使用 NGINX Plus 的共享内存
    least_conn;

    server webserver1 weight=1;
    server webserver2 weight=4;
}

本文将介绍一些配置 NGINX 和 NGINX Plus 的简单方法,以提高负载均衡效率。

 

HTTP keepalive

在 NGINX 或 NGINX Plus 与上游服务器之间启用 HTTP keepalive 可提高性能(通过减少延迟),并降低 NGINX 耗尽临时端口的可能性。

HTTP 协议使用底层 TCP 连接来传输 HTTP 请求并接收 HTTP 响应。HTTP keepalive 连接允许重用这些 TCP 连接,从而避免了为每个请求创建和终止连接的开销:

NGINX 是一个全代理,可独立管理客户端连接(前端 keepalive 连接)和服务器连接(上游 keepalive 连接):

NGINX 会维护 keepalive 连接的“缓存”(一组与上游服务器的空闲 keepalive 连接),当需要将请求转发到上游服务器时,它会使用这些缓存中已建立的 keepalive 连接,而非创建新的 TCP 连接。这可减少 NGINX 与上游服务器之间的事务延迟,并降低临时端口的使用率,因此 NGINX 能够处理大量流量并对其进行负载均衡。当流量激增时,这些缓存会被清空,在这种情况下,NGINX 将与上游服务器建立新的 HTTP 连接。

对于其他负载均衡工具,该技术有时称为“多路复用”、“连接池”、“连接复用”或“OneConnect”。

您可通过将 proxy_http_versionproxy_set_headerkeepalive 指令添加到配置中来配置 keepalive 连接缓存:

server {
    listen 80;
    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
     }
}

upstream backend {
    server webserver1;
    server webserver2;

    # 与上游服务器组保持多达 20 个空闲连接
    keepalive 20;
}

 

健康检查

启用健康检查不仅能够提高负载均衡服务的可靠性,降低最终用户出错率,而且还便于执行常见维护操作。

NGINX Plus 的健康检查功能可用于检测上游服务器的故障。NGINX Plus 使用“综合事务”探测每台服务器,并根据您在 health_check 指令中配置的参数(以及添加 match 参数的情况下,关联的 match 配置块)检查响应:

server {
    listen 80;

    location / {
        proxy_pass http://backend;

        health_check interval=2s fails=1 passes=5 uri=/test.php match=statusok;

        # 健康检查继承其他代理设置
        proxy_set_header Host www.foo.com;
    }
}

match statusok {
    # 用于 /test.php 健康检查
    status 200;
    header Content-Type = text/html;
    body ~ "Server[0-9]+ is alive";
}

健康检查从其父 location 块继承一些参数。如果在配置中使用运行时变量,这可能会导致出现问题。例如,以下配置适用于实际 HTTP 流量,因为它从客户端请求中提取 Host 请求头的值。但该配置不适用于健康检查所用的综合事务,因为未对这些事务设置 Host 请求头,这意味着综合事务中没有使用 Host 请求头。

location / {
    proxy_pass http://backend;

    # 该健康检查可能不起作用……
    health_check interval=2s fails=1 passes=5 uri=/test.php match=statusok;

    # 从请求中提取“Host”请求头
    proxy_set_header Host $host;
}

一种好办法是创建一个虚拟 location 块,以静态定义健康检查事务使用的所有参数:

location /internal-health-check1 {
    internal; # 防止外部请求匹配该 location 块

    proxy_pass http://backend;

    health_check interval=2s fails=1 passes=5 uri=/test.php match=statusok;

    # 明确设置请求参数;不使用运行时变量
    proxy_set_header Host www.example.com;
}

更多信息,请参阅《NGINX Plus 管理指南》。

 

会话保持

借助会话保持,可以让无法部署至集群的应用也能实现负载均衡和可靠扩展。存储和复制会话状态的应用可以更高效地运行,帮助提升最终用户性能。

某些应用有时会将状态信息存储到上游服务器,例如当用户将商品放入虚拟购物车或编辑上传的图片时。在这些情况下,您可能希望将来自该用户的所有后续请求都定向到同一服务器。

会话保持指定了请求所须路由到的目标位置,而负载均衡则允许 NGINX 自由选择最佳上游服务器。借助 NGINX Plus 的会话保持功能,这两个进程可以共存:

   如果请求符合会话保持规则
   那么使用目标上游服务器
   否则应用负载均衡算法选择上游服务器

如果会话保持决策因目标服务器不可用而失败,那么 NGINX Plus 会做出负载均衡决策。

最简单的会话保持方法是“sticky cookie”方法,其中 NGINX Plus 在第一个响应中插入一个 cookie,用于标识 sticky 上游服务器:

sticky cookie srv_id expires=1h domain=.example.com path=/;

在另一种“sticky 路由”方法中,NGINX 会根据 JSESSIONID cookie 等请求参数选择上游服务器:

upstream backend {
   server backend1.example.com route=a;
   server backend2.example.com route=b;

    # 选择第一个非空变量;它应包含“a”或“b”
    sticky route $route_cookie $route_uri;
}

更多信息,请参阅《NGINX Plus 管理指南》。

 

重写 HTTP 重定向

如果某些重定向被破坏,则您需要重写 HTTP 重定向,特别是当您从代理被重定向到真正的上游服务器时。

当您代理到上游服务器时,服务器在本地地址上发布应用,但您通过另一个地址(代理的地址)访问应用。这些地址通常解析为域名,如果服务器和代理的域名不同,就会出现问题。

例如,在测试环境中,您可能直接(通过 IP 地址)或按 localhost 对代理进行寻址。但上游服务器可能会监听真实域名(例如 www.nginx.com)。当上游服务器发出重定向消息(使用 3xx 状态码和 Location 请求头,或者使用 Refresh 请求头)时,消息中可能包含服务器的真实域名。

NGINX 会尝试拦截并纠正这种最常见的问题。如果您需要全权控制以执行特定重写,请使用 proxy_redirect 指令,如下所示:

proxy_redirect http://staging.mysite.com/ http://$host/;

 

重写 HTTP 响应

有时,您需要重写 HTTP 响应中的内容。也许,如上例所示,响应中包含指向代理以外其他服务器的绝对链接。

您可以使用 sub_filter 指令来定义要应用的重写:

sub_filter /blog/ /blog-staging/;
sub_filter_once off;

一个很常见的问题是 HTTP 压缩的使用。如果客户端发出信号表示可以接受压缩数据,而服务器随后压缩了响应,那么 NGINX 就无法检查和修改响应。最简单的方法是将 Accept-Encoding 请求头设置为空字符串(””),从而将其从客户端请求中删除:

proxy_set_header Accept-Encoding "";

 

完整示例

下面是一个负载均衡配置模板,它使用了本文提到的所有方法。NGINX Plus 具有的高级功能以橙色字体显示。

[编者按 — 以下配置已更新为使用 NGINX Plus API 对上游组进行实时活动监控和动态配置,取代了最初使用的单独模块。]

server {
    listen 80;

    location / {
        proxy_pass http://backend;

        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Accept-Encoding "";
        proxy_redirect http://staging.example.com/ http://$host/;

        # 将 Host 请求头重写为客户端请求中的值
        proxy_set_header Host $host;

        # 替换对 staging.example.com 的任何内联引用
        sub_filter http://staging.example.com/ /;
        sub_filter_once off;
    }

    location /internal-health-check1 {
        internal; # 防止外部请求匹配该 location 块
        proxy_pass http://backend;
        health_check interval=2s fails=1 passes=5 uri=/test.php match=statusok;
        # 明确设置请求参数;不使用运行时变量
        proxy_set_header Host www.example.com;
    }
 
upstream backend {
    zone backend 64k; # 使用 NGINX Plus 的共享内存
    least_conn;
    keepalive 20;

    # 为该上游组应用会话保持
    sticky cookie srv_id expires=1h domain=.example.com path=/servlet;

    server webserver1 weight=1; 
    server webserver2 weight=4; 
}

match statusok {
    # 用于 /test.php 健康检查
    status 200;
    header Content-Type = text/html;
    body ~ "Server[0-9]+ is alive";
}

server {
    listen 8080;
    root /usr/share/nginx/html;

    location = /api {
        api write=on; # 实时活动监控和
                      # 上游组的动态配置

        allow 127.0.0.1; # 允许从 localhost 访问
        deny all;        # 拒绝其他任何位置访问
    }
}

如欲试用 NGINX Plus 中所有出色的负载均衡功能,请立即下载 30 天免费试用版与我们联系以讨论您的用例

Hero image
免费 O'Reilly 电子书:
《NGINX 完全指南》

更新于 2022 年,一本书了解关于 NGINX 的一切

关于作者

Owen Garrett

产品管理高级总监

Owen is a senior member of the NGINX Product Management team, covering open source and commercial NGINX products. He holds a particular responsibility for microservices and Kubernetes‑centric solutions. He’s constantly amazed by the ingenuity of NGINX users and still learns of new ways to use NGINX with every discussion.

关于 F5 NGINX

F5, Inc. 是备受欢迎的开源软件 NGINX 背后的商业公司。我们为现代应用的开发和交付提供一整套技术。我们的联合解决方案弥合了 NetOps 和 DevOps 之间的横沟,提供从代码到用户的多云应用服务。访问 nginx-cn.net 了解更多相关信息。