Lesson 1: Design a URL Shortener
TinyURL: Hashing, Key-Value Stores, Redirection.
Lesson 1: Design a URL Shortener
Goal: Design a service like TinyURL that takes a long URL and converts it into a short alias (e.g., http://tiny.url/xyz).
Requirements
Functional
shorten(long_url) -> short_urlredirect(short_url) -> long_url- Custom aliases (optional).
Non-Functional
- Highly Available: If the service is down, URL redirection stops working.
- Low Latency: Redirection must happen in milliseconds.
- Read-Heavy: 100:1 read-to-write ratio.
Core Design
1. Database Choice
Since we need fast lookups and the data model is simple (Key-Value), a NoSQL Key-Value Store (like DynamoDB or Redis) is ideal.
- Key:
short_alias - Value:
long_url
2. Hashing Algorithm
How do we generate the alias?
- MD5/SHA256: Too long.
- Base62 Encoding: Converts a unique ID (from a counter or database ID) into a string of characters [a-z, A-Z, 0-9].
🛠️ Sruja Perspective: Modeling the Flow
We can use Sruja to model the system components and the user scenario for redirection.
import { * } from 'sruja.ai/stdlib'
R1 = requirement functional "Shorten long URL"
R2 = requirement functional "Redirect short URL"
R3 = requirement availability "High availability for redirects"
R4 = requirement performance "Low latency (< 200ms)"
// Define the system boundary
TinyURL = system "TinyURL Service" {
WebServer = container "API Server" {
technology "Go"
scale {
min 3
max 20
metric "cpu > 70%"
}
}
DB = database "UrlStore" {
technology "DynamoDB"
description "Stores mapping: short_alias -> long_url"
}
Cache = container "Cache" {
technology "Redis"
description "Caches popular redirects"
}
WebServer -> Cache "Reads"
WebServer -> DB "Reads/Writes"
}
User = person "User"
// Define the redirection scenario (most common - cache hit)
RedirectFlowCacheHit = scenario "User clicks a short link (cache hit)" {
User -> TinyURL.WebServer "GET /xyz"
TinyURL.WebServer -> TinyURL.Cache "Check cache for 'xyz'"
TinyURL.Cache -> TinyURL.WebServer "Hit: 'http://example.com'"
TinyURL.WebServer -> User "301 Redirect (from cache)"
}
// Cache miss scenario
RedirectFlowCacheMiss = scenario "User clicks a short link (cache miss)" {
User -> TinyURL.WebServer "GET /xyz"
TinyURL.WebServer -> TinyURL.Cache "Check cache for 'xyz'"
TinyURL.Cache -> TinyURL.WebServer "Miss"
TinyURL.WebServer -> TinyURL.DB "Get long_url for 'xyz'"
TinyURL.DB -> TinyURL.WebServer "Return 'http://example.com'"
TinyURL.WebServer -> TinyURL.Cache "Cache the mapping"
TinyURL.WebServer -> User "301 Redirect to 'http://example.com'"
}
// URL shortening scenario
ShortenURL = scenario "User creates a short URL" {
User -> TinyURL.WebServer "POST /shorten with long_url"
TinyURL.WebServer -> TinyURL.WebServer "Generate base62 alias"
TinyURL.WebServer -> TinyURL.DB "Store mapping: alias -> long_url"
TinyURL.DB -> TinyURL.WebServer "Confirm stored"
TinyURL.WebServer -> User "Return short URL"
}
view index {
include *
}