16.限制内容访问速率
根据客户端 IP 地址或其他变量限制连接、请求速率或带宽,从而保护upstream Web 和应用程序服务器。本文介绍如何设置连接的最大请求数或从服务器下载内容的最大速率。
使用NGINX,可以限制:
- 每个密钥值的连接数(例如,每个 IP 地址)
- 每个键值的请求速率(允许在一秒或一分钟内处理的请求数)
- 连接的下载速度
请注意,IP 地址可以在 NAT 设备后面共享,因此应明智地使用 IP 地址限制。
限制连接数(Limiting the Number of Connections)
要限制连接数:
-
使用 limit_conn_zone 指令定义键并设置共享内存区域的参数(工作进程将使用此区域共享键值的计数器)。作为第一个参数,指定计算为键的表达式。在第二个参数
zone中,指定区域的名称及其大小:limit_conn_zone $binary_remote_addr zone=addr:10m; -
使用 limit_conn 指令在
location {}、server {}或http {}上下文中应用限制。将共享内存区域的名称指定为第一个参数,将每个密钥允许的连接数指定为第二个参数:location /download/ {
limit_conn addr 1;
}连接数因 IP 地址而异,因为
$binary_remote_addr变量用作密钥。限制给定服务器连接数的另一种方法是使用
$server_name变量:http {
limit_conn_zone $server_name zone=servers:10m;
server {
limit_conn servers 1000;
}
}
限制请求速率(Limiting the Request Rate)
速率限制可用于防止 DDoS 攻击,或防止上游服务器同时被过多请求淹没。该方法基于泄漏存储桶算法:请求以不同的速率到达存储桶,并以固定速率离开 存储桶。
在使用限速之前,需要配置“泄漏桶”的全局参数:
- key - 用于区分一个客户端与另一个客户端的参数,通常是一个变量
- 共享内存区域(shared memory zone) - 保存这些密钥 状态的区域的名称和大小(“泄漏存储桶”)
- 速率(rate) - 在每秒请求数 (
r/s) 或每分钟请求数 (r/m) 中指定的请求速率限制(“漏桶排空”)。每分钟请求数用于指定每秒小于一个请求的速率。
这些参数使用 limit_req_zone 指令设置。该指令是在 http {}级别上定义的 - 这种方法允许将不同的区域和请求溢出参数应用于不同的上下文:
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
}
使用此配置,将创建大小为 10 MB 的共享内存区域 one。 该区域保留使用 $binary_remote_addr 变量设置的客户端 IP 地址的状态。请注意,与同时保存客户端 IP 地址的 $remote_addr 相比,$binary_remote_addr 保存的 IP 地址的二进制表示形式更短。
可以使用以下数据计算共享内存区域的最佳大小: 对于 IPv4 地址,$binary_remote_addr 值的大小为 4 个字节, 存储状态在 128 位平台上占用 64 个字节。因此,大约 16,000 个 IP 地址的状态信息占用 1 MB 的区域。
如果NGINX需要添加新条目时存储空间已耗尽,则会删除最旧的条目。如果释放的空间仍然不足以容纳新记录,NGINX 将返回状态代码 503 Service Unavailable。可以使用 limit_req_status 指令重新定义状态代码。
设置区域后,您可以使用限制 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将延迟处理此类请求,直到“存储桶”(共享内存区域 one)已满。对于到达整个存储桶的请求,NGINX 将响应错误 503 Service Unavailable(如果未使用 limit_req_status 重新定义)。
测试请求速率限制(Testing the Request Rate Limit)
在配置实际速率限制之前,您可以尝试不限制请求处理速率的“试运行(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请求数,超出速率的请求将被放入区域 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;
}
}
}
使用此配置,无论指定 rate如何,都会立即为 burst限制内的过多请求提供服务,超过突发限制的请求将被拒绝并返回 503 错误。