test sys design

Design a URL shortening service like TinyURL or bit.ly. Users paste a long URL and get a short link such as https://sho.rt/aZ3k9Q. Anyone who opens the short link is redirected to the original URL.

What the interviewer expects

  • Clear functional and non-functional requirements before any boxes are drawn.
  • A rough capacity estimate that drives your storage and caching choices.
  • A clean API and data model.
  • A high-level design with a fast redirect path.
  • One or two deep dives: ID generation, caching, sharding or analytics.

Starting assumptions (confirm with your interviewer)

  • 100 M new short URLs per month.
  • Read-heavy: about 100 redirects per URL created.
  • Links are kept for 5 years. Custom aliases and expiry are optional.

Use the Framework tab as your checklist. Start the mock system design interview from the timer to practise under time pressure.

Strong candidates ask questions like these before designing:

  1. Should the same long URL always return the same short URL?
  2. Can users choose a custom alias? Do links expire?
  3. How short must the code be? Which characters are allowed?
  4. Do we need click analytics (counts, referrers, geography)? Real-time or batch?
  5. What redirect latency is acceptable? (Typically p99 under 50 ms.)
  6. Is it OK if a brand-new link takes a second to work in every region?
100 M URLs/month is about 40 writes/s and 4,000 redirects/s on average. The redirect path is what you optimise.
7 characters of base62 give 62⁷ ≈ 3.5 trillion codes. That is plenty for 6 B URLs over 5 years.
Hashing the long URL causes collisions. A global counter (or pre-generated key ranges) handed to each app server avoids them without coordination on every request.
Redirects are a perfect cache workload: small values, heavy skew toward popular links. A cache plus a 301/302 decision changes your load a lot.

1. Requirements

Functional: create a short URL, redirect to the long URL, optional custom alias and expiry. Non-functional: very low redirect latency, 99.99% availability for redirects, codes that are hard to guess, durable storage.

2. Estimates

  • Writes: 100 M/month ≈ 40/s (peak ~120/s).
  • Reads: 100:1 ≈ 4 K/s (peak ~12 K/s).
  • Storage: 6 B URLs × ~500 B ≈ 3 TB, about 9 TB with 3 replicas.
  • Cache: 20% of daily hot links ≈ tens of GB, so it fits in a small Redis cluster.

3. API

POST /v1/urls   {longUrl, alias?, expiresAt?}  -> 201 {code, shortUrl}
GET  /{code}                                     -> 302 Location: longUrl

4. Data model

urls(code PK, long_url, user_id, created_at, expires_at) in a key-value or wide-column store (DynamoDB or Cassandra), partitioned by code. Access is always by key, so you do not need joins.

5. High-level design

Clients reach a load balancer, then a stateless URL service. The write path takes an ID from a Key Generation Service (ranges of IDs handed out from a counter), base62-encodes it and stores the row. The read path checks Redis first and falls back to the database. Click events go to Kafka, and an analytics worker aggregates them into an OLAP store.

6. Deep dives

  • ID generation: counter ranges avoid collisions and coordination. Shuffle or encrypt the ID if codes must not be guessable.
  • 301 vs 302: a 301 is cached by browsers, which cuts load but loses analytics. Use 302 when clicks must be counted.
  • Hot links: cache-aside with a TTL, plus a CDN or edge cache for viral links.
  • Failures: if the cache is down, the database absorbs reads (size for it). If the key service is down, servers keep working from the ranges they already hold.

Open the HLD board and click Reference to compare this diagram with yours.

Previous Post
No Comment
Add Comment
comment url