Skip to main content
When a celebrity posts one of our short links and millions of people click it in a short timeframe, the system must absorb a sudden burst of reads. This is a classic read-heavy, hot-key problem for URL shorteners.

Traffic baseline: normal day vs. celebrity hour

Assumptions:
  • ~1,000 clicks per short link created.
  • 1,000,000 links created per day.
Rough daily reads: 1,000,000 links × 1,000 reads/link = 1,000,000,000 redirects/day Spread evenly: 1,000,000,000 requests / 86,400 seconds ≈ 11,574 reads/sec Table — traffic summary Even if a well-tuned Postgres instance might handle tens of thousands of reads/sec, this is a lot for a single DB host — and most of those reads are identical lookups that never change. For example, if 1,000 users click the same short URL, the DB returns the same long URL 1,000 times. That is wasteful. Example mapping:
Now imagine the celebrity spike: a million clicks in the first hour (or even hundreds of millions globally in a day). Almost all those requests ask for the same short code. This “one thing goes viral and is accessed by many” pattern is called a hot key. Hot keys are the signature failure mode of read-heavy systems.

Solution: add a cache for hot keys

We should avoid sending a million identical queries to Postgres. Add a fast in-memory cache (for example, Redis) to serve hot keys in under a millisecond. Typical request flow for a redirect:
  1. Client requests the short URL.
  2. Request hits the application server.
  3. Application server checks Redis:
    • Cache hit: return the long URL immediately (no DB involved).
    • Cache miss: read from Postgres once, write the mapping into Redis, return the long URL.
  4. Subsequent requests for the same short code are served from Redis.
In a celebrity spike, the first request triggers one DB read; the remaining millions are cache hits.

Staleness concerns

A common cache problem is staleness: the cache can contain outdated data while the database has been updated (e.g., cache has x = 7, DB has x = 9). That can cause incorrect responses.
A stylized architecture diagram titled "STALENESS" showing multiple clients hitting an app server that reads from a cache and a Postgres database. The graphic highlights a stale-cache scenario where the cache returns x = 7 while the database value is 9.
In a URL shortener the mapping from short code to long URL is written once and never updated. That makes this workload ideal for aggressive caching: the cache will not serve incorrect data for these mappings.
Note: Because our design treats short codes as immutable (written once, never edited), staleness is not a practical issue for the core redirect mapping. This immutability is important to state in interviews: it justifies aggressive caching. Also remember caches have finite memory and use eviction policies. Redis typically evicts least-recently-used items to make room. Popular links remain cached; inactive links are removed — which is the desired behavior.

Further optimizations: push hot keys closer to users

If Redis becomes a bottleneck or you want even lower latency, add additional layers:
  1. Application-server local cache
    • Each app server keeps a small in-process LRU cache (e.g., top few thousand links).
    • Extremely hot links are served directly from app memory with minimal latency.
A stylized architecture diagram of a URL shortener: many mobile clients click a link that hits app servers which consult a cache (lightning icon) and a Postgres database. The database panel shows a urls table mapping short_code to long_url and the app server notes the top 5,000 links.
  1. Content Delivery Network (CDN)
    • Place a CDN in front of the service so geographically nearby nodes can answer redirect requests.
    • Regional CDN nodes absorb massive global spikes; on a cache miss they fall back to the origin.
A dark-themed network diagram showing several mobile phones on the left labeled "Everyone clicks the link" with an arrow to a "Tokyo" cache node. The Tokyo node links to a central "CDN" globe which connects to origin servers on the right labeled "The Origin · Virginia."

Cache layers and responsibilities

Operational considerations

  • TTL and eviction: set reasonable TTLs or rely on LRU eviction for Redis since mappings are immutable.
  • Cache warming: pre-populate cache for anticipated viral links (if known).
  • Monitoring & scaling: alert on cache miss rate, Redis CPU/network, and DB read rate to detect cascade failures early.
  • Rate-limiting: protect origin DB with rate limits or request-shedding for extreme spikes.
Even with immutable short codes, ensure your CDN and caches honor expected TTLs or cache-control headers so you can retire or rotate links if necessary (for example, in legal takedown situations).
  • Use Redis as the primary cache for hot keys to avoid repeated Postgres reads.
  • Keep a small LRU cache in each app server for the most popular short codes.
  • Front the system with a CDN so regional requests are handled close to the user.
These layers — CDN, edge/app-server in-memory cache, and Redis — allow your URL shortener to absorb celebrity spikes efficiently while keeping database load minimal.

Watch Video