Rate Limiting

How it works

Rate limiting is implemented on the router app’s nginx configuration. See the configuration for the current limits. A user exceeding the limit is returned a static error page with a 429 (Too Many Requests) status code.

Rate limiting being turned on depends on the environment variables present when supervisor compiles the templates and launches nginx using the (digitalmarketplace-router/nginx.sh bash script).

In the case of rate limiting the DM_RATE_LIMITING_ENABLED environment variable is parsed and supplied to the templates as rate_limiting_enabled here.

The www template (which is put in /etc/nginx/sites_enabled) and the main nginx.conf ( which ends up in /etc/nginx) both contain rate limiting dependent sections.

nginx.conf

In the main Nginx config we:

  • Change the return code for rate limited requests from the default 503 Service Unavailable to 429 Too Many Requests

  • Create a new custom variable to signify if the request is a POST or not $post_remote_addr

  • Create 2 zones/ buckets for requests

    • One which catches everything that has a non-blank $binary_remote_addr (everything)

    • One which catches everything that has a non-blank custom $post_remote_addr (only POST requests)

www

In www we:

  • Statically serve too_many_requests.html on port 10823

  • State that we want to apply our rate limiting buckets to incoming requests to the server on port 80 (the application)

    • Set burst allowances for these requests

  • Define a ‘location’ where every request is proxied to localhost:10823 as a GET

  • Tell Nginx that requests that trigger a 429 should be passed to this location

Burst

Nginx rate limiting works as a ‘leaky bucket algorithm’ or ‘FIFO’ pipeline.

As of May 2021, the rate limit is 18 requests a second with 20 burst.

This means that:

  • the fastest a user can be served 2 requests is 0.06 (1/18) seconds apart.

  • if requests arrive quicker than that they are put in a queue.

  • if the queue size exceeds 20 (for that IP) they are served 429s

Deactivating rate limiting

You might want to turn off rate limiting for load/ stress testing or for debugging purposes. You can achieve this in 2 ways but both involve changing the DM_RATE_LIMITING_ENABLED variable to something that is not "enabled" and restaging the router.

The first, and preferred method, would be to update the variable in the appropriate manifest variable file.

https://github.com/Crown-Commercial-Service/ccs-digitalmarketplace-aws/blob/main/vars/preview.yml#L10 https://github.com/Crown-Commercial-Service/ccs-digitalmarketplace-aws/blob/main/vars/staging.yml#L10 https://github.com/Crown-Commercial-Service/ccs-digitalmarketplace-aws/blob/main/vars/production.yml#L10

The second (which will be overwritten to enabled if a release is triggered on the router) is to use the Cloud Foundry Command Line Interface to update the variable and restage the router:

cf target -s preview
cf env router DM_RATE_LIMITING_ENABLED "disabled"
cf restage router