本文介绍了如何设置连接请求的最大数量,或从服务器下载内容的最大速率。
使用NGINX和NGINX Plus,可以限制:
请注意,可以在NAT设备后面共享IP地址,因此应谨慎使用IP地址限制。
为了限制连接数:
limit_conn_zone $binary_remote_addr zone=addr:10m;
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算法:请求以各种速率到达存储桶,并以固定速率离开存储桶。
在使用速率限制之前,您需要配置“泄漏桶”的全局参数:
这些参数是通过 limit_req_zone 指令设置的。该指令是在 http{} 级别定义的,这种方法允许将不同的区域和请求溢出参数应用于不同的上下文:
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
}
使用此配置,将one创建大小为10 MB 的共享内存区域。该区域保留使用 $binary_remote_addr 变量设置的客户端IP地址的状态。注意,与 $remote_addr 同时拥有客户端的IP地址相比,$binary_remote_addr 拥有IP地址的二进制表示,后者更短。
使用以下数据可以计算共享内存区域的最佳大小:对于IPv4地址,$binary_remote_addr 值的大小为4字节,存储状态在64位平台上占用64字节。因此,大约16000个IP地址的状态信息占据了分区的1兆字节。
如果NGINX需要添加新条目时存储空间耗尽,它将删除最旧的条目。如果释放的空间仍然不足以容纳新记录,NGINX将返回状态代码503 Service Unavailable。状态代码可以用limit_req_status指令重新定义。
一旦设置了zone区域,您就可以使用NGINX配置限制任何请求,在server {},location {},或 http {}上下文中使用 limit_req 进行设置。
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
#...
location /search/ {
limit_req zone=one;
}
}
}
使用此配置,NGINX将在 /search/ 位置内每秒处理不超过1个请求。延迟处理这些请求的方式使得总速率不大于指定速率。如果请求数超过指定的速率,NGINX将延迟处理这些请求,直到“bucket”(共享内存区域one)满为止。如果请求到达后,存储桶已满,NGINX将返回503 Service Unavailable错误(如果没有使用limit_req_status重新定义)。
在配置实际速率限制之前,可以尝试不限制请求处理速率的“空运行”模式。但是,过多的此类请求仍在共享内存区域中进行处理并记录。可以使用 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个请求,则超出速率的请求将被放入区域one。当区域已满时,将对过多的请求进行排队(burst),此队列的大小为5个请求。队列中的请求处理将以不大于指定速率的方式延迟。超过突发限制的请求将被拒绝,并返回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限制内的过多请求将立即被服务,而不管指定的速率如何,超过突发限制的请求将被拒绝,并出现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 方法,则可以在以下条件下同步其共享内存区域的内容:
http {
#...
limit_req_zone $ binary_remote_addr zone = one:10m rate = 1r / s sync ;
}
要限制每个连接的带宽,请使用 limit_rate 指令:
location /download/ {
limit_rate 50k;
}
通过这种设置,客户端将能够以每秒50k字节的最大速度通过单个连接下载内容。但是,客户端可以打开多个连接。因此,如果目标是防止下载速度超过指定值,那么连接的数量也应该受到限制。例如,每个IP地址一个连接(如果使用上面指定的共享内存区域):
location /download/ {
limit_conn addr 1;
limit_rate 50k;
}
若要仅在客户端下载一定数量的数据后实施限制,请使用limit_rate_after指令。允许客户端快速下载一定数量的数据(例如,文件头-电影索引)并限制下载其余数据的速率(使用户观看电影而不是下载)可能是合理的。
limit_rate_after 500k;
limit_rate 20k;
下面的示例显示了用于限制连接数和带宽的组合配置。允许的最大连接数被设置为每个客户端地址的5个连接,这符合大多数常见情况,因为现代浏览器通常一次打开3个连接。同时,提供下载服务的location只允许一个连接:
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;
}
}
https://docs.nginx.com/nginx/admin-guide/security-controls/controlling-access-proxied-http/