NGINX Full Version

使用 NGINX 和 NGINX Plus 实现负载均衡(第 2 部分)

在《使用 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 天免费试用版与我们联系以讨论您的用例