Rate Limiting Algorithms: Token Bucket, Leaky Bucket and Sliding Windows
Rate limiting algorithms compared: fixed window, sliding log, sliding window counter, token bucket and leaky bucket, with code and distributed design tips.
Caching strategies and their trade-offs: cache-aside, read-through, write-through, write-back and write-around, plus eviction policies, TTLs and invalidation.

A cache stores copies of data in a faster place, usually memory, so repeated requests don’t hit slower systems like databases or external APIs. Done well, caching cuts latency and load dramatically. Done badly, it serves stale data and creates subtle bugs. The strategy you choose decides which trade-offs you accept.
The application manages the cache directly:
def get_user(user_id):
key = f"user:{user_id}"
cached = cache.get(key)
if cached is not None:
return cached
user = db.query_user(user_id)
cache.set(key, user, ttl=300)
return user
Pros: simple, only caches data that is actually requested, and the app keeps working if the cache fails. Cons: the first request for each key is slow, and cached data can go stale until it expires or is invalidated.
The cache sits in front of the database and loads missing data itself. Application code only talks to the cache. It’s cleaner, but requires a cache layer or library that supports it.
Every write goes to the cache and the database at the same time, synchronously. Pros: the cache is always consistent with the database. Cons: slower writes, and data that is written but never read still fills the cache.
Writes go to the cache first and are flushed to the database later, often in batches. Pros: very fast writes and fewer database operations. Cons: if the cache fails before flushing, data can be lost. Use it only where that risk is acceptable or mitigated.
Writes go straight to the database, skipping the cache. The cache is populated only on reads. Pros: avoids filling the cache with data nobody reads. Cons: a read right after a write will miss the cache.
| Strategy | Read latency | Write latency | Consistency | Risk |
|---|---|---|---|---|
| Cache-aside | Fast after first read | Normal | Can be stale | Stale data |
| Read-through | Fast after first read | Normal | Can be stale | Cache dependency |
| Write-through | Fast | Slower | Strong | Wasted cache space |
| Write-back | Fast | Fastest | Eventual | Data loss on failure |
| Write-around | Miss after writes | Normal | Good | Cold reads |
Caches are finite, so something has to go when they fill up:
user:42:v7) so updates naturally create new entries.When a popular key expires, thousands of requests can miss at once and overwhelm the database. Defences include:
Browser caches, CDNs, reverse proxies, in-process memory, distributed caches such as Redis or Memcached, and database buffer caches all play a part. Many systems use several layers. When a distributed cache spans many nodes, consistent hashing is a common way to decide which node holds each key, so adding a node moves only a fraction of them.
Caching is also central to serving AI models efficiently: repeated prompts can be answered from cache rather than recomputed. AIEmulate’s guide to running AI models locally covers the hardware side.
Cache-aside, because it’s simple and resilient: if the cache fails, the application can still read from the database. It’s also a safe default to propose in a system design interview.
As long as your data can safely be stale. Seconds for fast-changing data, hours or days for rarely changing data.
No. Cache data that is read often, expensive to fetch and tolerant of brief staleness, such as the redirect lookups in a URL shortener.
Every article is edited by a human and checked against our editorial policy. Spotted a mistake? Tell us.
Rate limiting algorithms compared: fixed window, sliding log, sliding window counter, token bucket and leaky bucket, with code and distributed design tips.
Kafka, RabbitMQ and Amazon SQS compared: log vs queue models, ordering, replay, throughput, delivery guarantees and operations, and when to use each.
How idempotency keys make retries safe: why duplicate requests happen, how to store and check keys, handling concurrent requests, expiry and common mistakes.