-
Notifications
You must be signed in to change notification settings - Fork 0
Rate Limiting
Imagine the app is a clubhouse π with a friendly doorkeeper. The doorkeeper's only job is to make sure nobody knocks on the door too many times, too fast.
- When your computer shows up, it gets its own bucket with a handful of tokens (think: arcade coins ποΈ).
- Every time you ask the app for something (that's called a request), you drop one token in the slot.
- Tokens slowly come back on their own β a few refill every minute.
If your bucket has at least one token, the doorkeeper takes one and lets your request through. Easy.
If you knocked too many times and your bucket is empty, the doorkeeper says "come back in a bit." The app answers 429 β Too Many Requests, and even tells you how many seconds to wait (a Retry-After note). When your tokens refill, you're welcome again. π
flowchart TD
R["A request knocks"] --> Q{"Any tokens left in your bucket?"}
Q -->|Yes| T["Take one token and come in"]
Q -->|No| W["Please wait a bit (429 Too Many Requests)"]
W -.->|"tokens refill over time"| Q
- The login door (
/api/auth/...) is watched extra carefully β a small bucket (about 10 tries a minute). This stops bad guys from guessing passwords over and over. - Every other door gets a big bucket (about 100 tries a minute) β plenty for normal use.
Everyone is told apart by their address (their IP). Your bucket only counts your knocks β your neighbor has their own bucket. So one noisy visitor can't use up everybody else's tokens.
- On one computer / one server: the buckets live in the app's memory.
- When the app runs on many servers at once: the buckets live in a shared notebook called Redis, so every server agrees on how many tokens you have left.
The doorkeeper checks your bucket before the app even checks who you are. That way someone hammering the door gets turned away early, before the app does any real work.
If the shared notebook (Redis) can't be reached, the doorkeeper does not lock everyone out β it lets requests through so the app keeps working. Better to be a little too nice than to break the whole clubhouse.
| Kid word | Real name |
|---|---|
| bucket of tokens | the token-bucket algorithm |
| your address | the client IP (or the first X-Forwarded-For entry, only when behind a trusted proxy) |
| login door vs other doors | the auth tier (strict) vs the general tier |
| "come back later" |
HTTP 429 + a Retry-After header (plus X-RateLimit-Remaining on every reply) |
| shared notebook | Redis backend (an in-memory backend is used when there's a single instance) |
| doorkeeper at the front | the RateLimitWebFilter, ordered just ahead of Spring Security |
| doorkeeper gets sick β still let people in | fail-open |
| docs / health checks skip the line | excluded paths (/v3/api-docs, /swagger-ui, /webjars, /actuator) |
Turn it off with RATELIMIT_ENABLED=false; switch the backend with RATELIMIT_BACKEND=memory|redis.
Want the full picture of how requests flow through the app? See Architecture.
Getting started
How it works
Operations
Reference