Loading…
Rate limiting with Redis
Kwuang Tang
- Source
- Ramp
- Published
- Added to Yomu
Summary
Rate limiting at Ramp must handle third-party API quotas, globally paced Celery tasks, and inbound API traffic limited by authenticated application identities rather than only mutable IP addresses. Celery’s per-worker controls were insufficient for global limits, while queue prefetching could let rate-limited tasks block workers and stall queues. The team created a general framework for comparing algorithms and evaluated fixed-window, sliding-window, leaky/token-bucket, and Generic Cell Rate Algorithm (GCRA) approaches. They selected GCRA for implementation simplicity and compute and memory efficiency, storing a theoretical arrival time in Redis and using a Redis lock to prevent races. The implementation also uses floating-point timestamps, Redis server time, key expiration, unit tests, and manual testing; it has been introduced gradually across the three use cases, with monitoring, while additional algorithms remain planned.
Context
Ramp needed one global rate-limiting approach for third-party API quotas, periodic Celery workloads, and inbound API traffic. Existing Celery rate limiting was scoped per worker rather than globally, required configuration tied to queue and autoscaling details, and could block workers when prefetching was enabled. Cloudflare could limit by IP but could not authenticate Ramp’s application users.
Approach / What changed
Ramp built a general framework for testing rate-limiting algorithms and selected GCRA. Its Redis implementation uses a theoretical arrival time, a Redis lock to prevent race conditions, floating-point timestamps for precision, Redis server time, and key expiration. The limiter was introduced gradually across the three stated use cases with unit tests, manual testing, and monitoring.
Takeaways
- GCRA was chosen over fixed-window, sliding-window, and leaky/token-bucket approaches because the team considered its implementation simplicity and compute and memory efficiency suitable for most use cases.
- The implementation uses Redis time instead of each application server’s clock, since server clocks may differ, and stores timestamps as floats for higher precision.
- Celery’s built-in rate limiting is per-worker; distributing a desired global limit across workers requires awareness of queue placement, worker counts, and autoscaling behavior, and may still over-limit traffic.