NGINX:队列中查询的请求限制超时行为(突发)

Pio*_*źdź 2 nginx reverse-proxy 503-error high-load http-status-code-408

目前,我们的队列大小为 3000 个请求。

location /api/v2 {
     limit_req zone=bursted burst=3000;
     include /etc/nginx/proxy.conf;
 }
Run Code Online (Sandbox Code Playgroud)

速率限制为每秒 10 个请求。

 limit_req_zone $limit zone=api_slow:10m rate=1r/s;
 limit_req_zone $server_name zone=bursted:10m rate=10r/s;
Run Code Online (Sandbox Code Playgroud)

保持活动超时为 30 秒。换句话说,当队列已满时,每 30 秒应拒绝 2700 个请求,并显示错误代码 408。

 reset_timedout_connection on;
 client_body_timeout 10;
 send_timeout 2;
 keepalive_timeout 30;
Run Code Online (Sandbox Code Playgroud)

在高峰时段,我在日志中找不到任何请求,由于超时,该请求被 NGINX 拒绝,错误代码为 408,而请求正在队列中等待转发到 servlet 容器。仅拒绝并返回 503 错误代码,这与请求速率开销相对应。

delaying request, excess: 2958.320, by zone "bursted"
limiting requests, excess: 3000.730 by zone "bursted"
Run Code Online (Sandbox Code Playgroud)

如果此类队列中的请求挂起时间过长,NGINX 是否会通过超时拒绝这些请求?这个超时是什么?它的配置在哪里?

Bob*_*Bob 6

nginx 速率限制和超时的工作原理似乎有点混乱。速率限制没有超时。您只需设置速率和队列大小。任何超出速率的请求都将添加到队列中以供稍后处理。一旦队列完全填满,任何其他请求都将被拒绝,并显示 503 状态代码。


在您的示例中,您设置的速率为每秒 10 个请求 (10r/s),突发大小为 3000,区域“突发”大小为 10 MB。此速率限制适用于每个定义的服务器的单独计数。

换句话说,您的服务器每 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。


使用absiege执行负载测试