Protecting the API from its own users
Rate limits, quotas, backpressure, and graceful degradation — the difference between a spike and an outage.
What you will be able to do
- Choose between token bucket and sliding window rate limiting
- Explain where limits belong in a multi-layer system
- Design graceful degradation for an overloaded dependency
- Describe how to find and stop abusive traffic
Two algorithms, two intents
In a distributed fleet, the counter must be shared or the limit multiplies by the number of nodes. Redis with an atomic increment, or a local bucket with a small overshoot tolerance, are both defensible — say which and why.
INCR ratelimit:{tenant}:{minute}
EXPIRE ratelimit:{tenant}:{minute} 60
if count > limit: 429 with Retry-After: seconds-to-window-endWhere the limits live
| Layer | Limit | Why here |
|---|---|---|
| Edge / WAF | IP and coarse global caps | Stops floods before they consume your capacity |
| Gateway | Per-key, per-tenant quotas | Identity is known, and one place to change policy |
| Service | Per-endpoint cost limits, concurrency caps | Expensive endpoints need their own budget |
| Datastore | Connection pool sizes and query timeouts | The last line of defence for shared resources |
Overload: three honest answers
- Queue it — good when work is deferrable and the user is not waiting. A video transcode queue can absorb a spike.
- Shed it — refuse the excess with 429/503 quickly. Cheap, honest, and better than accepting work you cannot finish.
- Degrade it — serve a cheaper version: cached results, fewer recommendations, a static fallback. Users get something instead of an error.
The failure mode to avoid is accepting everything and finishing nothing. Latency climbs, queues grow, retries multiply, and a system that could have served 80% of traffic at full speed serves 0% at ten seconds per request.
Finding the abusers
You cannot limit what you cannot attribute. Emit a metric per key, tenant, endpoint, and status code, then watch the top talkers. Most incidents come from a small number of clients: a retry loop in someone's batch job, a scraper with no rate control, or your own mobile app on an old version hammering a deprecated endpoint. Look at the shape of the traffic before writing a rule — a limit applied to the wrong dimension just breaks honest users.
Worth remembering
- Token bucket allows bursts up to the bucket size; sliding window is fair but stricter. Pick by product intent.
- Limits belong at the edge for cheap, global protection and in the service for per-tenant fairness.
- Queueing, shedding, and degradation are three different answers to overload — say which you are doing and why.
- Always tell the client when you limit them (429 + Retry-After), or they will retry harder.