不忘初心,砥砺前行
作者 | 陌无崖
转载请联系授权
最近用到了nginx的负载均衡的UDP转发,下面的文章是对官方博客的一个翻译,实际应用中也主要参考了该文章;
介绍
负载平衡是指在多个后端服务器之间有效地分配网络流量。
在NGINX Plus版本5和更高版本中,NGINX Plus可以代理和负载平衡传输控制协议(TCP)通信。TCP是许多流行的应用程序和服务的协议,例如LDAP,MySQL和RTMP。
在NGINX Plus版本9和更高版本中,NGINX Plus可以代理和负载均衡UDP流量。UDP(用户数据报协议)是许多流行的非事务性应用程序的协议,例如DNS,syslog和RADIUS。
如果要负载均衡HTTP流量,请参阅HTTP负载均衡[1]文章。
前提
•最新的NGINX Plus(无需额外的构建步骤)或最新的NGINX Open Source使用--with-stream配置标记构建;•通过TCP或UDP进行通信的应用程序、数据库或服务;•上游服务器,每个服务器运行应用程序,数据库或服务的相同实例;
配置反向代理
首先,需要配置反向代理,以便NGINX Plus或NGINX开源可以将TCP连接或UDP数据报从客户端转发到上游组或代理服务器。
打开NGINX配置文件并执行以下步骤:
1.
创建一个stream
stream {
# ...
}
2.
在stream流上下文中为每个虚拟服务器定义一个或者多个服务器配置块;
3.
在每个服务器server{}中配置listen指令定义服务器监听的IP地址/或端口,对于UDP通信,还包括udp参数。由于tcp是流上下文的默认协议,因此可以省略;
stream {
server {
listen 12345;
# ...
}
server {
listen 53 udp;
# ...
}
# ...
}
4.包括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;
}
# ...
}
5.如果代理服务器具有多个网络接口,则可以选择将NGINX配置为在连接到上游服务器时使用特定的源IP地址。即代理服务器配置为接受来自特定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;
}
}
6.也可以配置内存缓冲区的大小,nginx可以在其中放置来自客户端和上游连接的数据。如果数据量很小,则可以减少缓冲区,用来节省内存资源。如果有大量数据,则可以增加缓冲区的大小写以减少套接字读写操作的数量。如果在一个连接上接收数据,nginx将读取该数据并将其通过另一连接进行转发,缓冲区由proxy_buffer_size指令控制:
stream {
# ...
server {
listen 127.0.0.1:12345;
proxy_pass backend.example.com:12345;
proxy_buffer_size 16k;
}
}
配置TCP或者UDP负载均衡
1.
创建一组服务器,或者一个上游组将其流量实现为负载均衡,在stream{}上下文中定义一个或者多个上游{}配置块,并未上游组设置名称,如对于TCP服务器为stream_backend,对于UDP服务器为dns_servers;
stream {
upstream stream_backend {
# ...
}
upstream dns_servers {
# ...
}
# ...
}
确保上游组的名称由proxy_pass指令引用,就像上面为反向代理配置的那样。
2.
使用上游服务器填充upstream组,在upstream{}块内,为每个upstream服务器添加一个服务器指令,指定服务器指令,指定其IP地址或者主机名(可以解析为多个IP地址)和一个必须的端口号。在这里并没有指定每个服务器的协议,协议的指定在先前创建的服务器块中listen指令中包含的参数为整个upstream组定义的。
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.
配置upstream组所使用的负载均衡方法,可以选择以下方法之一:
1.轮询——默认情况,nginx使用轮询算法对流量进行负载均衡,将其顺序引导至已经配置好的upstream组中的服务器,因为是默认的方法,所以没有循环指令。只需要在top-level层stream{}上下文中创建一个upstream{}配置块,并按照上一步中的说明添加指令;2.Least Connections[2]最少连接——nginx选择当前活动连接数量较少的服务器。3.**Least Time[3] **最少时间(仅仅适用于nginx plus)-nginx plus选择具有最低平均延迟和最少活动连接数的服务器。用于计算最低平均等待时间的方法取决于minimum_time指令中包含以下参数:
1.connect
– 连接upstream{}所需要的时间;2.first_byte
– 接收数据的第一个字节的时间;3.last_byte
– 从服务器接收完整响应的时间;
upstream stream_backend {
least_time first_byte;
server backend1.example.com:12345;
server backend2.example.com:12345;
server backend3.example.com:12346;
}
d. 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;
}
哈希负载平衡方法还用于配置会话持久性。由于哈希函数基于客户端IP地址,因此除非服务器关闭或不可用,否则来自给定客户端的连接将始终传递到同一服务器。指定一个可选的consistent参数以应用
ketama[4]一致性哈希方法:
hash $remote_addr consistent;
e. Random[5] 每个连接都将传递到随机选择的服务器。如果指定了两个参数,首先,NGINX考虑服务器权重随机选择两个服务器,然后使用指定的方法选择这些服务器之一:
•least_conn
– 最少活动连接数;•least_time=connect
(NGINX Plus) – 连接到upstream server 的时间($upstream_connect_time
[6])•least_time=first_byte
(NGINX Plus) – 从服务器接收数据的第一个字节的最短平均时间 ($upstream_first_byte_time
[7])•least_time=last_byte
(NGINX Plus) – 从服务器接收最后一个字节的最小平均时间 ($upstream_session_time
[8])
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;
}
随机负载均衡方法应用于多个负载均衡器将请求传递到同一组后端的分布式环境。对于负载平衡器具有所有请求的完整视图的环境,请使用其他负载平衡方法,例如轮询,最少连接和最少时间。
1.(可选)为每个上游服务器指定服务器特定的参数,包括最大连接数,服务器权重[9]等:
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使用Round Robin算法在IP地址之间负载流量平衡。在这种情况下,您必须在proxy_pass指令中指定服务器的端口号,并且不得在IP地址或主机名之前指定协议:
stream {
# ...
server {
listen 12345;
proxy_pass backend.example.com:12345;
}
}
配置健康检查
NGINX可以不断测试您的TCP或UDP上游服务器,避免出现故障的服务器,并将恢复的服务器正常地添加到负载平衡组中。
有关如何配置TCP的运行状况[10]检查的说明,请参阅TCP运行状况检查。
有关如何配置UDP配置运行状况[11]检查的说明,请参阅UDP运行状况检查。
动态配置
使用NGINX Plus REST API可以轻松地即时重新配置upstream服务器组。使用此界面,您可以查看upstream组中的所有服务器或特定服务器,修改服务器参数以及添加或删除上游服务器。
1.
创建http{}块
http {
# ...
}
2.
创建用于配置请求的位置
http {
server {
location /api {
# ...
}
}
}
3.
在此位置指定api指令
http {
server {
location /api {
api;
# ...
}
}
}
4.默认情况下,NGINX Plus API提供对数据的只读访问权限。write = on参数启用读/写访问,以便可以对上游进行更改:
http {
server {
location /api {
api write=on;
# ...
}
}
}
5.使用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
}
}
}
6.在写入模式下启用API时,建议限制特定用户对PATCH,POST和DELETE方法的访问。这可以通过实现HTTP基本身份验证来完成
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;
}
}
}
7.为upstream服务器组创建一个共享内存区域,以便所有工作进程都可以使用相同的配置。为此,请在stream{}块中找到目标upsteam组,将zone指令添加到upstream{}服务器组中并指定区域名称(此处为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,请通过任何方法(例如,使用curl)发送API命令。
例如,要将新服务器添加到服务器组,请发送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负载平衡配置示例
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代理相关的功能都在流模块中配置,就像HTTP请求的设置在http模块中配置一样;
有两个命名的upstream{}模块,每个模块分别包含了3个服务器;
三个服务器定义了三个虚拟服务器
•第一个server监听端口12345并代理到上游服务器的流后端组的所有TCP连接。
•指定了两个可选的超时参数,proxy_connect_timeout指令设置与stream_backend组中的服务器建立连接所需的超时。proxy_timeout指令设置在代理到stream_backend组中的一台服务器已启动之后使用的超时。
•第二个server监听端口53,并将所有的UDP数据包代理到dns_server中;•第三个server监听端口123456并代理到backend4.example. com的tcp连接
References
[1]
HTTP负载均衡: https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/[2]
Least Connections: https://nginx.org/en/docs/stream/ngx_stream_upstream_module.html?&_ga=2.41585058.1629549096.1596096318-711001157.1596096318#least_conn[3]
Least Time: https://nginx.org/en/docs/stream/ngx_stream_upstream_module.html?&_ga=2.143887797.1629549096.1596096318-711001157.1596096318#least_time[4]
ketama: https://www.last.fm/user/RJ/journal/2007/04/10/rz_libketama_-_a_consistent_hashing_algo_for_memcache_clients[5]
Random: https://nginx.org/en/docs/stream/ngx_stream_upstream_module.html#random[6]
$upstream_connect_time
: https://nginx.org/en/docs/stream/ngx_stream_upstream_module.html#var_upstream_connect_time[7]
$upstream_first_byte_time
: https://nginx.org/en/docs/stream/ngx_stream_upstream_module.html#var_upstream_first_byte_time[8]
$upstream_session_time
: https://nginx.org/en/docs/stream/ngx_stream_upstream_module.html#var_upstream_session_time[9]
最大连接数,服务器权重: https://nginx.org/en/docs/stream/ngx_stream_upstream_module.html?&_ga=2.213503892.1629549096.1596096318-711001157.1596096318#max_conns[10]
TCP的运行状况: https://docs.nginx.com/nginx/admin-guide/load-balancer/tcp-health-check/[11]
UDP配置运行状况: https://docs.nginx.com/nginx/admin-guide/load-balancer/udp-health-check/
▼关注我,一起成长
主要分享 学习心得、笔记、随笔▼