NGINX限流配置
摘自:https://docs.nginx.com/nginx/admin-guide/security-controls/controlling-access-proxied-http/
介绍
使用 NGINX 和 NGINX Plus,可以限制:
- 每个键值的连接数(例如,每个 IP 地址)
- 每个键值的请求率(一秒或一分钟内允许处理的请求数)
- 连接的下载速度
请注意,IP 地址可以在 NAT 设备后面共享,因此应明智地使用 IP 地址限制。
限制连接数
限制连接数:
-
使用limit_conn_zone指令来定义键并设置共享内存区域的参数(工作进程将使用该区域来共享键值的计数器)。作为第一个参数,指定计算为键的表达式。在第二个参数
zone
中,指定区域的名称及其大小:limit_conn_zone $binary_remote_addr zone=addr:10m;
-
使用limit_conn指令在 、 或 上下文中
location {}
应用server {}
限制http {}
。第一个参数指定共享内存区域的名称,第二个参数指定每个键允许的连接数:location /download/ { limit_conn addr 1; }
由于该
$binary_remote_addr
变量被用作键,因此连接数受限于 IP 地址。限制给定服务器的连接数的另一种方法是使用
$server_name
变量:http { limit_conn_zone $server_name zone=servers:10m; server { limit_conn servers 1000; } }
限制请求率
限速可用于防止 DDoS 攻击,或防止上游服务器同时被太多请求淹没。该方法基于以下leaky bucket
算法:请求以各种速率到达存储桶并以固定速率离开存储桶。
在使用限速之前,您需要配置“漏桶”的全局参数:
- key - 用于区分一个客户端和另一个客户端的参数,通常是一个变量
- 共享内存区域 - 保存这些键状态的区域的名称和大小(“漏桶”)
r/s
rate - 每秒请求数 ( ) 或每分钟请求数( )中指定的请求速率限制r/m
(“漏桶耗尽”)。每分钟请求数用于指定小于每秒一个请求的速率。
这些参数是使用limit_req_zone指令设置的。该指令在http {}
级别上定义 - 这种方法允许将不同的区域和请求溢出参数应用于不同的上下文:
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
}
使用此配置,将one
创建大小为 10 兆字节的共享内存区域。该区域保持使用该$binary_remote_addr
变量设置的客户端 IP 地址的状态。请注意,与它相比$remote_addr
,它还保存客户端的 IP 地址,$binary_remote_addr
保存 IP 地址的二进制表示,它更短。
共享内存区域的最佳大小可以使用以下数据来计算:$binary_remote_addr
对于 IPv4 地址,value 的大小为 4 字节,存储状态在 64 位平台上占用 128 字节。因此,大约 16,000 个 IP 地址的状态信息占用了 1 兆字节的区域。
如果 NGINX 需要添加新条目时存储空间耗尽,它会删除最旧的条目。如果释放的空间仍然不足以容纳新记录,NGINX 返回状态码503 Service Unavailable
。可以使用limit_req_status指令重新定义状态代码。
设置区域后,您可以在 NGINX 配置中的任何位置使用请求限制,并为 a 、或context 指定limit_req:server {}
location {}
http {}
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
#...
location /search/ {
limit_req zone=one;
}
}
}
使用此配置,NGINX 将在该位置1
内每秒处理不超过请求。/search/
这些请求的处理以这样一种方式延迟,即总速率不大于指定的速率。如果请求数量超过指定速率,NGINX 将延迟处理此类请求,直到“桶”(共享内存区域one
)已满。对于到达完整存储桶的请求,NGINX 将响应503 Service Unavailable
错误(如果未使用limit_req_status重新定义)。
测试请求速率限制
在配置实际限速之前,可以尝试不限制请求处理速率的“dry run”模式。但是,此类过多的请求仍会记入共享内存区域并记录下来。可以使用limit_req_dry_run指令启用“试运行”模式:
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
#...
location /search/ {
limit_req zone=one;
limit_req_dry_run on;
}
}
}
每个超出定义速率限制的请求都将被记录为“试运行”标记:
2019/09/03 10:28:45 [error] 142#142: *13246 limiting requests, dry run, excess: 1.000 by zone "one", client: 172.19.0.1, server: www.example.com, request: "GET / HTTP/1.0", host: "www.example.com:80"
处理过多的请求
请求被限制为符合limit_req_zone指令中定义的速率。如果请求的数量超过指定的速率并且共享内存区域已满,NGINX 将响应错误。由于流量往往是突发的,因此在流量突发期间返回错误以响应客户端请求并不是最好的情况。
NGINX 中这种过多的请求可以被缓冲和处理。limit_req指令的burst
参数设置等待以指定速率处理的过多请求的最大数量:
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
#...
location /search/ {
limit_req zone=one burst=5;
}
}
}
使用此配置,如果请求速率超过1
每秒请求,则超出该速率的请求将被放入 zone one
。当 zone 已满时,过多的请求会被排队(burst
),这个队列的大小是5
requests。队列中的请求处理以这样的方式延迟,即总速率不大于指定的速率。超出突发限制的请求将被拒绝并出现503
错误。
如果在流量突发期间不希望请求延迟,请添加nodelay
参数:
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
#...
location /search/ {
limit_req zone=one burst=5 nodelay;
}
}
}
burst
使用此配置,无论指定如何,都会立即处理限制内的过多请求rate
,超过突发限制的请求将被拒绝并出现503
错误。
延迟过多的请求
处理过多请求的另一种方法是立即处理一些此类请求,然后应用速率限制,直到拒绝过多请求为止。
这可以通过delay
和burst
参数来实现。该delay
参数定义了延迟过多请求以符合定义的速率限制的点:
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
#...
location /search/ {
limit_req zone=one burst=5 delay=3;
}
}
}
使用此配置,前 3 个请求 ( delay
) 会立即通过,接下来的 2 个请求 ( burst
- delay
) 会延迟,以使总速率不大于指定的速率,因为超过了总突发大小,将拒绝更多的请求,后续请求将被延迟。
同步多个共享内存区域的内容
如果您有一个具有多个 NGINX 实例的计算机集群并且这些实例使用该limit_req
方法,则可以在以下条件下同步其共享内存区域的内容:
- 为每个实例配置了zone_sync功能
- 在limit_req_zone指令中为每个实例设置的共享内存区域具有相同的名称
- 为每个实例指定了limit_req_zone指令的同步参数:
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s sync;
}
有关详细信息,请参阅集群中的运行时状态共享。
限制带宽
要限制每个连接的带宽,请使用limit_rate指令:
location /download/ {
limit_rate 50k;
}
使用此设置,客户端将能够通过单个连接以50
每秒千字节的最大速度下载内容。但是,客户端可以打开多个连接。因此,如果目标是防止下载速度大于指定值,则还应限制连接数。例如,每个 IP 地址一个连接(如果使用上面指定的共享内存区域):
location /download/ {
limit_conn addr 1;
limit_rate 50k;
}
要仅在客户端下载一定数量的数据后施加限制,请使用limit_rate_after指令。允许客户端快速下载一定量的数据(例如,文件头——电影索引)并限制下载其余数据的速率(让用户观看电影,而不是下载)可能是合理的。
limit_rate_after 500k;
limit_rate 20k;
以下示例显示了用于限制连接数和带宽的组合配置。允许的最大连接数设置为5
每个客户端地址的连接数,这适合大多数常见情况,因为现代浏览器通常一次最多打开 3 个连接。同时,提供下载的位置只允许一个连接:
http {
limit_conn_zone $binary_remote_address zone=addr:10m
server {
root /www/data;
limit_conn addr 5;
location / {
}
location /download/ {
limit_conn addr 1;
limit_rate_after 1m;
limit_rate 50k;
}
}
}
动态带宽控制
limit_rate值也可以指定为变量 - 这可以启用动态带宽用例,例如,允许对现代浏览器进行更高的带宽限制:
map $ssl_protocol $response_rate {
"TLSv1.1" 10k;
"TLSv1.2" 100k;
"TLSv1.3" 1000k;
}
server {
listen 443 ssl;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
location / {
limit_rate $response_rate; # Limit bandwidth based on TLS version
limit_rate_after 512; # Apply limit after headers have been sent
proxy_pass http://my_backend;
}
}