Diagram in progress 😊.. v0 below
bitly.excalidraw
1️⃣ Problem Statement
Build a URL shortening service like:
https://www.google.com/search?q=system+design
↓
https://bit.ly/aB3xYzWhen users visit the short URL, they should be redirected to the original URL.
2️⃣ Requirements Gathering
Functional Requirements
Core Features
- Create short URL from long URL
Long URL
↓
Short URLExample:
https://google.com/search?q=test
↓
bit.ly/aB3xYz- Redirect users
bit.ly/aB3xYz
↓
https://google.com/search?q=testOptional Features
Custom Alias
User can provide custom code:
bit.ly/omi
bit.ly/interview
bit.ly/sdeprepinstead of
bit.ly/aB3xYzExpiration Time
bit.ly/event2026Valid only until:
2026-12-31After expiry:
404 / Link Expired3️⃣ Non-Functional Requirements
Low Latency
Redirect should feel instant.
Target:
< 200 msReason:
- Human perceives anything below ~200ms as real-time.
Scalability
Support:
100 Million DAU
1 Billion URLsUniqueness
Every short URL must be unique.
Bad:
bit.ly/abc123
→ Google.com
and
bit.ly/abc123
→ Amazon.comCollision must never happen.
High Availability
System should remain operational even during failures.
Prefer:
Availability > Strong Consistencybecause URL shortening is not a banking system.
4️⃣ CAP Theorem Decision
Need Strong Consistency?
Examples that require it:
- Banking
- Ticket Booking
- Trading Systems
Reason:
Every read must see latest write.Bitly?
Not necessary. Scenario:
Create URL
↓
Immediately open URL
↓
Fails for few secondsThis is acceptable.
Decision
CP ❌
AP ✅Choose:
High Availability
Eventual Consistency5️⃣ Core Entities
User
UserURL
Short URL
Long URL6️⃣ API Design
Create Short URL
POST /urlsRequest:
{
"originalUrl": "https://google.com",
"customAlias": "omi",
"expirationTime": "2026-12-31"
}Response:
{
"shortUrl": "bit.ly/omi"
}Redirect
GET /{shortCode}Example:
GET /aB3xYzResponse:
302 Redirect
Location: https://google.com7️⃣ Database Design
URL Table
| Column | Description |
|---|---|
| short_url | Generated code |
| original_url | Actual URL |
| created_at | Creation timestamp |
| expiration_time | Optional expiry |
| user_id | Creator |
User Table
| Column | Description |
|---|---|
| user_id | Primary Key |
| User email | |
| metadata | Other info |
8️⃣ Basic High Level Design
Client
|
v
Application Server
|
v
DatabaseCreate URL Flow
Client
|
POST /urls
|
v
Server
|
Generate Short Code
|
Store Mapping
|
v
Database
|
Return Short URLRedirect Flow
Client
|
GET /abc123
|
v
Server
|
Lookup Original URL
|
v
Database
|
Return Original URL
|
302 Redirect9️⃣ 301 vs 302 Redirect
301 Permanent Redirect
Client caches redirect.Future requests may never reach Bitly.
Pros
- Lower server cost
- Less traffic
Cons
- No analytics
- Harder monitoring
302 Temporary Redirect
Every request hits Bitly.
Pros
- Analytics tracking
- Monitoring
- Click counting
Cons
- Higher traffic
Interview Choice
302 Redirect ✅Reason:
Analytics and observability are valuable.
🔟 Deep Dive #1 - Generating Unique Short Codes
Option 1: URL Prefix
Take first few characters.
Example:
https://google.com
↓
https:Problem
Many URLs share same prefix.
https://twitter.com
https://facebook.comHigh collision rate.
❌ Reject
Option 2: Random Number + Base62
Generate:
Random NumberThen convert to:
Base62Characters:
0-9
A-Z
a-zTotal:
62 charactersWhy Base62?
6-character code:
62^6 ≈ 56 Billion combinationsProblem
Birthday Paradox
Even with 56 billion combinations:
1 Billion URLscan still produce collisions.
Solution
Before insert:
Generate Code
|
Check DB
|
Collision?If yes:
Generate AgainOption 3: Hash Long URL
SHA256(url)Then:
Base62 EncodeTake first:
6 charsProblem
Still collisions.
Same fix:
Check DB firstOption 4: Counter (Recommended)
Use:
1
2
3
4
...Convert using Base62. Example:
1 -> 1
10 -> A
61 -> z
62 -> 10Benefits
- Fast
- Unique
- No collision checks
Drawback
Predictable IDs Competitors can:
bit.ly/1
bit.ly/2
bit.ly/3
...and scrape links.
Solution
Use Bijective Function
Counter
|
Obfuscation
|
Base62Example library:
SqidsProduces:
fG8xT2
kL9pQ1instead of predictable values.
1️⃣1️⃣ Deep Dive #2 - Reducing Redirect Latency
Step 1: Database Indexing
Without index:
1 Billion rows
↓
Full ScanVery slow.
Use:
PRIMARY KEY(short_url)Database builds:
B-Tree IndexLookup becomes:
O(log N)Step 2: Redis Cache
Client
|
Server
|
Redis
|
DatabaseCache Structure
Key = Short URL
Value = Original URLExample:
abc123
↓
https://google.comRead Through Cache
Check RedisIf hit:
Return immediatelyIf miss:
Read DB
↓
Update Cache
↓
Return ResultEviction Policy
LRULeast Recently Used.
Old URLs automatically removed.
Step 3: CDN (Optional)
Store redirects at edge locations.
China User
|
China CDNinstead of
China User
|
California ServerTradeoff
Pros:
- Faster global latency
Cons:
- Lose analytics visibility
1️⃣2️⃣ Deep Dive #3 - Scaling
Estimate Traffic
Given:
100 Million DAUApprox:
10^8 usersSeconds/day:
10^5RPS:
10^8 / 10^5
≈ 10^3
≈ 1000 RPSPeak:
10k - 100k RPSScale Application Layer
Vertical Scaling
Bigger ServerMore CPU More Memory
Horizontal Scaling (Preferred)
+---- Server 1
Client -> LB
+---- Server 2
+---- Server 3Split Services
Instead of:
One MonolithUse:
API Gateway
|
+--> Read Service
|
+--> Write ServiceReason:
Reads >> WritesRedirect traffic dominates.
Auto Scaling
Scale based on:
CPU > 75%
Memory > 75%Add instances automatically.
1️⃣3️⃣ Scaling Counter Service
Problem:
Multiple Write ServersEach maintaining own counter.
Server A -> Counter = 10
Server B -> Counter = 10Collision!
Solution
Global Counter
Write Service
|
v
Redis CounterRedis command:
INCRBecause Redis is single-threaded:
1
2
3
4
5Guaranteed unique.
Optimization
Allocate batches:
Server A -> 1-1000
Server B -> 1001-2000Reduces Redis calls.
1️⃣4️⃣ Database Scaling
Storage estimate:
~500 bytes per rowFor:
1 Billion URLsStorage:
500 GBModern SSDs:
Multiple TBsSo:
Single DB is enough.If needed:
Sharding
Shard by:
short_urlExample:
hash(short_url) % NRoutes data to correct shard.
1️⃣5️⃣ High Availability
Redis Cache Failure
Not critical.
Cache Miss
↓
Database
↓
Rebuild CacheSystem still works.
Global Counter Failure
Critical. Need:
- Replication
- Snapshots
- Failover
Database Failure
Use:
Primary DB
|
Replica DBand
Hourly Snapshots
→ S3Recovery:
Replica Promotion
or
Restore SnapshotFinal Architecture
+----------------+
| API Gateway |
+----------------+
/ \
/ \
v v
+---------------+ +---------------+
| Read Service | | Write Service |
+---------------+ +---------------+
| |
| |
v v
+---------+ +------------+
| Redis | | Global |
| Cache | | Counter |
+---------+ +------------+
| |
+--------+--------+
|
v
+-------------+
| PostgreSQL |
+-------------+
|
v
Replica + BackupInterview Summary
Functional Requirements
✅ Create short URL
✅ Redirect users
✅ Custom Alias
✅ Expiration Time
Non-Functional Requirements
✅ Low Latency (<200ms)
✅ Scalability (100M DAU)
✅ Unique Short Codes
✅ High Availability
✅ Eventual Consistency
Key Technologies
- PostgreSQL
- Redis Cache
- Redis Global Counter (
INCR) - Base62 Encoding
- B-Tree Index
- API Gateway
- Horizontal Scaling
- Read/Write Service Separation
- Database Replication
- Snapshots/Backups