Search DistillSys

Find a concept

Type at least two characters to search lessons, designs, papers, and interview prep.

End-to-end walkthrough

Distributed Rate Limiter

Enforce fair request budgets across many stateless service instances.

01
Frame before solving

Requirements & boundaries

Functional

  • Apply per-tenant, per-user, or per-route policies.
  • Support sustained rate plus controlled burst capacity.
  • Return remaining budget and retry guidance.

Quality attributes

  • Decision p99 below 2 ms in-process or 10 ms over the network.
  • Policy changes propagate within seconds.
  • A limiter outage must not become a platform-wide outage.

Explicitly out of scope

  • Billing-grade usage metering.
  • Bot detection and reputation scoring.
02
Size the important constraints

Back-of-the-envelope estimates

Protected traffic5M requests/s peak

A network call for every request is expensive and risky.

Principals50M active keys

Counters need expiry and memory-efficient representation.

Policy readsThousands/s

Policies can be versioned and cached aggressively.

Decision budget<1% of endpoint latency

Use local tokens or regional batching on critical paths.

These are reference assumptions, not universal facts. In an interview or architecture review, change them when the product context changes.

03
Define the contract

API & data model

Core operations

POST/v1/checkEvaluate principal, resource, and cost; return allow plus retry_after.
PUT/v1/policies/{id}Publish a versioned rate policy.
GET/v1/usage/{principal}Inspect approximate current budget for operations.

Authoritative records

Policypolicy_id, matcher, rate, burst, action, versionImmutable versions allow atomic rollout and rollback.
Bucketprincipal+policy PK, tokens, last_refill_at, expires_atUpdate atomically with server-side time.
04
Trace the critical path

Architecture & request flow

  1. 1Identify principal
  2. 2Select policy
  3. 3Read or increment counter
  4. 4Allow or reject
  5. 5Emit decision telemetry

Policy service

Own limits and rollout rules

Limiter

Make the hot-path decision

Counter store

Coordinate shared usage windows

Local fallback

Protect dependencies during store failure

05
Reason about the hard parts

Critical design deep dives

Algorithm boundary

Token bucket fits bursty APIs; sliding-window counters give intuitive quotas but cost more state. Use fixed windows only where boundary bursts are acceptable.

Local versus global

Lease token batches from a regional store to each gateway. The hot path spends local tokens; unused leases expire. Overshoot is bounded by lease size × active gateways.

Failure policy

Authentication, payment, and write-amplifying endpoints may fail closed; ordinary reads often fail open with a conservative local cap. Encode this choice in policy so incident behavior is predictable.

06
Make trade-offs explicit

Architecture decisions

ChoiceWhyCost
Token bucketAllows controlled burstsDistributed token state must be reconciled
Local quotasRemoves a network hopGlobal limit becomes approximate
07
Failure-first review

What happens if…?

Counter store is slow

Fail open or closed by endpoint risk; never use one global default.

One tenant is hot

Partition by tenant and isolate heavy hitters before they saturate shared shards.

08
Avoid premature complexity

How the design evolves

1
One service

In-process token buckets

Move here when: Single replica or best-effort limits.

2
Shared regional limits

Atomic counter store with cached policies

Move here when: Multiple replicas need coordinated fairness.

3
Fleet scale

Leased token batches, tenant isolation, regional policy plane

Move here when: Limiter latency or store QPS dominates.

09
Test the reasoning

Interview follow-ups

How much can a leased-token design overshoot?

Strong answer signal: Derive the bound from lease size and concurrent holders.

What clock should refill use?

Strong answer signal: Use authoritative monotonic/server-side elapsed time, not client wall clocks.

How do policy rollouts avoid a thundering herd?

Strong answer signal: Versioned push, jittered refresh, and last-known-good fallback.

10
Build from primitives

Concepts used