Skip to main content

4.TCP和UDP负载均衡

本章介绍如何使用 NGINX 来代理和负载平衡 TCP 和 UDP 流量。

介绍

负载均衡(Load balancing)是指在多个后端服务器之间有效地分配网络流量。若要对 HTTP 流量进行负载均衡,请参阅 HTTP 负载均衡一文。

先决条件

  • 使用配置标志(configuration flag) --with-stream构建的最新NGINX
  • 通过 TCP 或 UDP 进行通信的应用程序、数据库或服务
  • upstream服务器,每个服务器运行应用程序、数据库或服务的相同实例

配置反向代理(Configuring Reverse Proxy)

首先,您需要配置 反向代理(reverse proxy) ,NGINX 可以将TCP连接或UDP数据报从客户端转发到 upstream 组或 proxied(代理)服务器。步骤如下:

创建顶级 stream {} 块:

stream {
# ...
}

为顶级 stream {}上下文中的每个虚拟服务器定义一个或多个 server {} 配置块。

在每个服务器的配置 server {}块中,包括侦听指令以定义服务器 listenIP 地址和(或) 端口 。对于 UDP 流量,还包括 udp 参数。由于 TCP 是 stream上下文的默认协议,因此 tcp该指令没有 listen参数:

stream {

server {
listen 12345;
# ...
}

server {
listen 53 udp;
# ...
}
# ...
}

通过 proxy_pass 指令以定义代理服务器或服务器将流量转发到的 upstream 组:

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 配置为在连接到 uptream 服务器时使用特定的源 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 可以在其中放置来自客户端和 upstream 连接的数据。如果数据量较小,则可以减少缓冲区,从而节省内存资源。如果存在大量数据,则可以增加缓冲区大小以减少套接字读/写操作的数量。一旦在一个连接上收到数据,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组 。在顶级upstream 上下文中定义一个或多个 upstream {} 配置块,并为 upstream组设置名称,例如,TCP 服务器 stream_backend和 UDP 服务器 dns_servers

stream {

upstream stream_backend {
# ...
}

upstream dns_servers {
# ...
}
# ...
}

确保upstream组的名称由 proxy_pass 指令引用,就像上面为反向代理配置的那些指令一样。

使用upstream 服务器填充upstream组 。在 upstream {} 块中,为每个upstream服务器添加一个 server指令,指定其 IP 地址或主机名(可以解析为多个 IP 地址)和必需的端口号。请注意,您没有为每个服务器定义协议,因为该协议是由您之前创建的 server块中的 listen指令中包含的参数为整个upstream组定义的。

stream {   #upstream服务器

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;
# ...
}

# ...
}

配置upstream组使用的负载平衡方法。您可以指定以下方法之一:

  • 轮循机制(Round Robin) – 默认情况下,NGINX 使用轮询算法对流量进行负载均衡,将其按顺序定向到配置的upstream组中的服务器。因为它是默认方法,所以 round‑robin没有指令;只需在顶级 upstream {}上下文中创建配置 stream {}块并添加 server指令,如上一步所述。
  • 最少连接(Least Connections) – NGINX选择当前活动连接数较少的服务器。
  • 哈希(Hash) – 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;

随机(Random) – 每个连接都将传递到随机选择的服务器。如果指定了 two参数,NGINX首先在考虑服务器权重的情况下随机选择两台服务器,然后使用指定的方法选择其中一台服务器:

  • least_conn– 最少的活动连接数
  • least_time=connect(NGINX Plus) – 连接到upstream服务器的时间 ($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;
}

随机负载均衡方法应用于多个负载均衡器将请求传递到同一组后端的分布式环境。对于负载均衡器具有所有请求的完整视图(a full view)的环境,请使用其他负载平衡方法,例如轮循机制、最少连接数和最短时间。

(可选)为每个upstream服务器指定特定于服务器的参数,包括最大连接数服务器权重等:

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;
# ...
}

另一种方法是将流量代理到单个服务器而不是upstream组。如果按主机名标识服务器,并将主机名配置为解析为多个 IP 地址,则 NGINX 使用 Round Robin该算法在 IP 地址之间对流量进行负载平衡。在这种情况下,必须在 proxy_pass指令中指定服务器的端口号,并且不得在 IP 地址或主机名之前指定协议:

stream {
# ...
server {
listen 12345;
proxy_pass backend.example.com:12345;
}
}