URL:- POST /shorten
Request:- {
"long_url": "https://example.com/abc",
"custom_alias": "myurl", // optional
"expiry": "2026-12-31" // optional
}
Response:-
{
"short_url" : "https://tinyurl.com/abc123"
}
URL: -GET /{short_code}
Response:- HTTP 301 Redirect -> Original URL
URL:- GET /analytics/{short_code}
Client -> Load Balancer -> API Servers -> Cache -> Database
Load Balancer
API Servers (Node.js)
Cache (Redis)
Database (MYSQL/NOSQL)
Redirect Flow
System is read-heavy. Cache is critical.
URL Generation
Approach - Auto Increment ID -> Base62 encoding
Example - ID = 125 -> "cb"
Problem: Predictable IDs
Sequencial IDs can be guessed.
Solution:
short_code = Base62(ID XOR random_salt)
Prevents enumeration attacks
Scalable Option:
Use Distributed ID Generator
timestamp + machine_id + sequence
Avoids bottleneck of single DB
CONCURRENT CREATES & COLLISION
Auto Increment ensures uniqueness
DB Gurantees atomic inserts
If using random codes
Problem: Collision Possible
Solution: UNIQUE Constraint + retry
REDIRECT Service
Flow:
Check Redis
If hit -> return
If miss -> Db lookup
Cache result
Return 301 Redirect
Why 301?
Cache Design (Redis)
Strategy - Cache Aside
Key Design
Key = url:{short_code}
value = long_url
Why Cache
Failure Handling
If Redis Fails
Fallback -> DB
Production Setup
DataBase Design (MYSQL)
Schema
CREATE TABLE urls (
id BIGINT PRIMARY KEY,
short_code VARCHAR(10) UNIQUE,
long_url TEXT,
created_at TIMESTAMP,
expiry TIMESTAMP
);
Optimization
SCALABILITY
API Layer
Sateless Node.js Servers behind load balancers
Database Scaling
Partition data using:
shard = hash(short_code) % N;
Each shard handles subset of data.
Writes -> Primary DB
Reads -> Replica DB
Reduces read pressure.
Cache Scaling
keys distributed across multiple nodes.
Increases memory + throughput
Global Scaling
Reduces latency for global users.
The system scales horizontally at each layer: stateless API servers, Redis Cluster for distributed caching, and database sharding with read replicas for handling large-scale traffic.
Fault Tolerance
Redis Failure
Generator Failure
Split Brain Handling
use machine_id in ID Generation
Traffic Spikes
System should:
use token bucket/ sliding window
Example -
INCR user_ip
EXPIRE 1 Sec
if:
Count > 100 -> reject request
Redirects = High Priority
Shorten API = Low Priority
Under load:
Reject POST /shorten
Allow GET redirect
If system overloaded:
Return:
503 Service Unavailable
Retry-After: 5 Seconds
Scale API Servers
Scale Redis Cluster
Scale DB Replicas
BURST HANDLING + BACKOFF
Problem:
Clients retry aggressively:
1000 failed requests -> retry instantly -> system collapse
Solution: Exponential Backoff + Jitter
Example:
Retry 1 -> Wait 1 Sec
Retry 2 -> Wait 2 Sec
Retry 3 -> Wait 4 Sec
Add randomness:
Wait = base + 2^n + random(0-100ms)
Why?
Prevents thundering herd problem
Server Hint
Return: 503 + Retry+After header
Analytics (ASYNC)
Do Not Update DB Per request
Solution
Flow
Redirect -> publish event -> process async -> batch update DB
Expiry & Data Management
Expiry Strategy
Scaling Data