← Writing

Rate Limiter Design

I'm implementing rate limiting for my personal project and documenting the design before coding.

1. Why rate limiting?

To prevent clients from overloading the system and ensure stable performance on a small server.

Goals:

  • Protect APIs from excessive traffic
  • Prevent single-client abuse
  • Safeguard expensive operations

2. What to limit?

Limit requests per client within a time window.

Example:

100 requests / minute

Exceeding the limit returns:

429 Too Many Requests

3. Algorithm choice

Options include Fixed Window, Sliding Window, and Token Bucket.

I'll use Sliding Window for the initial implementation.

4. Where to apply it?

Infrastructure layer

Client → Proxy / Load Balancer → App
  • Blocks traffic early
  • Limited application context

Application layer

Client → App → Rate Limiter → Controller
  • Full access to user and route context
  • Requests already hit the app

Combined approach

Client
  ↓
Infrastructure (IP-based coarse limit)
  ↓
Application (user/route-specific limit)

Infrastructure handles basic protection; application handles fine-grained rules.

5. Rate-limit identity

Authenticated

user_id

Unauthenticated

IP address

IP is imperfect but sufficient for initial protection.

6. State storage

Options:

  • In-memory → fast but not shared across instances
  • Database → too heavy for frequent updates
  • Redis → fast, shared, supports TTL and atomic ops

→ Use Redis

7. Rate-limit policy

Core structure:

Identity: USER | IP
Scope: GLOBAL | ROUTE | RESOURCE
Algorithm: SLIDING_WINDOW
Store: REDIS
Limit: N
Window: T

Example:

USER + ROUTE
POST /assessments
20 requests / 60s

Controller only declares policy:

@Post()
@RateLimit(...)
createAssessment() {}

8. Rate limiting vs usage quotas

Rate limiting controls frequency, not total consumption.

Example:

Rate limit: 10 requests / hour
Usage quota: 500 generations / month

They solve different problems:

  • Rate limit → request frequency
  • Quota → resource consumption

Quota tracking is handled separately in the system.

9. Redis key design

Examples:

rl:user:123:route:POST:/assessments
rl:ip:192.168.1.10:route:POST:/assessments
rl:global

Final structure depends on the sliding window implementation.

Next

Implement Sliding Window using Redis, atomic operations, and Lua scripting for concurrency safety.