Backend Development 18 min read

Interface Idempotency and Distributed Rate Limiting: Token Bucket, Leaky Bucket, Guava, Nginx, and Redis+Lua

This article explains the concept of interface idempotency, presents practical techniques such as version‑based updates and token mechanisms, and then dives into distributed rate‑limiting strategies covering dimensions, token‑bucket and leaky‑bucket algorithms, and concrete implementations using Guava RateLimiter, Nginx, and Redis‑Lua scripts.

IT Architects Alliance
IT Architects Alliance
IT Architects Alliance
Interface Idempotency and Distributed Rate Limiting: Token Bucket, Leaky Bucket, Guava, Nginx, and Redis+Lua

Interface idempotency ensures that repeated requests produce the same result without side effects; a typical example is payment where duplicate clicks must not cause double charges. The core idea is to use a unique business identifier (or version number) to guard the operation, optionally acquiring a distributed lock.

For update operations, idempotency can be achieved by adding a version column and using it in the WHERE clause:

update set version = version + 1, xxx=${xxx} where id = ${id} and version = ${version};

When no natural business key exists, a token generated on the client side can be stored in a hidden field and validated on the server, often combined with a distributed lock to guarantee a single successful insert.

Distributed rate limiting controls traffic across multiple dimensions such as QPS, connection count, transmission speed, black/white lists, and the overall distributed environment. Multiple rules can be combined to form comprehensive protection.

The two most common algorithms are:

Token Bucket : a bucket holds a configurable number of tokens generated at a steady rate; each request consumes a token, allowing bursts while the bucket is not empty.

Leaky Bucket : requests are queued in a bucket that drains at a constant rate, smoothing traffic regardless of arrival spikes.

Implementation examples:

Guava RateLimiter (Java)

@RestController
@Slf4j
public class Controller {
    // 2 tokens per second
    RateLimiter limiter = RateLimiter.create(2.0);

    @GetMapping("/tryAcquire")
    public String tryAcquire(Integer count) {
        if (limiter.tryAcquire(count)) {
            log.info("success, rate={}", limiter.getRate());
            return "success";
        } else {
            log.info("fail, rate={}", limiter.getRate());
            return "fail";
        }
    }

    @GetMapping("/acquire")
    public String acquire(Integer count) {
        limiter.acquire(count);
        log.info("success, rate={}", limiter.getRate());
        return "success";
    }
}

Nginx IP‑based rate limiting

# Define a shared memory zone for IP limits
limit_req_zone $binary_remote_addr zone=iplimit:20m rate=1r/s;

server {
    server_name www.test.com;
    location /access-limit/ {
        proxy_pass http://127.0.0.1:8080/;
        limit_req zone=iplimit burst=2 nodelay;
    }
}

Redis + Lua distributed limiter

-- Lua script (rateLimiter.lua)
local methodKey = KEYS[1]
local limit = tonumber(ARGV[1])
local count = tonumber(redis.call('get', methodKey) or "0")
if count + 1 > limit then
    return false
else
    redis.call('INCRBY', methodKey, 1)
    redis.call('EXPIRE', methodKey, 1)
    return true
end

In a Spring Boot application the script is loaded and executed via StringRedisTemplate :

@Service
@Slf4j
public class AccessLimiter {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisScript
rateLimitLua;

    public void limitAccess(String key, Integer limit) {
        Boolean acquired = stringRedisTemplate.execute(rateLimitLua, Collections.singletonList(key), limit.toString());
        if (!acquired) {
            log.error("Your access is blocked, key={}", key);
            throw new RuntimeException("Your access is blocked");
        }
    }
}

An AOP annotation can be added to methods to apply the limiter transparently.

Overall, the article provides a complete guide from theory to practical code for achieving idempotent APIs and robust distributed rate limiting in backend systems.

JavaRedisIdempotencynginxRate LimitingLuatoken bucketleaky bucket
IT Architects Alliance
Written by

IT Architects Alliance

Discussion and exchange on system, internet, large‑scale distributed, high‑availability, and high‑performance architectures, as well as big data, machine learning, AI, and architecture adjustments with internet technologies. Includes real‑world large‑scale architecture case studies. Open to architects who have ideas and enjoy sharing.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.