← Back to portfolio

System Design

Bitly — High-Level Design

A walkthrough of how I'd design a URL shortener like Bitly and scale it from a single server to a distributed, read-heavy system serving 100M daily active users. Below is the design, step by step.

System DesignCachingRedisSnowflakeZookeeperMicroservices
  1. 01

    Requirements & API

    Nailing down functional requirements (create a short URL with optional alias & expiry, redirect users) and non-functional ones (low latency, 100M DAU, unique URLs, high availability with eventual consistency). The API surface is a POST /url to create and GET /url/{short_code} to redirect.

    Requirements & API
  2. 02

    Day 0 Architecture

    The simplest thing that works: a single server writing to a database, returning 301/302 redirects on reads. Good enough for roughly 1–10k users — a sensible starting point before optimizing.

    Day 0 Architecture
  3. 03

    Day 100 — Estimating Scale

    Targeting 100M daily active users works out to ~1000 requests/sec (and bursts far higher). A single vertically-scaled box hits a hardware ceiling — you can't just keep buying a bigger EC2 instance.

    Day 100 — Estimating Scale
  4. 04

    Microservices & Data Model

    Move to horizontally-scaled services behind a load balancer. The url_table stores short_code (indexed), long_url, alias, created_at and user_id — roughly 242 bytes per row, or ~242 GB for 1 billion URLs.

    Microservices & Data Model
  5. 05

    Why Cache?

    242 GB fits comfortably in a single modern DB, but the real problem is query volume: one viral short link can trigger millions of reads. Caching protects the stateful database — the resource we least want to overload.

    Why Cache?
  6. 06

    Read vs Write Split

    Bitly is read-heavy — URLs are created rarely but redirected constantly. Splitting into dedicated Read and Write services lets each scale independently. Reads check Redis first and fall back to the DB.

    Read vs Write Split
  7. 07

    Caching Layer

    On a GET, the read service checks Redis; on a miss it queries the DB and populates the cache. This keeps hot links blazing fast and shields the database from the redirect firehose.

    Caching Layer
  8. 08

    Generating Unique Short URLs

    The write service owns short-code generation. A naive MD5 hash risks collisions, so a better approach is a global counter fed into the hashing step to guarantee uniqueness.

    Generating Unique Short URLs
  9. 09

    Distributed IDs — Snowflake + Zookeeper

    To generate unique IDs without a single bottleneck, each write server gets a worker ID from Zookeeper and keeps a local counter. A Snowflake-style 64-bit ID (timestamp + worker ID + sequence) is generated per server and hashed into a short code.

    Distributed IDs — Snowflake + Zookeeper
← Back to portfolio