Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configure NGINX to respond 204 to a percentage of incoming requests

Tags:

nginx

I'd like to throttle incoming requests into an nginx route.

The current config is similar to this:

upstream up0 {
        server x.x.x.x:1111;
        keepalive 1024;
}

server {
        location /auc {
            limit_req   zone=one    burst=2100;
            proxy_pass http://up0/auc;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
        }
}

I'd like to control the number of requests I see at the upstream server. For all other requests I'd like nginx to respond with a 204 response.

Controlling by percentage of incoming requests would also work.

Thanks.

like image 468
Anas Alkhatib Avatar asked Nov 17 '15 19:11

Anas Alkhatib


1 Answers

Nginx is very effective at limiting requests using limit_req_zone and limit_req.

First create a zone which has defined limits. For a global limit, the key of the zone can be static, it's also possible to use variables such as the source ip address as a key for the zone which is useful for limiting by specific ip's or just slower pages on your site. The rate can be defined in requests per second or minute.

  limit_req_zone key zone=name:size rate=rate;

Next, create a rule to apply that zone to incoming requests. The location directive can be used first to apply the rule only to specific requests or it can be server wide. The burst option will queue a specified number requests that exceed the rate limit and is useful to throttle short bursts of traffic rather than return errors.

  limit_req zone=name [burst=number] [nodelay];

The default response code for traffic exceeding the rate limit and not held in a burst queue is 503 (Service Unvailable). Alternate codes like 204 (No content) can be set.

 limit_req_status code;

Putting all that together a valid config to limit all requests in the location block to 10 per second with a buffer to queue up to 50 requests before returning errors and return the specified 204 response could would look like:

http {

    ....

    limit_req_zone $hostname zone=limit:20m rate=10r/s;
    limit_req_status 204;

    server {

        ...

        location / {
            ...
            limit_req zone=limit burst=50;

        }

    }
}

In practice it's likely the server block will be in a different file included from within the http block. I've just condensed them for clarity.

To test, either use a flood tool or set the request rate=10r/m (10 per minute) and use a browser. It's useful to check the logs and monitor the amount of rejected requests so that you are aware of any impact on your users.

Multiple limit_req_zone rules can be combined to specify loose global limits and then stricter per source ip limits. This will enable targeting of the most persistent few users before the wider user base.

like image 55
Steve E. Avatar answered Nov 15 '22 05:11

Steve E.