Skip to content

Performance

Cost per request

Every check is exactly one round trip to Redis (one EVAL call), regardless of algorithm. There is no separate "read" then "write" — that's the entire point of using a Lua script. On a local or same-AZ Redis, this is typically sub-millisecond.

Algorithm cost comparison

Algorithm Redis operations per check Keys touched
Fixed window INCRBY + conditional PEXPIRE + PTTL 1
Sliding window 2× GET + conditional INCRBY + PEXPIRE 2 (same slot)
Token bucket HMGET + conditional HSET + PEXPIRE 1

All three are O(1) — none scale with request volume or history length (unlike, say, a sorted-set-based "exact" sliding window log, which this package deliberately avoids in favor of the O(1) approximate counter approach).

Multiple throttles multiply round trips

If a view has N throttles in throttle_classes, that's N Redis round trips per request (DRF checks each in turn). Keep the throttle count per view small — two or three is typical (e.g. one per-user, one per-tenant); avoid stacking many redundant ones.

Connection pooling

get_redis_client() builds one client (via redis.Redis.from_url()) and caches it for the process lifetime — redis-py's client already manages a connection pool internally, so this package doesn't add its own pooling layer on top. For high-concurrency deployments, tune the pool via a custom client passed through REDIS_CLIENT:

import redis

pool = redis.ConnectionPool.from_url("redis://localhost:6379/0", max_connections=50)
client = redis.Redis(connection_pool=pool)
RATELIMIT_PLUS = {"REDIS_CLIENT": "myapp.redis_setup.client"}

Benchmarking

import time
from drf_ratelimit_plus.algorithms import token_bucket_check
from drf_ratelimit_plus.rates import parse_rate
from drf_ratelimit_plus.client import get_redis_client

client = get_redis_client()
rate = parse_rate("1000000/h")  # effectively unlimited, for pure latency measurement
start = time.perf_counter()
for i in range(1000):
    token_bucket_check(client, f"bench-{i % 10}", rate, burst=1000000)
elapsed = time.perf_counter() - start
print(f"{1000 / elapsed:.0f} checks/sec")

Run this against your actual Redis deployment (not fakeredis, which doesn't reflect real network/serialization overhead) for representative numbers.