NGINX系列(六) 限制请求速率和带宽限制

1
2
3
4
5
6
7
作者:李晓辉

联系方式:

1. 微信:Lxh_Chat

2. 邮箱:939958092@qq.com

环境介绍

操作系统IP地址主机名NGINX版本角色
Rocky9.4192.168.8.3loadbalance.xiaohui.cn1.26.2负载均衡

限制请求速率和限制带宽的概念

限制请求速率

定义:限制请求速率是指控制每个客户端在一定时间内可以向服务器发起请求的数量。例如,可以限制每个IP地址每秒钟只能发起10个请求。

请求速率限制原理:NGINX 通过 limit_req_zonelimit_req 指令来实现请求速率限制。limit_req_zone 指令创建一个共享内存区域,用于存储请求的状态信息,而 limit_req 指令则在特定的服务器块或位置块中应用请求限制。工作原理是 NGINX 监控每个客户端的请求速率,当请求超过设定的阈值时,会对请求进行丢弃或延迟处理。

使用场景示例

  • 防止DDoS攻击:通过限制每个客户端的请求速率,可以有效防止恶意用户利用大量请求来攻击服务器。

  • API保护:限制API接口的调用速率,防止用户频繁调用接口,保护服务器资源。

  • 流量管理:合理分配服务器资源,避免某些客户端占用过多带宽或处理能力。

限制带宽

定义:限制带宽是指控制每个连接(或请求)的数据传输速率。通过限制带宽,可以有效地管理和分配服务器资源,确保每个客户端获得公平的传输速率。

带宽限制原理:NGINX 通过 limit_ratelimit_rate_after 指令来实现带宽限制。limit_rate 指令设置每个连接的传输速率,而 limit_rate_after 指令则指定在传输一定大小的数据后开始限速。这两个指令可以在服务器块或位置块中使用,控制每个请求的带宽。

使用场景示例

  • 最大化带宽利用率:通过限制每个请求的带宽,确保所有用户能够公平地使用服务器资源。

  • 防止下载滥用:限制文件下载速度,防止客户端过度占用带宽,影响其他用户的访问体验。

  • 视频和音频流控制:控制视频和音频流的传输速率,保证流媒体的平稳传输。

限制请求数案例

生成配置文件

1
2
3
4
5
6
7
8
9
10
11
12
cat > /etc/nginx/conf.d/limitconn.conf <<'EOF'
limit_conn_zone $binary_remote_addr zone=limitbyaddr:10m;
limit_conn_status 429;
server {
listen 80 default_server;
limit_conn limitbyaddr 1;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
EOF

配置文件详解

  1. limit_conn_zone $binary_remote_addr zone=limitbyaddr:10m;

    • 解释:这个指令定义了一个共享内存区域,用来保存客户端连接状态。limitbyaddr是区域名称,可以是任意字符串,10m是分配给这个区域的内存大小(10MB)。$binary_remote_addr表示以客户端的IP地址为键,这样每一个唯一的IP地址都有自己独立的连接计数。

    • 作用:为每个客户端IP地址创建一个连接状态追踪器。

  2. limit_conn_status 429;

    • 解释:这个指令设置当客户端连接数超过限制时,返回的HTTP状态码为429(Too Many Requests)。

    • 作用:当连接数超过规定的数量时,向客户端返回429错误。

  3. server { ... }

    • 解释:这一部分包含服务器块的配置。在这个服务器块中,有一些重要的指令和设定。

    • 作用:配置服务器的基本功能和行为。

  4. listen 80 default_server;

    • 解释:这个指令让服务器监听80端口,并将其设置为默认服务器。它会处理所有发往80端口的请求。

    • 作用:定义服务器监听的端口和默认服务器的角色。

  5. limit_conn limitbyaddr 1;

    • 解释:这个指令启用了连接数限制。limitbyaddr是前面定义的共享内存区域的名称,1表示每个客户端(每个IP地址)只允许一个连接。

    • 作用:限制每个客户端(每个IP地址)同时只能与服务器建立一个连接。

创建测试网页

echo的小数据可能看不到效果,我们用dd命令场景一个稍微大点的文件。

1
2
3
4
5
[root@loadbalance ~]# dd if=/dev/random of=/usr/share/nginx/html/index.html bs=10M count=10
10+0 records in
10+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.279367 s, 375 MB/s
[root@loadbalance ~]# systemctl restart nginx

访问测试页面

这里要注意,必须能正常返回预期的100M数据,如果是返回的别的内容,就是有其他配置文件干扰,需要删除其他配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@loadbalance ~]# wget http://loadbalance.xiaohui.cn
--2025-01-19 13:54:28-- http://loadbalance.xiaohui.cn/
Resolving loadbalance.xiaohui.cn (loadbalance.xiaohui.cn)... 192.168.8.138
Connecting to loadbalance.xiaohui.cn (loadbalance.xiaohui.cn)|192.168.8.138|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 104857600 (100M) [text/html]
Saving to: ‘index.html’

