aily active users 10 million Popular service
New URLs created per day 100 million ~10 URLs per user
Read/Write ratio 100:1 For every 1 URL created, 100 people click it
Step 2: Calculate QPS (Queries Per Second)
Writes (URL creation):
100M URLs per day ÷ 86,400 seconds ≈ 1,200 writes/sec
Reads (Redirects):
1,200 × 100 (read ratio) = 120,000 reads/sec
Peak traffic: Multiply by 2-3x ⇒ ~3,600 writes/sec and ~360,000 reads/sec
Step 3: Storage
Each URL entry needs roughly:
Short key (6 chars) + Long URL (500 chars avg) + Created date + User ID ≈ ~1 KB
Time Total URLs Storage
1 day 100M 100 GB
1 year 36.5B ~36 TB
Pro tip: Mention you'd use TTL/expiration (auto-delete old URLs after 1 year) to cap storage.
Step 4: Bandwidth (Optional but nice)
Writes: 1,200 writes/sec × 1 KB = ~1.2 MB/s incoming Reads: 120,000 reads/sec × 1 KB = ~120 MB/s outgoing
Here's a quick template you can paste in:
Assumptions:
100M new URLs/day, 100:1 read:write ratio
QPS:
Writes: ~1,200/sec (peaks at ~3,600)
Reads: ~120,000/sec (peaks at ~360,000)
Storage:
~100 GB/day, ~36 TB/year (before cleanup)
Bandwidth:
In: ~1.2 MB/s, Out: ~120 MB/s
Define the APIs expected from the system. This is your chance to analyze and define the read and write paths so that you can come up with the high-level design...
Describe the overall system architecture. Identify the main components needed to solve the problem end-to-end. Use the diagramming tool to create a block diagram.
core components --> Write DB
Read operation separate DB - Read Replication
Load Balancer - to multiple request will go to different through LB to service
Redis Cache is optional I will use it for strong consistency otherwise I will skip as tiny url will be eventual consistency is enough
Define the data model. Identify the main entities, their attributes, and relationships. Consider the choice of database type (SQL vs NoSQL) and justify your decision based on access patterns...
urls| Column | Type | Notes |
id | BIGINT | Primary key, auto-increment |
short_key | VARCHAR(10) | Unique index — this is what users click |
long_url | TEXT | Original URL (up to 2048 chars) |
user_id | VARCHAR(50) | Nullable — who created it |
created_at | TIMESTAMP | When it was created |
expires_at | TIMESTAMP | Nullable — TTL for auto-delete |
Deep dive into 2-3 key components. Explain how they work, how they scale, discuss tradeoffs, capacity, and any relevant algorithms or data structures.
Step 1: Unique constraint on short_key
Step 2: Retry logic in application
def create_short_url(long_url): for attempt in range(3): short_key = generate_random_key(7) try: db.insert(short_key=short_key, long_url=long_url) return short_key except UniqueConstraintViolation: continue # Try again with a new key raise Exception("Failed after 3 attempts")
That's it! Simple and effective.
Then the race condition shifts:
| Method | Race condition | Solution |
| Random key | Same key generated twice | Unique constraint + retry ✅ |
| Auto-increment ID | Two services ask for next ID at same time | Use a database sequence or Snowflake ID generator |
"For ID generation, I'll use a random 7-character base62 string. On collision (caught by the unique constraint on short_key), the service retries with a new random key up to 3 times. Since 62^7 ≈ 3.5 trillion combinations, collisions are extremely rare in practice."
| Component | Why it matters |
| 1. ID Generation | How do you create unique short keys at 1,200 writes/sec without collisions? |
| 2. Caching | What happens when a URL goes viral and gets 100K clicks/second? |
| 3. Redirect Flow | What happens step-by-step when a user clicks a short URL? |
Write about:
Try writing something like:
"For ID generation, I'll use a random 7-character base62 string. That gives 62^7 ≈ 3.5 trillion unique keys — more than enough. On collision (caught by unique constraint), I retry with a new random string. This is simple, distributed-friendly, and hard to guess."