NGINX 和 NGINX Plus 的速率限制功能
原文作者:Amir Rawdat - F5 NGINX 技术营销工程师原文来源:NGINX 中文官网
速率限制是 NGINX 最有用的功能之一,却往往被误解,且未能得到正确配置。此功能可以限制单个用户在给定时长内可发起的 HTTP 请求数量。此类请求可能非常简单,例如网站主页的 GET 请求,或登录页面的 POST 请求。速率限制可用于安全目的,例如减缓暴力破解密码的攻击频率。此功能可以将传入的请求速率限制为实际用户的典型值,(通过日志记录)识别目标 URL,从而达到防范 DDoS 攻击的目的。再概括一点说,可以防止上游应用服务器因同时服务过多用户请求而不堪重负。这篇博文将介绍如何使用 NGINX 进行速率限制,包括基础知识和高级配置。在NGINX Plus 中,速率限制的工作原理相同。
NGINX 速率限制的工作原理
速率限制基本配置
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
server {
location /login/ {
limit_req zone=mylimit;
proxy_pass http://my_upstream;
}
}
limit_req_zone 指令用于定义速率限制的参数,而 limit_req 在其出现的上下文环境中启用速率限制(在本例中,应用于指向 /login/ 的所有请求)。
处理突发流量
location /login/ {
limit_req zone=mylimit burst=20;
proxy_pass http://my_upstream;
}
burst 参数用于定义客户端在该区域定义的速率上限之外还可以发出的请求数量(以 mylimit 区域为样本,速率限制为每秒 10 个请求,即每 100 毫秒 1 个请求)。在前一个请求后 100 毫秒内到达的请求会加入队列,这里我们将队列容量设置为 20。
无延迟队列
location /login/ {
limit_req zone=mylimit burst=20 nodelay;
proxy_pass http://my_upstream;
}
二段式速率限制
limit_req_zone $binary_remote_addr zone=ip:10m rate=5r/s;
server {
listen 80;
location / {
limit_req zone=ip burst=12 delay=8;
proxy_pass http://website;
}
}
Delay 参数定义了一个点,在突发请求上限内,超出这个点的请求会被限流(延迟),从而达到已定义的速率限制标准。使用此配置,以 8 r/s 速率连续发出请求的客户端会经历如下行为。
高级配置示例
geo $limit {
default 1;
10.0.0.0/8 0;
192.168.0.0/24 0;
}
map $limit $limit_key {
0 "";
1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=req_zone:10m rate=5r/s;
server {
location / {
limit_req zone=req_zone burst=10 nodelay;
# ...
}
}
本例同时使用了 geo 和 map 指令。geo 模块为允许列表中 IP 地址的 $limit 赋值 0,为所有其他 IP 地址的 $limit 赋值 1。然后,我们使用 map 指令将这些值转换为关键字,例如:
-
如果 $limit 值为 0,则 $limit_key 设为空字符串
-
如果 $limit 值为 1,则 $limit_key 设为二进制格式的客户端 IP 地址
http {
# ...
limit_req_zone $limit_key zone=req_zone:10m rate=5r/s;
limit_req_zone $binary_remote_addr zone=req_zone_wl:10m rate=15r/s;
server {
# ...
location / {
limit_req zone=req_zone burst=10 nodelay;
limit_req zone=req_zone_wl burst=20 nodelay;
# ...
}
}
}
允许列表中的 IP 地址不符合第一个速率限制条件 (req_zone),但符合第二个条件 (req_zone_wl),因此被限制为每秒 15 个请求。允许列表以外的 IP 地址同时符合两个速率限制条件,因此更严格的一项限制生效:每秒 5 个请求。
配置相关功能
2015/06/13 04:20:00 [error] 120315#0: *32086 limiting requests, excess: 1.000 by zone "mylimit", client: 192.168.1.2, server: nginx.com, request: "GET / HTTP/1.0", host: "nginx.com"
日志条目包含以下字段:
-
2015/06/13 04:20:00 – 日志的录入日期和时间
-
[error] – 错误等级
-
120315#0 – NGINX worker 的 process ID 和 thread ID,以 # 号分隔
-
*32086 – 速率受限的代理连接的 ID
-
limiting requests – 表明日志条目记录到一次速率限制
-
excess – 显示此请求超过配置速率的每毫秒请求数
-
zone – 定义了强制执行速率限制的区域
-
client – 发出该请求的客户端 IP 地址
-
server – 服务器的 IP 地址或主机名
-
request – 客户端发出的实际 HTTP 请求
-
host – Host HTTP 的 header 值
location /login/ {
limit_req zone=mylimit burst=20 nodelay;
limit_req_log_level warn;
proxy_pass http://my_upstream;
}
发送至客户端的错误代码
location /login/ {
limit_req zone=mylimit burst=20 nodelay;
limit_req_status 444;
}
location /foo.php {
deny all;
}