Friday, August 26, 2016

Rate limiting with nginx

I just love Nginx, it's amazing at how little memory it consumes and how well it performs, much of this is owed to nginx’s use of the event driven mode.

One of my teams repeated problems that come up is the simple fact that some users and bots are a little excessive of the servers.

 http {

  limit_conn_zone  $binary_remote_addr zone=conn_limit_per_ip:50m;
  limit_req_zone   $binary_remote_addr zone=req_limit_per_ip:50m rate=1r/s;


    server {

        location / {

            limit_conn conn_limit_per_ip 10;
            limit_req zone=req_limit_per_ip burst=10 nodelay;

        }

     }

}
 


The directives that count here: limit_conn_zone, limit_req_zone, limit_conn and limit_req.

We first use limit_req_zone to set up at least a rate limit zone, which will then be enabled by placing them inside specific nginx location directives.

We start by setting up our first zone named ‘default’, give it 50 megabytes of memory to track our sessions, and set a rate at 1 request per second.

We then implement it in the ‘/’ location, and give it a ‘burst’ of 10.

Every time that a bot exceed the rate of 1 request per second, they have to pay a token.  Once they’ve spent all of their tokens, they are given an HTTP 503 error message. 

503 means  the server is currently unavailable (because it is overloaded or down for maintenance). Generally, this is a temporary state.

As you experience an excessive bot you will see the following in your log

2016/09/01 10:06:29 [error] 109154#109154: *42450 limiting requests, excess:
10.195 by zone "req_limit_per_ip", client: ip.of.attacher, server: default,
request: "GET
 
*42450 means:
This is a connection number, also available as $connection.
 
109154#109154 means:
This is nginx worker PID (also available as $pid) and thread identifier.
 
10.195 means:
This is number of requests accumulated in the bucket.  If this 
number is more than burst defined (10 in our case), further 
request will be rejected.
 
Number of requests in the bucket is reduced according to the rate 
defined and current time, and may not be integer.  The ".195" 
means that an additional request will be allowed in about 195 
milliseconds assuming rate 1r/s.

You can get more information at the following location(s) :
http://www.checkupdown.com/status/E503.html
http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html
http://nginx.org/en/docs/http/ngx_http_limit_req_module.html

HTH
Brent