Nginx TCP和UDP负载均衡

摘要:摘要: Nginx TCP UDP 负载均衡

1 介绍

负载均衡是指有效的通过多个后端服务器分发网络流量。

Nginx能代理和负载均衡TCP、UDP通信。TCP(传输控制协议)、UDP(用户数据包协议)是许多流行应用程序和服务的协议,例如LDAP、MySQL和RTMP使用TCP协议,DNS、syslog和RADIUS。

1 (82).jpg

2 需要

使用--with-stream配置标记构建最新Nginx,或最新的Nginx+(不需要额外构建步骤)

应用程序、数据库或服务基于TCP或UDP通信

Upstream服务器运行相同的应用程序、数据库或服务实例

3 配置反向代理

首先,你需要配置反向代理,因此,Nginx转发来自客户端的TCP连接或UDP数据包到upstream组或一个代理服务器。

打开Nginx配置文件并执行以下步骤:

创建顶级stream {}块

stream {

...

}

在顶级stream {}上下文中为每个虚拟主机定义一个或多个server {}配置块。

在每个server {}配置块中包括listen指令定义服务器监听的IP地址和/或端口。对于UDP通信,也包括udp参数。TCP是stream上下文的默认协议:

stream {

server {

listen 12345;

...

}

server {

listen 53 udp;

...

}

...

}

包括proxy_pass指令定义代理服务器或upstream组

stream {

server {

listen 12345;

proxy_pass stream_backend;

}

 

server {

listen 12346;

proxy_pass backend.example.com:12346;

}

 

server {

listen 53 udp;

proxy_pass dns_servers;

}

...

}

可选,如果你的代理服务器多个网络接口,你能配置Nginx选择源IP地址连接到upstream服务器。代理服务器在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;

}

}

4 配置TCP和UDP负载均衡

为了配置负载均衡:

1、创建服务器组,或upstream组将负载均衡通信。定义一个或多个upstream {}配置块在顶级steam {}上下文,设置upstream组的名字,例如,TCP服务器steam_backed和UDP服务器dns_servers:

stream {

upstream stream_backend {

...

}

 

upstream dns_servers {

...

}

...

}

2、在upstream组中填充upstream服务器。upstream {}块中,为每个upstream服务器添加server指令,指定IP地址或主机名(解析多个IP地址)和必须的端口号。

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;

...

}

...

}

3、配置负载均衡方法

round-robin(轮询)——默认,Nginx使用轮询算法负载均衡通信。因为是默认方法,所以没有round-robin指令;只创建upstream配置块在顶级stream上下文并像之前步骤添加server指令。

last_conn(最少连接)——Nginx选择当前活跃连接数较少的服务器。

least_tome——Nginx选择最低平均延迟和最少活跃连接的服务器。最低活跃连接基于least_time指令的以下参数计算:

connect——连接upstream服务器的时间

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;

}

hash——Nginx基于用户定义键选择服务器,例如,源IP地址

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;

4、可选,指定最大连接数、服务器权重等

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地址使用轮询算法负载均衡。在这种情况下,你必须在proxy_pass指令中指定服务器的端口号,不必指定协议:

stream {

...

server {

listen 12345;

proxy_pass backend.example.com:12345;

}

}

5 被动健康检查

如果试图连接upstream服务器超时或出错,Nginx标记服务器为不可用并在指定时间内停止发送请求给该服务器。为了定义不可用条件,包括以下参数到server指令:

fail_timeout——同Nginx负载均衡章节

max_fails——同Nginx负载均衡章节

fail_timeout默认为10秒,max_fails默认为1次。因此,如果连接10秒内尝试至少一次失败,Nginx标记服务器10秒内不可用。

upstream stream_backend {

server backend1.example.com:12345 weight=5;

server backend2.example.com:12345 max_fails=2 fail_timeout=30s;

server backend3.example.com:12346 max_conns=3;

}

6 主动健康检查

健康检查能配置测试广范围的错误类型。例如,Nginx能不断测试upstream服务器的响应能力并避免服务器故障。

6.1 工作原理

Nginx发送特定健康检查请求到每个upstream服务器并检查响应满足某一条件。如果不能连接到服务器,那么健康检查失败,服务器不健康。Nginx不代理客户端连接到不健康的服务器。如果多个健康检查定义在服务器组中,相应服务器的任意一个检查不通过该服务器都是不健康的。

6.2 预备条件

你在stream上下文中配置upstream服务器组

stream {

upstream stream_backend {

 

server backend1.example.com:12345;

server backend2.example.com:12345;

server backend3.example.com:12345;

}

}

你配置一台服务器传递通信(在这种情况下,是TCP连接)到服务器组

server {

listen 12345;

proxy_pass stream_backend;

}

6.3 基础配置

指定共享内存区域

stream {

upstream stream_backend {

 

zone stream_backend 64k;

server backend1.example.com:12345;

server backend2.example.com:12345;

server backend3.example.com:12345;

}

}

启用健康检查

server {

listen 12345;

proxy_pass stream_backend;

health_check;

health_check_timeout5s;

}

health_check指令启用健康检查功能,health_check_timeout覆盖健康检查的proxy_timeout。

