学习笔记—通过nginx对UDP做负载均衡

  在某些场合下,大量的请求对于单个实例来说是很难承受的,有可能会导致服务器宕机。

  因此,所谓负载均衡,就是要把大量的请求按照指定的方式均衡分配给集群中的每台服务器,从而避免这种情况。

  做负载的方式有许多,此处针对UDP,通过nginx做负载均衡。

  实现负载均衡前,首先需要实现反向代理,也就是说,请求到某个宇明的时候,该请求默认是被nginx接收到的,然后nginx根据配置,做解析,把特定的请求转发到对应的服务器上去。如下述代码为nginx.conf的一部分。

[title] [lang:language] [url] [link text] [additional options]
1
2
3
4
5
6
7
8
9
10
11
12
13
stream {
upstream udp_servers {
server 192.168.186.1:8081; # 第一个UDP程序实例的地址和端口
server 192.168.186.1:8082; # 第二个UDP程序实例的地址和端口
server 192.168.186.1:8083; # 第三个UDP程序实例的地址和端口
}

server {
listen 8080 udp;
proxy_pass udp_servers;
proxy_responses 1;
}
}

  这段代码是用于nginx服务器配置的,定义了一个UDP流量的负载均衡设置。

  stream{}这一行表示开始定义了一个流模块的配置块,nginx的流模块可以用于处理TCP和UDP流量。

  upstream udp_servers {}:这一行定义了一个名为udp_servers的上游服务器组。这个组将包含多个UDP服务器实例,用于处理负载均衡。其中包含的就是可以负载过去的实例对象。

  server 192.168.186.1:8081;:这是定义在udp_servers组中的第一个服务器实例,其IP地址为192.168.186.1,端口为8081。这表示UDP流量可以被发送到这个地址和端口。

  另外两个同理。

  server {}:这一行开始定义一个服务器配置块,它将监听特定的端口,并将流量代理到上游服务器。

  listen 8080 udp;:这一行指定Nginx服务器将监听UDP协议的8080端口。任何到达这个端口的UDP数据包都将被Nginx处理。

  proxy_pass udp_servers;:这一行指定了将流量代理到之前定义的udp_servers上游服务器组。这意味着Nginx将根据负载均衡算法将UDP数据包发送到组中的服务器。

  proxy_responses 1;:这一行配置了代理响应的数量。在这里,它被设置为1,意味着Nginx在接收到来自上游服务器的第一个响应后,就会停止处理并返回给客户端。这在某些UDP协议中很有用,比如DNS查询。

  这样,监听8080端口的UDP流量,就会被分发到三个不同的UDP服务器实例上。

  HTTP与TCP是类似的。

  如下为一个包含8080端口的UDP、8081端口的UDP和8080端口的HTTP负载均衡的nginx.conf的示例,在这个配置中,UDP和HTTP(包块还有websocket)流量都配置在一个端口上,但是NGINX可以根据类型正确的分发它们。

[title] [lang:language] [url] [link text] [additional options]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

# HTTP 负载均衡配置
http {
upstream http_servers {
server 192.168.186.1:8082; # 第一个HTTP实例
# 更多的HTTP服务实例
server 192.168.186.1:8083;
server 192.168.186.1:8084;
}

server {
listen 8080; # HTTP 监听端口
location / {
proxy_pass http://http_servers;
proxy_set_header Host $host; # 确保将正确的 Host 头部传递给上游服务器
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

# WebSocket 专用头部设置
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; # 支持 WebSocket 的升级机制
proxy_set_header Connection "upgrade";
proxy_read_timeout 60s; # 允许 WebSocket 连接保持 60s
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}

# UDP 负载均衡配置
stream {
upstream udp_servers1 {
server 192.168.186.1:8082; # 第一个UDP程序实例的地址和端口
server 192.168.186.1:8083; # 第二个UDP程序实例的地址和端口
# 添加更多UDP服务器实例
server 192.168.186.1:8084; # 第三个UDP程序实例的地址和端口
}

upstream udp_servers2 {
server 192.168.186.1:8085; # 第一个UDP程序实例的地址和端口
server 192.168.186.1:8086; # 第二个UDP程序实例的地址和端口
# 添加更多UDP服务器实例
server 192.168.186.1:8087; # 第三个UDP程序实例的地址和端口
}

server {
listen 8080 udp;
proxy_pass udp_servers1;
proxy_responses 1;
}

server {
listen 8081 udp;
proxy_pass udp_servers2;
proxy_responses 1;
}
}

events {
worker_connections 1024; # 默认配置
}

  值得注意的是,为了确保nginx代理服务器能够正确的处理websocket连接,需要有一些专门的设置,如上所示。其中:

  proxy_http_version 1.1;WebSocket 协议需要使用 HTTP/1.1 版本。这是因为 WebSocket 连接在建立时,会使用 HTTP 升级机制从标准的 HTTP 或 HTTPS 请求升级到 WebSocket 连接。HTTP/1.1 支持这种升级机制。

  proxy_set_header Upgrade $http_upgrade;这个头部告诉代理服务器,客户端想要升级连接到 WebSocket 协议。$http_upgrade 是一个 Nginx 变量,它包含了客户端请求中的 Upgrade 头部的值。如果客户端请求中包含 Upgrade: websocket,则此变量值为 websocket,否则为空。

  proxy_set_header Connection “upgrade”;当客户端请求升级到 WebSocket 连接时,它还会发送一个 Connection: Upgrade 头部。这个设置确保了代理服务器将这个头部转发给上游服务器,表示客户端想要升级协议。

  proxy_read_timeout 60s;WebSocket 连接一旦建立,就会保持开放状态直到客户端或服务器决定关闭。默认情况下,Nginx 的 proxy_read_timeout 设置可能比较短,这可能会导致 WebSocket 连接在没有数据传输时被关闭。将此值设置得更高(如 60 秒),可以确保在没有数据传输的情况下连接不会超时。

  proxy_set_header X-Forwarded-Proto $scheme;这个头部用于告诉上游服务器,原始请求使用的是 HTTP 还是 HTTPS 协议。这对于那些需要知道客户端原始连接协议的上游服务器来说很重要。$scheme 变量包含了请求的协议(http 或 https)。

  靠着这一系列的配置,确保nginx能够正确处理websocket的升级握手并且在握手成功后维持连接,从而使得websocket的连接可以正常工作。


学习笔记—通过nginx对UDP做负载均衡
https://gagaducko.github.io/2024/09/06/学习笔记—通过nginx对UDP做负载均衡/
作者
gagaduck
发布于
2024年9月6日
许可协议