Real-World Designs — Cheat Sheet
System Design · 6 topics. Download the PDF or the Instagram carousel and share it.
Design: URL Shortener
A URL shortener (like bit.ly) maps long URLs to short codes, stores the mapping in a database, and redirects users from the short URL to the original. Key challenges include unique ID generation, high-read throughput, and analytics.
- ✓Core: generate unique short code, store mapping, redirect with 301/302.
- ✓Base62 encoding of auto-increment ID is simplest — no collision, predictable length.
- ✓Read-heavy (100:1) — Redis cache with ~99% hit rate handles most redirects.
- ✓Analytics via async event streaming (Kafka) — never block the redirect path.
- ✓A 7-character base62 code supports 3.5 trillion URLs — more than enough for most systems.
// URL Shortener architecture
//
// Client: POST /api/shorten { url: "https://very-long-url.com/..." }
// │
// ▼
// ┌──────────────────┐
// │ API Service │ → generate short code → store in DB
// │ (stateless) │ → return short.ly/abc123
// └──────┬───────────┘
// │
// Client: GET short.ly/abc123
// │
// ▼
// ┌──────────────────┐ ┌──────────┐
// │ Redirect Service │────►│ Cache │ (Redis: shortCode → longURL)
// │ (stateless) │ │ (L1) │
// └──────────────────┘ └──────┬───┘
// │ cache miss
// ▼
// ┌──────────┐
// │ DB │ (DynamoDB / PostgreSQL)
// └──────────┘
//
// Response: HTTP 301 Location: https://very-long-url.com/...Design: Chat System
A real-time chat system (WhatsApp, Slack) requires persistent WebSocket connections, message ordering, delivery guarantees (sent/delivered/read), offline message storage, and group messaging.
- ✓WebSocket connections for real-time bidirectional communication; push notifications for offline users.
- ✓Message store (Cassandra) partitioned by conversation_id — write-optimised, time-ordered.
- ✓Presence service (Redis) tracks online/offline status via heartbeats.
- ✓Cross-server message routing via Redis pub-sub or internal message bus.
- ✓Delivery receipts (sent/delivered/read) require acknowledgement from client devices.
// Chat system architecture // // User A (sender) User B (receiver) // │ WebSocket ▲ WebSocket // ▼ │ // ┌─────────────┐ ┌─────────────┐ // │ WS Gateway │────────────────────────│ WS Gateway │ // │ (stateful) │ │ (stateful) │ // └──────┬──────┘ └──────▲──────┘ // │ │ // ▼ │ // ┌─────────────┐ ┌──────────┐ ┌──────────────┐ // │ Chat Service │───►│ Message │───►│ Message Fan- │ // │ │ │ Store │ │ Out Service │ // └──────┬──────┘ │(Cassandra)│ └──────┬───────┘ // │ └──────────┘ │ // ▼ ▼ // ┌─────────────┐ ┌──────────────┐ // │ Presence Svc │ │ Push Notif │ // │ (Redis) │ │ (FCM / APNs) │ // └─────────────┘ └──────────────┘ // Message flow: // 1. User A sends message via WebSocket // 2. Chat service validates, assigns message_id + timestamp // 3. Store in message DB // 4. Check if User B is online (presence service) // Online: forward via WebSocket gateway // Offline: queue push notification
Design: Notification Service
A notification service delivers messages to users via multiple channels (push, email, SMS, in-app). It must handle high throughput, user preferences, rate limiting, and reliable delivery with retries.
- ✓Decouple notification requests from delivery using message queues — producers are not blocked.
- ✓Multi-channel delivery (push, email, SMS, in-app) based on user preferences per notification category.
- ✓Priority queues ensure critical notifications (OTP, security) are never delayed by marketing.
- ✓Rate limiting prevents notification fatigue — configurable per channel and per user.
- ✓Retry with backoff + DLQ for reliable delivery; idempotency keys prevent duplicate sends.
// Notification service architecture // // Order Service ─┐ // Auth Service ──┤ Notification Request // Payment Svc ──┤ (user_id, type, data) // │ // ▼ // ┌──────────────┐ // │ Kafka Topic │ (notification-requests) // └──────┬───────┘ // │ // ▼ // ┌──────────────┐ // │ Notification │ 1. Look up user preferences // │ Service │ 2. Render template // │ │ 3. Route to channel queues // └──┬────┬───┬──┘ // │ │ │ // ▼ ▼ ▼ // Push Email SMS ← channel-specific queues // Queue Queue Queue // │ │ │ // ▼ ▼ ▼ // FCM/ Send- Twilio ← external providers // APNs Grid
Design: News Feed
A news feed (Facebook, Twitter/X) aggregates posts from followed users and ranks them for display. The core trade-off is fan-out on write (pre-compute feeds) vs fan-out on read (compute at request time).
- ✓Fan-out on write: fast reads, expensive writes — good for users with few followers.
- ✓Fan-out on read: cheap writes, slower reads — good for celebrities with millions of followers.
- ✓Hybrid approach: fan-out on write for regular users, fan-out on read for celebrities.
- ✓Feed ranking considers recency, engagement, relationship strength, and content type.
- ✓Redis sorted sets are ideal for pre-computed feed caches — scored by timestamp or ranking score.
// Fan-out on write (push model) // User posts → push to all followers' feed caches // // Alice (1000 followers) posts "Hello World" // → Write to 1000 feed caches (one per follower) // → Bob opens feed → read from pre-computed cache (fast!) // // Problem: Celebrity with 10M followers → 10M writes per post! 😱 // Fan-out on read (pull model) // User opens feed → fetch posts from all followed users → merge + rank // // Bob follows 500 users → opens feed // → Query 500 users' recent posts → merge → rank → return // → Slow if following many users // Hybrid (Twitter/X approach) // Regular users (< 10K followers): fan-out on write // Celebrities (> 10K followers): fan-out on read // // Bob's feed = pre-computed cache (regular follows) // + real-time merge (celebrity follows) // Feed cache (Redis sorted set per user) // Key: feed:bob // Members: post_ids, scored by timestamp ZADD feed:bob 1711700000 "post:123" ZADD feed:bob 1711699000 "post:456" ZREVRANGE feed:bob 0 19 // top 20 posts, newest first
Design: Distributed Cache
A distributed cache (Redis Cluster, Memcached) spreads cached data across multiple nodes using consistent hashing. It must handle cache invalidation, eviction, replication, and the thundering herd problem.
- ✓Distributed cache partitions data across nodes using consistent hashing (Redis: 16384 hash slots).
- ✓Each shard is replicated for fault tolerance — automatic failover if master dies.
- ✓Thundering herd: use mutex locks or staggered TTLs to prevent stampede on popular key expiry.
- ✓Hot keys: replicate across nodes, use local L1 cache, or split into multiple sub-keys.
- ✓Eviction (LRU) + TTL together bound both memory usage and staleness.
// Redis Cluster architecture // // Application Instances // │ │ │ // ▼ ▼ ▼ // ┌──────────────────────────────────────────┐ // │ Redis Cluster │ // │ │ // │ Shard 1 Shard 2 Shard 3 │ // │ slots 0-5460 slots 5461-10922 slots 10923-16383 // │ ┌────────┐ ┌────────┐ ┌────────┐ │ // │ │Master 1│ │Master 2│ │Master 3│ │ // │ └───┬────┘ └───┬────┘ └───┬────┘ │ // │ │ │ │ │ // │ ┌───▼────┐ ┌───▼────┐ ┌───▼────┐ │ // │ │Replica 1│ │Replica 2│ │Replica 3│ │ // │ └────────┘ └────────┘ └────────┘ │ // └──────────────────────────────────────────┘ // // Key routing: slot = CRC16(key) % 16384 // Client knows slot→node mapping → direct connection // If wrong node: MOVED redirect → client updates mapping
Design: Rate Limiter
A rate limiter service enforces request quotas per client using algorithms like token bucket or sliding window. It must be distributed (shared state via Redis), low-latency, and support tiered limits.
- ✓Rate limiter sits at the API gateway — checks Redis counters on every request.
- ✓Token bucket allows bursts; sliding window is more accurate but uses more memory.
- ✓Redis Lua scripts provide atomic check-and-increment for distributed rate limiting.
- ✓Support tiered limits per client plan (free, pro, enterprise) with configurable rules.
- ✓Return 429 with X-RateLimit-* and Retry-After headers for graceful client back-off.
// Rate limiter architecture
//
// Client Request
// │
// ▼
// ┌──────────────────┐
// │ API Gateway │
// │ ┌──────────────┐ │ ┌──────────────┐
// │ │ Rate Limiter │◄────►│ Redis │ (shared counters)
// │ │ Middleware │ │ └──────────────┘
// │ └──────┬───────┘ │ ┌──────────────┐
// │ │ │ │ Rules Config │ (rate limit rules)
// │ │ allowed? │ └──────────────┘
// │ ▼ │
// │ ┌──────────────┐ │
// │ │ Route to │ │
// │ │ Backend Svc │ │
// │ └──────────────┘ │
// └──────────────────┘
// Rate limiting rules (config)
{
"rules": [
{
"endpoint": "/api/v1/orders",
"method": "POST",
"limits": {
"free": { "requests": 10, "window": "1m" },
"pro": { "requests": 100, "window": "1m" },
"enterprise": { "requests": 1000, "window": "1m" }
}
},
{
"endpoint": "/api/v1/auth/login",
"limits": { "default": { "requests": 5, "window": "1m" } }
}
]
}