目前,我们的队列大小为 3000 个请求。
location /api/v2 {
limit_req zone=bursted burst=3000;
include /etc/nginx/proxy.conf;
}
速率限制为每秒 10 个请求。
limit_req_zone $limit zone=api_slow:10m rate=1r/s;
limit_req_zone $server_name zone=bursted:10m rate=10r/s;
Keep-Alive 超时为 30 秒。换句话说,当队列已满时,每 30 秒应拒绝 2700 个请求并显示错误代码 408。
reset_timedout_connection on;
client_body_timeout 10;
send_timeout 2;
keepalive_timeout 30;
在高峰时段,我在日志中找不到任何被 NGINX 拒绝的请求,原因是请求在队列中等待转发到 servlet 容器时超时,错误代码为 408。只有 503 错误代码被拒绝,这与请求速率开销相对应。
delaying request, excess: 2958.320, by zone "bursted"
limiting requests, excess: 3000.730 by zone "bursted"
如果队列中的请求挂起时间过长,NGINX 是否会通过超时拒绝这些请求?这个超时是多少?它的配置在哪里?
答案1
似乎对 nginx 速率限制和超时的工作原理有些困惑。没有暂停用于速率限制。您只需设置速率和队列大小。任何超过该速率的请求都将被添加到队列中,以便稍后处理。一旦队列完全填满,任何其他请求都将被拒绝,并显示 503 状态代码。
在你的例子中您已将速率设置为每秒 10 个请求 (10r/s),突发大小为 3000,区域“突发”大小为 10 兆字节。并且此速率限制适用于每个定义的服务器的单独计数。
换句话说,您的服务器每 0.1 秒接受并处理一个请求,最多可以排队 3000 个超出的请求,然后以定义的速率处理这些请求:每 0.1 秒一个。您的突发区域可以存储大约 160,000 个 IP 地址。
这意味着如果 3011 个请求在一秒钟内到达,nginx 会立即处理前 10 个请求,将另外 3000 个请求放入队列,第 3011 个请求将被拒绝并返回 503 状态代码。然后,队列将以定义的速率(每 0.1 秒一个请求)进行处理。只要没有新请求到达,队列就会变短,并且可以再次将新请求添加到队列中。但是,虽然队列已经容纳了 3000 个请求,但每个额外的请求都将被拒绝并返回 503 状态代码。
这种线性处理突发队列的行为可能会使您的网站看起来很慢。为了防止这种情况,您可以将参数添加nodelay
到limit_req zone=bursted burst=3000 nodelay;
。这将使来自突发队列的所有请求立即得到处理,同时将队列中的插槽标记为“已占用”,然后再次以定义的速率逐个插槽“释放”,因此定义的速率限制会随着时间的推移而得到满足。
limit_req_status 444;
顺便说一句:您可以通过添加到配置块将拒绝请求的状态代码从 503 更改为 444 http
。
更多详细信息请参阅:
您的配置中的两个超时:
这client_body_timeout 10;
将使你的服务器在收到请求后最多等待 10 秒,等待客户端主体发送。如果在这段时间内客户端没有发送主体,服务器将关闭连接并返回 408 状态代码。
这keepalive_timeout 30;
将使你的服务器关闭 30 秒后仍处于打开状态的客户端的任何连接。但根据我的测试,请求在突发队列中等待的时间不计入 keepalive_timeout。