08-04-2023, 04:50 PM
本章介绍如何使用 NGINX Plus 和 NGINX Open Source 来代理和负载平衡 TCP 和 UDP 流量。
介绍
负载均衡是指在多个后端服务器之间有效分配网络流量。
在 NGINX Plus版本 5及更高版本中,NGINX Plus 可以代理和负载平衡传输控制协议 (TCP) 流量。TCP 是许多流行应用程序和服务的协议,例如 LDAP、MySQL 和 RTMP。
在 NGINX Plus Release 9及更高版本中,NGINX Plus 可以代理和负载平衡 UDP 流量。UDP(用户数据报协议)是许多流行的非事务性应用程序的协议,例如 DNS、系统日志和 RADIUS。
要对 HTTP 流量进行负载平衡,请参阅HTTP 负载平衡一文。
先决条件
配置反向代理
首先,您需要配置反向代理,以便 NGINX Plus 或 NGINX Open Source 可以将 TCP 连接或 UDP 数据报从客户端转发到上游组或代理服务器。
打开 NGINX 配置文件并执行以下步骤:
配置 TCP 或 UDP 负载平衡
配置负载平衡:
另一种方法是将流量代理到单个服务器而不是上游组。如果您通过主机名识别服务器,并将主机名配置为解析为多个 IP 地址,则 NGINX 会使用该算法对 IP 地址之间的流量进行负载平衡Round Robin。在这种情况下,您必须在指令中指定服务器的端口号proxy_pass,并且不得在 IP 地址或主机名之前指定协议:
配置健康检查
NGINX 可以持续测试您的 TCP 或 UDP 上游服务器,避免出现故障的服务器,并将恢复的服务器正常添加到负载平衡组中。
有关如何配置TCP 运行状况检查的说明,请参阅TCP 运行状况检查。
有关如何配置UDP 运行状况检查的说明,请参阅UDP 运行状况检查。
即时配置
使用 NGINX Plus REST API 可以轻松地动态重新配置上游服务器组。使用此界面,您可以查看上游组中的所有服务器或特定服务器、修改服务器参数以及添加或删除上游服务器。
要启用即时配置:
介绍
负载均衡是指在多个后端服务器之间有效分配网络流量。
在 NGINX Plus版本 5及更高版本中,NGINX Plus 可以代理和负载平衡传输控制协议 (TCP) 流量。TCP 是许多流行应用程序和服务的协议,例如 LDAP、MySQL 和 RTMP。
在 NGINX Plus Release 9及更高版本中,NGINX Plus 可以代理和负载平衡 UDP 流量。UDP(用户数据报协议)是许多流行的非事务性应用程序的协议,例如 DNS、系统日志和 RADIUS。
要对 HTTP 流量进行负载平衡,请参阅HTTP 负载平衡一文。
先决条件
- 最新的 NGINX Plus(无需额外的构建步骤)或使用配置标志构建的最新NGINX 开源代码--with-stream
- 通过 TCP 或 UDP 进行通信的应用程序、数据库或服务
- 上游服务器,每个服务器都运行相同的应用程序、数据库或服务实例
配置反向代理
首先,您需要配置反向代理,以便 NGINX Plus 或 NGINX Open Source 可以将 TCP 连接或 UDP 数据报从客户端转发到上游组或代理服务器。
打开 NGINX 配置文件并执行以下步骤:
- 创建一个顶级stream {}块:
代码:stream {
# ...
}
- server {}在顶级上下文中为每个虚拟服务器定义一个或多个配置块stream {}。
- 在server {}每个服务器的配置块中,包含listen用于定义服务器侦听的IP 地址和/或端口的指令。
对于 UDP 流量,还包括该udp参数。由于 TCP 是上下文的默认协议stream,因此该指令没有tcp参数listen:
代码:stream {
server {
listen 12345;
# ...
}
server {
listen 53 udp;
# ...
}
# ...
}
- 包含proxy_pass用于定义代理服务器或服务器将流量转发到的上游组的指令:
代码:stream {
server {
listen 12345;
#TCP traffic will be forwarded to the "stream_backend" upstream group
proxy_pass stream_backend;
}
server {
listen 12346;
#TCP traffic will be forwarded to the specified server
proxy_pass backend.example.com:12346;
}
server {
listen 53 udp;
#UDP traffic will be forwarded to the "dns_servers" upstream group
proxy_pass dns_servers;
}
# ...
}
- 如果代理服务器有多个网络接口,您可以选择将 NGINX 配置为在连接到上游服务器时使用特定的源 IP 地址。如果 NGINX 后面的代理服务器配置为接受来自特定 IP 网络或 IP 地址范围的连接,这可能很有用。
包括proxy_bind相应网络接口的指令和 IP 地址:
代码:stream {
# ...
server {
listen 127.0.0.1:12345;
proxy_pass backend.example.com:12345;
proxy_bind 127.0.0.1:12345;
}
}
- 或者,您可以调整两个内存缓冲区的大小,NGINX 可以在其中放置来自客户端和上游连接的数据。如果数据量较小,可以减少缓冲区,这样可以节省内存资源。如果数据量较大,可以增加缓冲区大小,以减少socket读写操作的次数。一旦一个连接上收到数据,NGINX 就会读取它并通过另一个连接转发它。缓冲区由proxy_buffer_size指令控制:
代码:stream {
# ...
server {
listen 127.0.0.1:12345;
proxy_pass backend.example.com:12345;
proxy_buffer_size 16k;
}
}
配置 TCP 或 UDP 负载平衡
配置负载平衡:
- 创建一组服务器或上游组,其流量将被负载均衡。upstream {}在顶级上下文中定义一个或多个配置块stream {},并设置上游组的名称,例如stream_backendTCP 服务器和dns_serversUDP 服务器:
确保上游组的名称由指令引用,就像上面proxy_pass为反向代理配置的那样。代码:stream {
upstream stream_backend {
# ...
}
upstream dns_servers {
# ...
}
# ...
}
- 使用上游服务器填充上游组。在该upstream {}块中,为每个上游服务器添加一条server指令,指定其 IP 地址或主机名(可以解析为多个 IP 地址)以及必需的端口号。请注意,您不必为每个服务器定义协议,因为该协议是通过您之前创建的块listen中的指令中包含的参数为整个上游组定义的。server
代码:stream {
upstream stream_backend {
server backend1.example.com:12345;
server backend2.example.com:12345;
server backend3.example.com:12346;
# ...
}
upstream dns_servers {
server 192.168.136.130:53;
server 192.168.136.131:53;
# ...
}
# ...
} - 配置上游组使用的负载均衡方法。您可以指定以下方法之一:
- 循环法 – 默认情况下,NGINX 使用循环法算法来负载平衡流量,将其按顺序定向到配置的上游组中的服务器。因为是默认方法,所以没有round‑robin指令;upstream {}只需在顶级上下文中创建一个配置块stream {}并server按照上一步所述添加指令即可。
- 最少连接– NGINX 选择当前活动连接数较少的服务器。
- 最短时间(仅限 NGINX Plus)- NGINX Plus 选择平均延迟最低且活动连接数最少的服务器。用于计算最低平均延迟的方法取决于指令中包含以下哪些参数least_time:
- connect – 连接到上游服务器的时间
- first_byte– 接收数据第一个字节的时间
- last_byte – 从服务器接收完整响应的时间
代码:upstream stream_backend {
least_time first_byte;
server backend1.example.com:12345;
server backend2.example.com:12345;
server backend3.example.com:12346;
}
- connect – 连接到上游服务器的时间
- 哈希– NGINX 根据用户定义的密钥选择服务器,例如源 IP 地址 ( $remote_addr):
代码:upstream stream_backend {
hash $remote_addr;
server backend1.example.com:12345;
server backend2.example.com:12345;
server backend3.example.com:12346;
}
负载Hash平衡方法还用于配置会话持久性。由于哈希函数基于客户端 IP 地址,因此来自给定客户端的连接始终会传递到同一服务器,除非该服务器出现故障或不可用。指定一个可选consistent参数来应用ketama一致性哈希方法:
代码:hash $remote_addr consistent;
- 随机– 每个连接将被传递到随机选择的服务器。如果two指定了该参数,首先NGINX会根据服务器权重随机选择两台服务器,然后使用指定的方法选择其中一台服务器:
- least_conn– 最少的活动连接数
- least_time=connect(NGINX Plus) – 连接到上游服务器的时间 ( $upstream_connect_time)
- least_time=first_byte(NGINX Plus) – 从服务器接收第一个字节数据的最短平均时间 ( $upstream_first_byte_time)
- least_time=last_byte(NGINX Plus) – 从服务器接收最后一个字节数据的最短平均时间 ( $upstream_session_time)
随机负载平衡方法应用于多个负载平衡器将请求传递到同一组后端的分布式环境。对于负载均衡器具有所有请求的完整视图的环境,请使用其他负载均衡方法,例如循环法、最少连接数和最少时间。代码:upstream stream_backend {
random two least_time=last_byte;
server backend1.example.com:12345;
server backend2.example.com:12345;
server backend3.example.com:12346;
server backend4.example.com:12346;
}
- least_conn– 最少的活动连接数
- 循环法 – 默认情况下,NGINX 使用循环法算法来负载平衡流量,将其按顺序定向到配置的上游组中的服务器。因为是默认方法,所以没有round‑robin指令;upstream {}只需在顶级上下文中创建一个配置块stream {}并server按照上一步所述添加指令即可。
- (可选)为每个上游服务器指定特定于服务器的参数,包括最大连接数、服务器权重等:
代码:upstream stream_backend {
hash $remote_addr consistent;
server backend1.example.com:12345 weight=5;
server backend2.example.com:12345;
server backend3.example.com:12346 max_conns=3;
}
upstream dns_servers {
least_conn;
server 192.168.136.130:53;
server 192.168.136.131:53;
# ...
}
另一种方法是将流量代理到单个服务器而不是上游组。如果您通过主机名识别服务器,并将主机名配置为解析为多个 IP 地址,则 NGINX 会使用该算法对 IP 地址之间的流量进行负载平衡Round Robin。在这种情况下,您必须在指令中指定服务器的端口号proxy_pass,并且不得在 IP 地址或主机名之前指定协议:
代码:
stream {
# ...
server {
listen 12345;
proxy_pass backend.example.com:12345;
}
}
配置健康检查
NGINX 可以持续测试您的 TCP 或 UDP 上游服务器,避免出现故障的服务器,并将恢复的服务器正常添加到负载平衡组中。
有关如何配置TCP 运行状况检查的说明,请参阅TCP 运行状况检查。
有关如何配置UDP 运行状况检查的说明,请参阅UDP 运行状况检查。
即时配置
使用 NGINX Plus REST API 可以轻松地动态重新配置上游服务器组。使用此界面,您可以查看上游组中的所有服务器或特定服务器、修改服务器参数以及添加或删除上游服务器。
要启用即时配置:
- 创建顶级http {}块或确保它存在于您的配置中:
代码:http {
# ...
}
- 创建配置请求的位置,例如api:
代码:http {
server {
location /api {
# ...
}
}
}
- 在此位置指定api指令:
代码:http {
server {
location /api {
api;
# ...
}
}
}
- 默认情况下,NGINX Plus API 提供对数据的只读访问。该write=on参数启用读/写访问,以便可以对上游进行更改:
代码:http {
server {
location /api {
api write=on;
# ...
}
}
}
- allow使用和指令限制对此位置的访问deny:
代码:http {
server {
location /api {
api write=on;
allow 127.0.0.1; # permit access from localhost
deny all; # deny access from everywhere else
}
}
}
- 当 API 在写入模式下启用时,建议限制特定用户对PATCH、POST和方法的访问。这可以通过实现HTTP 基本身份验证DELETE来完成:
代码:http {
server {
location /api {
limit_except GET {
auth_basic "NGINX Plus API";
auth_basic_user_file /path/to/passwd/file;
}
api write=on;
allow 127.0.0.1;
deny all;
}
}
}
- 为上游服务器组创建共享内存区域,以便所有工作进程可以使用相同的配置。为此,在顶级stream {}块中找到目标 upsteam 组,将zone指令添加到上游服务器组并指定区域名称(此处为stream_backend)和内存量(64 KB):
代码:stream {
upstream stream_backend {
zone backend 64k;
# ...
}
}
即时配置示例
代码:stream {
# ...
# Configuration of an upstream server group
upstream appservers {
zone appservers 64k;
server appserv1.example.com:12345 weight=5;
server appserv2.example.com:12345 fail_timeout=5s;
server backup1.example.com:12345 backup;
server backup2.example.com:12345 backup;
}
server {
# Server that proxies connections to the upstream group
proxy_pass appservers;
health_check;
}
}
http {
# ...
server {
# Location for API requests
location /api {
limit_except GET {
auth_basic "NGINX Plus API";
auth_basic_user_file /path/to/passwd/file;
}
api write=on;
allow 127.0.0.1;
deny all;
}
}
}
此处,仅允许从本地主机地址 ( ) 访问该位置127.0.0.1。来自所有其他 IP 地址的访问均被拒绝。
要将配置命令传递给 NGINX,请通过任何方法发送 API 命令,例如使用curl。
例如,要将新服务器添加到服务器组,请发送请求POST:
代码:curl -X POST -d '{ \
"server": "appserv3.example.com:12345", \
"weight": 4 \
}' -s 'http://127.0.0.1/api/6/stream/upstreams/appservers/servers'
要从服务器组中删除服务器,请发送请求DELETE:
代码:curl -X DELETE -s 'http://127.0.0.1/api/6/stream/upstreams/appservers/servers/0'
要修改特定服务器的参数,请发送请求 PATCH:
代码:curl -X PATCH -d '{ "down": true }' -s 'http://127.0.0.1/api/6/http/upstreams/appservers/servers/0'
TCP 和 UDP 负载平衡配置示例
这是使用 NGINX 进行 TCP 和 UDP 负载平衡的配置示例:
代码:stream {
upstream stream_backend {
least_conn;
server backend1.example.com:12345 weight=5;
server backend2.example.com:12345 max_fails=2 fail_timeout=30s;
server backend3.example.com:12345 max_conns=3;
}
upstream dns_servers {
least_conn;
server 192.168.136.130:53;
server 192.168.136.131:53;
server 192.168.136.132:53;
}
server {
listen 12345;
proxy_pass stream_backend;
proxy_timeout 3s;
proxy_connect_timeout 1s;
}
server {
listen 53 udp;
proxy_pass dns_servers;
}
server {
listen 12346;
proxy_pass backend4.example.com:12346;
}
}
在此示例中,所有 TCP 和 UDP 代理相关功能都在块内配置stream,就像 HTTP 请求的设置在http块内配置一样。
有两个命名upstream块,每个块包含三台服务器,这些服务器彼此托管相同的内容。在每个服务器中server,服务器名称后跟强制端口号。连接根据最少连接负载平衡方法在服务器之间分配:连接转到活动连接数最少的服务器。
这三个server块定义了三个虚拟服务器:
- 第一个服务器侦听端口 12345,并将所有 TCP 连接代理到上游服务器的stream_backend组。请注意,模块proxy_pass上下文中定义的指令stream不得包含协议。
指定了两个可选的超时参数:该指令设置与stream_backendproxy_connect_timeout组中的服务器建立连接所需的超时。该指令设置在开始代理到stream_backend组中的服务器之一后使用的超时。proxy_timeout
- 第二个服务器侦听端口 53 并将所有 UDP 数据报(指令udp的参数)代理到名为dns_serverslisten的上游组。如果未指定该参数,则套接字侦听 TCP 连接。udp
- 第三个虚拟服务器侦听端口 12346 并代理到backend4.example.com的 TCP 连接,该连接可以解析为通过循环方法进行负载平衡的多个 IP 地址。
- 第一个服务器侦听端口 12345,并将所有 TCP 连接代理到上游服务器的stream_backend组。请注意,模块proxy_pass上下文中定义的指令stream不得包含协议。