为了启用健康检查UDP通信,为health_check指令指定udp参数:

server {

listen 5053;

proxy_pass dns_servers;

health_check udp;

health_check_timeout 5s;

}

6.4 健康检查调优

默认,Nginx尝试每5秒连接upstream服务器组中的每台服务器。如果不能建立连接,Nginx认为健康检查失败,标记为不健康,停止转发客户端连接到服务器。

为了改变默认行为,包括参数到health_check指令:

interval——Nginx多久发送一次健康检查请求(默认5秒)

passes——服务器连续多少次响应健康检查认为是健康(默认是1次)

fails——服务器连续多少次健康检查失败认为是不健康(默认是1次)

server {

listen 12345;

proxy_pass stream_backend;

health_check interval=10 passes=2 fails=3;

}

在例子中,TCP健康检查时间间隔增加到10秒,服务器认为连续3次健康检查失败是不健康,服务器需要连续2次通过健康检查才再次认为是健康的。

默认,Nginx发送健康检查消息给upstream块中的server指令的特定端口。你能指定其它的健康检查端口,当许多服务在相同主机检查健康时非常有用。为了覆盖端口,指定health_check指令的port参数:

server {

listen 12345;

proxy_pass stream_backend;

health_check port=8080;

}

6.5 使用match配置块调优健康检查

你能通过配置大量健康检查测试验证服务响应。这些测试放置在stream{}上下文中的match {}配置块。指定match {}块并设置它的名字,例如,tcp_test:

stream {

...

match tcp_test {

...

}

}

然后在health_check指令包括match参数和match块相同名称引用块:

stream {

server {

listen 12345;

health_check match=tcp_test;

proxy_pass stream_backend;

}

}

健康检查的条件或测试使用send和expect参数设置:

send——发送给服务器文本字符串或十六进制字符(“/x”后面跟两个十六进制数字) expect——服务器返回的数据匹配的字符串货正则表达式

这些参数能用于不同的组合,但不能同时制定超过一个send和一个expect参数。参数配置也依赖于使用(TCP或UDP)的协议。

6.5.1 调优TCP健康检查

为了调优TCP健康检查,你能组合send和expect参数:

如果没有send或expect参数指定,测试连接服务器能力。

如果expect参数被指定,服务器期望无条件发送数据:

match pop3 {

expect ~* "+OK";

}

如果send参数指定,它期望连接将成功建立并指定字符串发送给服务器:

match pop_quit {

send QUIT;

}

如果send和expect参数被指定

stream {

upstream stream_backend {

zone upstream_backend 64k;

server backend1.example.com:12345;

}

 

match http {

send "GET / HTTP/1.0rnHost: localhostrnrn";

expect ~* "200 OK";

}

 

server {

listen 12345;

health_check match=http;

proxy_pass stream_backend;

}

}

例子显示为了健康检查传入,HTTP请求必须发送到服务器,并期望服务器结果包含”200 OK”表示HTTP响应成功。

6.5.2 UDP健康检查调优

为了调优UDP健康检查,你应该指定send和expect参数:

NTP例子

match ntp {

send xe3x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00;

expect ~* x24;

}

DNS例子

match dns {

send x00x2ax00x00x00x01x00x00x00x00x00x00x03x73x74x6cx04x75x6dx73x6cx03x65x64x75x00x00x01x00x01;

expect ~* "health.is.good";

}

7 动态配置

Upstream服务器组能容易使用简单的HTTP接口重新动态配置。使用该接口,你能浏览所有服务器在upstream组或特定服务器,修改服务器参数,并添加或删除upstream服务器。

为了启用动态配置:

创建顶级http {}块或确保在你的配置文件中存在

http {

...

}

创建配置请求的location,例如,upstream_conf。

http {

 

server {

location /upstream_conf {

...

}

}

}

在该location中指定upstream_conf指令——一个能用于解释和重新配置upstream组的处理器

http {

 

server {

location /upstream_conf {

upstream_conf;

...

}

}

}

限制该location的访问

 

http {

 

server {

location /upstream_conf {

upstream_conf;

allow 127.0.0.1;

deny all;

}

}

}

创建共享内存区域

stream {

upstream stream_backend {

zone backend 64k;

...

}

}

7.1 动态配置例子

stream {

...

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 {

proxy_pass appservers;

health_check;

}

}

 

http {

...

server {

location /upstream_conf {

upstream_conf;

allow 127.0.0.1;

deny all;

}

}

}

浏览所有备机

http://127.0.0.1/upstream_conf?stream=&upstream=appservers&backup=

添加新服务器到服务器组

http://127.0.0.1/upstream_conf?stream=&add=&upstream=appservers&server=appserv3.example.com:12345&weight=2&max_fails=3

从服务器组删除服务器

http://127.0.0.1/upstream_conf?stream=&remove=&upstream=appservers&id=2

修改指定服务器

http://127.0.0.1/upstream_conf?stream=&upstream=appservers&id=2&down=

8 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:12346 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 backend;

proxy_timeout 3s;

proxy_connect_timeout 1s;

}

 

server {

listen 53 udp;

proxy_pass dns_servers;

}

 

server {

listen 12346;

proxy_pass backend.example.com:12346;

}

}