Understanding Nginx Rate Limiting: The Relationship Between burst and nodelay Parameters


2 views

In Nginx, the limit_req_zone and limit_req directives work together to implement request rate limiting. The basic syntax looks like this:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

server {
    location / {
        limit_req zone=mylimit burst=20 nodelay;
    }
}

The burst parameter defines how many requests can exceed the base rate before Nginx starts rejecting requests. Without nodelay, excess requests are queued and processed at the defined rate.

For example, with rate=10r/s and burst=5:

  1. First 10 requests in a second are processed immediately
  2. Next 5 requests are queued and processed in subsequent 500ms
  3. Any additional requests get 503 response

The nodelay parameter changes this behavior fundamentally. When present:

  1. It allows the burst number of requests to be processed immediately
  2. No queuing occurs - either the request is processed now or rejected
  3. The burst "bucket" is still refilled at the specified rate

Consider these three configurations with rate=10r/s:

# Case 1: Basic rate limiting
limit_req zone=mylimit;

# Case 2: With burst but no nodelay
limit_req zone=mylimit burst=5;

# Case 3: With burst and nodelay
limit_req zone=mylimit burst=5 nodelay;

Behavior comparison:

Requests in 100ms Case 1 Case 2 Case 3
10 All processed All processed All processed
15 10 processed, 5 rejected 10 processed, 5 delayed 15 processed
20 10 processed, 10 rejected 10 processed, 5 delayed, 5 rejected 15 processed, 5 rejected

When to use nodelay:

  • When you need to allow occasional traffic spikes
  • When request queuing isn't practical (e.g., API endpoints)
  • When you want to strictly enforce rate limits after the burst

When to avoid nodelay:

  • When you want smooth rate limiting without sharp cutoffs
  • For endpoints where delayed responses are acceptable

Here's a more sophisticated setup that combines multiple rate limits:

geo $limited {
    default 0;
    10.0.0.0/8 1;
}

map $limited $limit_key {
    0 $binary_remote_addr;
    1 "";
}

limit_req_zone $limit_key zone=strict:10m rate=5r/s;
limit_req_zone $binary_remote_addr zone=normal:10m rate=10r/s;

server {
    location /api/ {
        limit_req zone=strict burst=3 nodelay;
        limit_req zone=normal burst=10;
    }
}

When configuring Nginx's limit_req directive, the combination of burst and nodelay often causes confusion. Let's break down their actual behavior:

limit_req zone=one burst=5 nodelay;

Without nodelay, burst creates a queue for excess requests:

limit_req zone=one burst=5;
# 6th request gets delayed (503 if queue fills completely)

Adding nodelay changes the behavior fundamentally:

  1. Burst size still defines the maximum number of excess requests
  2. Instead of delaying, Nginx immediately processes burst requests
  3. However, it still counts them against the rate limit

This combination is perfect for handling temporary traffic spikes while maintaining overall rate control:

# Allow 5 immediate excess requests, then enforce strict limit
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req zone=api burst=5 nodelay;

To observe the difference, try these test cases:

# Case 1: Without nodelay
ab -n 20 -c 5 http://yoursite.com/

# Case 2: With nodelay
ab -n 20 -c 5 http://yoursite.com/limited-endpoint
  • Myth: nodelay makes burst irrelevant
  • Truth: Burst still controls how many excess requests are allowed before enforcement
  • Myth: Nodelay disables rate limiting
  • Truth: It just changes the enforcement method

Combine with logging for debugging:

limit_req_status 429;
limit_req_log_level warn;