index.html 100%[=================================================================================================================>] 100.00M --.-KB/s in 0.06s

2025-01-19 13:54:28 (1.58 GB/s) - ‘index.html’ saved [104857600/104857600]


[root@loadbalance ~]# ls -lh index.html
-rw-r--r--. 1 root root 100M Jan 19 13:53 index.html
[root@loadbalance ~]#

测试连接数限制

本次文章用到了ApacheBench压力测试工具,安装httpd-tools即可

1
dnf install httpd-tools -y

一共访问20次,每次并发2个请求,可以看到非2XX开头的失败有19个,只有一个成功,但是每次并发一个请求,就会都成功

1
ab -n 20 -c 2 http://loadbalance.xiaohui.cn/
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
This is ApacheBench, Version 2.3 <$Revision: 1913912 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking loadbalance.xiaohui.cn (be patient).....done


Server Software: nginx/1.26.2
Server Hostname: loadbalance.xiaohui.cn
Server Port: 80

Document Path: /
Document Length: 169 bytes

Concurrency Level: 2
Time taken for tests: 0.033 seconds
Complete requests: 20
Failed requests: 1
(Connect: 0, Receive: 0, Length: 1, Exceptions: 0)
Non-2xx responses: 19
Total transferred: 104864056 bytes
HTML transferred: 104860811 bytes
Requests per second: 599.38 [#/sec] (mean)
Time per request: 3.337 [ms] (mean)
Time per request: 1.668 [ms] (mean, across all concurrent requests)
Transfer rate: 3068997.38 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 0 2 7.4 0 33
Waiting: 0 0 0.1 0 0
Total: 0 2 7.4 0 33

Percentage of the requests served within a certain time (ms)
50% 0
66% 0
75% 0
80% 0
90% 0
95% 33
98% 33
99% 33
100% 33 (longest request)

限制客户端请求速率案例

简单限制请求速率

为了避免干扰,别忘了把其他配置文件都删了

此处限速为一秒只能处理一个request: 1r/s,超过就会返回HTTP 429

1
2
3
4
5
6
7
8
9
10
11
12
cat > /etc/nginx/conf.d/limitreq.conf <<'EOF'
limit_req_zone $binary_remote_addr zone=limitbyaddr:10m rate=1r/s;
limit_req_status 429;
server {
listen 80 default_server;
limit_req zone=limitbyaddr;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
EOF

重新nginx服务后,测试请求速率

一共快速发起2个请求,但是其中有一个失败了

1
[root@loadbalance ~]# ab -n 2 http://loadbalance.xiaohui.cn/

输出

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
This is ApacheBench, Version 2.3 <$Revision: 1913912 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking loadbalance.xiaohui.cn (be patient).....done


Server Software: nginx/1.26.2
Server Hostname: loadbalance.xiaohui.cn
Server Port: 80

Document Path: /
Document Length: 104857600 bytes

Concurrency Level: 1
Time taken for tests: 0.022 seconds
Complete requests: 2
Failed requests: 1
(Connect: 0, Receive: 0, Length: 1, Exceptions: 0)
Non-2xx responses: 1
Total transferred: 104858170 bytes
HTML transferred: 104857769 bytes
Requests per second: 90.10 [#/sec] (mean)
Time per request: 11.099 [ms] (mean)
Time per request: 11.099 [ms] (mean, across all concurrent requests)
Transfer rate: 4613261.10 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 0 11 15.2 22 22
Waiting: 0 0 0.1 0 0
Total: 0 11 15.2 22 22

Percentage of the requests served within a certain time (ms)
50% 22
66% 22
75% 22
80% 22
90% 22
95% 22
98% 22
99% 22
100% 22 (longest request)
[root@loadbalance ~]#

查看日志

1
2
3
4
5
6
7
8
9
10
11
[root@loadbalance ~]# tail /var/log/nginx/error.log
2025/01/19 14:00:02 [notice] 1445#1445: nginx/1.26.2
2025/01/19 14:00:02 [notice] 1445#1445: built by gcc 11.5.0 20240719 (Red Hat 11.5.0-2) (GCC)
2025/01/19 14:00:02 [notice] 1445#1445: OS: Linux 5.14.0-427.13.1.el9_4.x86_64
2025/01/19 14:00:02 [notice] 1445#1445: getrlimit(RLIMIT_NOFILE): 1024:524288
2025/01/19 14:00:02 [notice] 1446#1446: start worker processes
2025/01/19 14:00:02 [notice] 1446#1446: start worker process 1447
2025/01/19 14:00:02 [notice] 1446#1446: start worker process 1448
2025/01/19 14:00:02 [notice] 1446#1446: start worker process 1449
2025/01/19 14:00:02 [notice] 1446#1446: start worker process 1450
2025/01/19 14:00:19 [error] 1447#1447: *2 limiting requests, excess: 0.978 by zone "limitbyaddr", client: 192.168.8.138, server: , request: "GET / HTTP/1.0", host: "loadbalance.xiaohui.cn"

两段式限制请求速率

什么是两段式限速?

在某些情况下,客户端可能需要在短时间内发出大量请求,然后迅速平静下来。这种情况常见于流量激增的瞬间,如电子商务网站上的促销活动、限时抢购、直播实时互动等。为有效应对这种突发流量,NGINX提供了一个名为burst的参数,它允许客户端在超出其速率限制时,继续发送请求而不被直接拒绝。

burst参数设置了一个允许超出的请求数量上限。超出速率限制但在burst限度内的请求,将被NGINX排序,按预设速率逐个处理,而不是立即返回错误。这些超出的请求会被暂时延迟处理,从而使系统能更平稳地应对瞬时的请求高峰。例如,可以设置burst参数为10,这意味着在允许速率基础上,最多可超出10个请求,而这些请求会被缓冲处理。

另外,可以结合使用nodelay参数,使得这些burst请求不产生延迟,立即按照速率限制处理完毕。在许多高负载的应用场景中,这种设置可以显著改善用户体验,防止因瞬间请求过多而导致服务中断或性能下降。

这种策略特别适用于那些需要在关键时间段处理大量请求,然后逐渐恢复到正常流量的场景,如网站流量高峰、API调用激增等。通过合理设置burst和请求速率限制,可以确保服务器在高峰期依然能够稳定、高效地处理用户请求。

在这个例子中能够限制每个客户端的请求速率,避免恶意用户通过大量请求来攻击服务器。同时,通过允许一定数量的突发请求,能够处理突发流量而不影响用户体验。能够限制每个客户端的请求速率,避免恶意用户通过大量请求来攻击服务器。同时,通过允许一定数量的突发请求,能够处理突发流量而不影响用户体验。本例中,将burst设置为10,以允许有10个额外请求作为缓冲地带

1
2
3
4
5
6
7
8
9
10
11
12
cat > /etc/nginx/conf.d/limitreq.conf <<'EOF'
limit_req_zone $binary_remote_addr zone=limitbyaddr:10m rate=1r/s;
limit_req_status 429;
server {
listen 80 default_server;
limit_req zone=limitbyaddr burst=10;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
EOF

两段式限速配置文件详解

  1. limit_req_zone $binary_remote_addr zone=limitbyaddr:10m rate=1r/s;
  • 解释:这条指令创建了一个共享内存区域,用于存储请求的速率限制信息。

    • $binary_remote_addr:使用客户端的IP地址作为键,以二进制格式表示。

    • zone=limitbyaddr:10m:定义了一个名为limitbyaddr的共享内存区域,大小为10MB。

    • rate=1r/s:设置速率限制为每秒1个请求。

  • 作用:确保每个客户端的请求速度不会超过每秒1次。

  1. limit_req_status 429;
  • 解释:这条指令设置当请求超出速率限制时,返回的HTTP状态码为429(Too Many Requests)。

  • 作用:当客户端请求速度超过设定的限制时,服务器将返回429错误码,告知客户端请求过多。

  1. server { ... }
  • 解释:定义一个服务器块,其中包含了服务器配置的具体内容。

    • listen 80 default_server;:服务器监听80端口,并设置为默认服务器。

    • limit_req zone=limitbyaddr burst=10;:应用请求速率限制,允许突发最多10个额外请求。

    • location / { ... }:定义请求路径处理,具体是根路径/的处理方式。

      • root /usr/share/nginx/html;:设置根目录为/usr/share/nginx/html,即服务器会在此目录下查找文件。

      • index index.html;:设置默认主页文件为index.html,即当访问根路径/时,返回该文件。

深入分析

  1. 共享内存区(limit_req_zone)

    • 设置背景:NGINX使用共享内存区域来跟踪每个客户端的请求数,以确定速率是否超过限制。

    • 意义:通过设置较大的内存区域(10MB),可以支持更多客户端的请求记录。

  2. 状态码设置(limit_req_status)

    • 作用:通过返回429状态码,通知客户端当前请求过多,避免服务器过载。
  3. 服务器块配置(server)

    • 监听端口:设置为80端口,常用于HTTP请求。

    • 突发请求(burst):突发允许10个多余请求,这些请求会被暂时延迟处理,而不会立即拒绝。

    • 根目录和主页配置

      • 根目录:设置为/usr/share/nginx/html,这是NGINX默认的HTML文件目录。

      • 主页文件:设置为index.html,当客户端访问根路径/时,会返回这个文件作为响应。

测试缓冲效果

我们设置了每秒处理一个,然后额外缓冲10个,然后一共可以有11个不会拒绝,所以一共发起13个请求中,失败了2个

而且本次ab测试,明显速度就慢了下来

1
ab -n 13 -c 13 http://loadbalance.xiaohui.cn/

输出

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
This is ApacheBench, Version 2.3 <$Revision: 1913912 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking loadbalance.xiaohui.cn (be patient).....done


Server Software: nginx/1.26.2
Server Hostname: loadbalance.xiaohui.cn
Server Port: 80

Document Path: /
Document Length: 169 bytes

Concurrency Level: 13
Time taken for tests: 10.025 seconds
Complete requests: 13
Failed requests: 11
(Connect: 0, Receive: 0, Length: 11, Exceptions: 0)
Non-2xx responses: 2
Total transferred: 1153436927 bytes
HTML transferred: 1153433938 bytes
Requests per second: 1.30 [#/sec] (mean)
Time per request: 10024.943 [ms] (mean)
Time per request: 771.149 [ms] (mean, across all concurrent requests)
Transfer rate: 112360.07 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 0
Processing: 0 4253 3567.4 4527 10024
Waiting: 0 4231 3562.8 4501 10000
Total: 0 4253 3567.4 4528 10024

Percentage of the requests served within a certain time (ms)
50% 4027
66% 6025
75% 7026
80% 8027
90% 9025
95% 10024
98% 10024
99% 10024
100% 10024 (longest request)

下面这个配置文件能够有效地控制每个客户端的请求速率,并允许一定数量的突发请求在短时间内被处理。通过配置 burstdelay 参数,可以将超出速率的请求平滑地分配在处理时间内,从而防止瞬时高流量对服务器的冲击。

  • burst=20:允许最多20个突发请求。

  • delay=9:请求总量超过限制后,将以每秒1个请求的速率进行延迟处理。

  • 作用:短时间内,服务器最多可以处理20个超出速率限制的请求,这些请求会被平滑地分配到每秒1个的时间间隔中进行处理,从而防止瞬时请求过多导致服务器过载。

1
2
3
4
5
6
7
8
9
10
11
12
cat > /etc/nginx/conf.d/limitreq.conf <<'EOF'
limit_req_zone $binary_remote_addr zone=limitbyaddr:10m rate=1r/s;
limit_req_status 429;
server {
listen 80 default_server;
limit_req zone=limitbyaddr burst=20 delay=9;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
EOF

虽然burst和delay使得业务流量在突发时不至于拒绝的太猛,但同时也带来了延迟,如果不能有太多延迟,可以使用nodelay参数,见下方例子

limit_req zone=limitbyaddr burst=20 nodelay;

  • 解释:配置请求速率限制,允许20个突发请求并且没有延迟。

  • zone=limitbyaddr:指明使用之前定义的共享内存区域limitbyaddr

  • burst=20:允许最多20个超出速率限制的突发请求。

  • nodelay:表示这些请求不会被延迟,而是立即进行处理。

  • 作用:允许短时间内处理最多20个额外请求而不会延迟。

1
2
3
4
5
6
7
8
9
10
11
12
cat > /etc/nginx/conf.d/limitreq.conf <<'EOF'
limit_req_zone $binary_remote_addr zone=limitbyaddr:10m rate=1r/s;
limit_req_status 429;
server {
listen 80 default_server;
limit_req zone=limitbyaddr burst=20 nodelay;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
EOF

限制带宽速率

带宽限速概述

NGINX高度灵活的带宽控制功能使得limit_ratelimit_rate_after这两个参数在流量管理中无比重要。limit_rate参数用于控制每个连接的传输速率,确保不会发生单个连接占用过多带宽的情况。通过设定传输速率,比如limit_rate 50k;,服务器可以将每个连接的传输速率限制为每秒50KB。这在限制大型文件下载速度以及流媒体传输速率时非常有用,有助于避免单一客户端占用资源不当影响其他用户。

limit_rate_after参数则同样强大,它允许对连接进行更灵活的带宽管理。在使用这个参数时,可以设定在传输了一定量的数据之后才开始应用带宽限制。例如,配置limit_rate_after 500k;意味着在传输了500KB数据后,服务器才会开始对该连接应用limit_rate设定的限制。这种配置非常适用于需要在早期快速响应用户请求,但随后慢速传输大文件的情况。

这种带宽控制策略不仅可以优化服务器资源分配,还能提升整体用户体验,确保更多用户能够公平地使用服务器资源。通过合理应用limit_ratelimit_rate_after,可以更好地应对高峰流量和防止带宽滥用。

配置文件解释

别忘了删除别的配置文件防止干扰

我这里针对本网站的/lixiaohui二级目录做了限速,前10M的速度为满速,超过10M之后,限制为1M

1
2
3
4
5
6
7
8
9
10
11
cat > /etc/nginx/conf.d/limitbandw.conf <<'EOF'
server {
listen 80 default_server;
location /lixiaohui {
limit_rate_after 10m;
limit_rate 1m;
root /usr/share/nginx/html;
index index.html;
}
}
EOF
  • server { ... }

    • 解释:定义服务器块,包括服务器的一些基本配置。

    • 作用:配置服务器的监听端口、位置处理和文件服务等功能。

  • listen 80 default_server;

    • 解释:服务器监听80端口,并设置为默认服务器。

    • 作用:使服务器响应发往80端口的所有请求。

  • location /lixiaohui { ... }

    • 解释:定义位置块,用于处理/lixiaohui路径的请求。

    • 作用:配置该路径下请求的特定处理方式。

  • limit_rate_after 10m;

    • 解释:设定在传输了10MB数据之后,开始应用带宽限制。

    • 作用:初始阶段立即回应大量数据,随后开始限速,有助于在初期快速传输大文件。

  • limit_rate 1m;

    • 解释:将带宽限制设置为每秒1MB。

    • 作用:确保在传输10MB之后,每个连接的传输速率不超过每秒1MB。

  • root /usr/share/nginx/html;

    • 解释:设置根目录为/usr/share/nginx/html,服务器会在此目录下查找文件。

    • 作用:定义文件服务的根目录。

  • index index.html;

    • 解释:指定默认主页文件为index.html

    • 作用:当客户端访问/lixiaohui路径时,服务器将返回此文件作为响应。

创建二级目录,并制作了一个2GB的文件

1
2
3
mkdir /usr/share/nginx/html/lixiaohui
dd if=/dev/zero of=/usr/share/nginx/html/lixiaohui/index.html bs=1M count=2000
systemctl restart nginx

测试带宽速率

可以看到速度刚开始是满速,后面速度被限制在1.00MB/s

1
2
3
4
5
6
7
8
9
[root@loadbalance ~]# wget http://loadbalance.xiaohui.cn/lixiaohui/index.html
--2025-01-19 14:30:13-- http://loadbalance.xiaohui.cn/lixiaohui/index.html
Resolving loadbalance.xiaohui.cn (loadbalance.xiaohui.cn)... 192.168.8.138
Connecting to loadbalance.xiaohui.cn (loadbalance.xiaohui.cn)|192.168.8.138|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2097152000 (2.0G) [text/html]
Saving to: ‘index.html.1’

index.html.1 0%[ ] 12.01M 5.99MB/s
1
2
3
4
5
6
7
8
9
[root@loadbalance ~]# wget http://loadbalance.xiaohui.cn/lixiaohui/index.html
--2025-01-19 14:30:13-- http://loadbalance.xiaohui.cn/lixiaohui/index.html
Resolving loadbalance.xiaohui.cn (loadbalance.xiaohui.cn)... 192.168.8.138
Connecting to loadbalance.xiaohui.cn (loadbalance.xiaohui.cn)|192.168.8.138|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2097152000 (2.0G) [text/html]
Saving to: ‘index.html.1’

index.html.1 2%[=> ] 40.00M 1.00MB/s eta 24m 30s