Routes by IP/port. Faster, less overhead. Good for simple TCP traffic. Cannot inspect HTTP headers for smart routing.
Routes by URL path, headers, cookies. Slower per-request but enables content-based routing, SSL termination, rate limiting.
Returns multiple IPs for one hostname. Simple but no health awareness — clients may hit dead servers until DNS TTL expires.
ACID transactions, joins, schema enforcement. Best for financial data, user accounts, inventory where consistency matters.
Flexible schema, fast reads on primary key. Best for content catalogs, user profiles, IoT telemetry. Trade-off: no JOINs, weaker consistency.
In-memory, microsecond latency. Best for caching, session storage, real-time leaderboards. Data must fit in RAM.
Append-only log, persists to disk. Best for event streaming, log aggregation, clickstreams. Replays possible. Higher throughput but higher latency.
Smart broker, routing keys, exchanges. Best for task queues, RPC, workloads needing complex routing. Lower throughput than Kafka.
Fully managed, auto-scaling. SQS for simple queues, PubSub for pub/sub fan-out. No broker to manage. Vendor lock-in consideration.
Store blobs (images, videos, backups). 11 nines durability, cheap. Eventual consistency (read-after-write for PUT of new objects only).
Raw disk volumes attached to a VM. Low latency, persists independently. Used for databases, file systems. Limited to single-instance mount.
Shared NFS across instances. POSIX permissions. Good for shared file systems, media processing workflows. Higher latency than block.
| Style | Best For | Trade-offs |
|---|---|---|
| REST | CRUD APIs, resource-oriented | Over-fetching/under-fetching, multiple round-trips |
| GraphQL | Complex queries, mobile clients | Hard to cache, N+1 problem, complex rate limiting |
| gRPC | Service-to-service, streaming | Binary protocol (hard to debug), HTTP/2 required |
| WebSocket | Real-time bidirectional | Stateful — hard to scale horizontally |
Sacrifice availability during partitions. All nodes return same data or error. Examples: Zookeeper, etcd, HBase.
Sacrifice consistency during partitions. Nodes accept writes & return stale reads. Examples: Cassandra, DynamoDB, Riak.
Sacrifice partition tolerance. Cannot survive network splits. Examples: Single-node RDBMS.
DynamoDB: PA/EL (available during partitions, eventually consistent normally). Cassandra: PA/EL. MongoDB: CP/EC (consistent during partitions, consistent normally).
Maps both nodes and keys onto a hash ring. Each key is assigned to the next clockwise node. Adding/removing a node only reshuffles keys on its immediate neighbors — not the whole ring.
Each physical node is represented by N virtual nodes on the ring. Prevents hot spots — a heavy key range is spread across physical nodes. Trade-off: more metadata to store.
| Algorithm | Pros | Cons |
|---|---|---|
| Token Bucket | Burst-friendly, simple | Memory per user, needs tuning |
| Leaky Bucket | Smooth output, constant rate | No bursts allowed |
| Sliding Window Log | Precise, no boundary spikes | O(N) memory per user (timestamps) |
| Sliding Window Counter | Memory-efficient, precise enough | Slightly less accurate than log |
Implementation strategies: idempotency key (client-generated UUID in header), idempotent PUT (replace resource), idempotent DELETE (succeed even if already deleted). Payment APIs must be idempotent — never charge twice.
Decompose app into small, independent services. Each owns its data, communicates via API. Scales independently, enables polyglot tech stacks. Trade-off: distributed complexity, network latency, data consistency challenges.
Services communicate via events (Kafka, EventBridge). Decoupled producers/consumers. Excellent for async workflows, audit trails. Can be hard to debug (event flow across many services).
Separate read models from write models. Reads use optimized views (denormalized, cached), writes go through domain logic. Enables different scaling for reads vs writes. Adds eventual consistency complexity.
Chain of local transactions, each publishing events for the next step. On failure, execute compensating transactions. Choreography: each service listens and acts. Orchestration: central coordinator manages flow.
Wrapper around a remote call. After N failures, trips to OPEN state (fast-fail). After timeout, goes HALF-OPEN to test recovery. Prevents cascading failures, gives downstream time to recover.
Isolate resources (thread pools, connections) per service/endpoint. A failure in one bulkhead can't consume resources from another. Ship compartments analogy — one flooded section doesn't sink the whole ship.
Gradually replace a monolithic system by routing specific functionality to new microservices. Old and new coexist. Eventually the monolith is "strangled" — all traffic goes to new services.
Store all state changes as an append-only event log. Current state = replay all events. Enables audit trail, time travel, full rebuild. Storage grows unbounded — compaction/snapshots needed.
| Problem | Pattern | When To Use |
|---|---|---|
| Monolith too large | Strangler Fig | Can't rewrite, need incremental migration |
| Service depends on failing downstream | Circuit Breaker | External APIs, microservice calls |
| High read/write imbalance | CQRS | Reporting, dashboards vs transactional writes |
| One failure eats all resources | Bulkhead | Shared thread pools, connection pools |
| Distributed transaction needed | Saga | Multi-service order fulfillment, booking |
| Async decoupling needed | Event-Driven | Notifications, analytics pipeline |
| Factor | SQL | NoSQL |
|---|---|---|
| Schema | Fixed, enforced | Flexible, optional |
| ACID Transactions | Full support | Limited or none |
| Joins | Native, efficient | Application-side only |
| Horizontal Scale | Hard (sharding complex) | Built-in |
| Query Flexibility | SQL — rich queries | Limited by data model |
| Read Performance | Good with indexes | Excellent (key lookup) |
| Write Throughput | Limited by single node | Linear scaling |
One primary (writes), N replicas (reads). Async: possibly stale reads. Sync: slower writes but consistent reads. Handles read scaling well, writer is bottleneck.
Multiple nodes accept writes. Each replicates to others. Used in multi-DC deployments. Conflict resolution needed (last-write-wins, CRDTs, custom merge).
All nodes accept reads/writes (Cassandra). Quorum: R + W > N for consistency. Tunable: specify R and W per operation. Highest availability, lowest consistency.
Hash shard key → look up range. Even distribution, but range queries hit all shards. Re-sharding requires moving data (consistent hashing helps).
Data divided by key ranges (A-M, N-Z). Good for range scans, but hot spots if keys are not uniformly distributed (timestamps).
| Index Type | Best For | Cost |
|---|---|---|
| B-Tree | Range queries, equality, sorting | O(log N), default for most DBs |
| Hash | Point lookups (exact match) | O(1), no range queries |
| Bitmap | Low cardinality columns (gender, status) | Efficient for AND/OR of enums |
| Inverted | Full-text search | Large index, slow writes |
| LSM-Tree | Write-heavy workloads | Write-optimized, read amplification |
Core requirement: Shorten long URLs, redirect via 301/302. Scale: 100M URLs/day.
Key decisions: Base-62 encoding for short keys (7 chars = 3.5T combos). Write to DB (PostgreSQL/AWS Aurora), read from cache (Redis). Pre-generate keys to avoid collisions. 301 for permanent redirect (browser caches), 302 for analytics tracking.
Architecture: API Gateway → URL Service (generate/store) → DB + Cache. Redirect: Cache → fallback DB. Analytics: async Kafka → ClickHouse/AWS Athena.
Core requirement: Real-time messaging, 2B+ users, delivery status, media sharing. Key challenges: End-to-end encryption, low latency, exactly-once delivery.
Architecture: WebSocket for real-time delivery. Message stored in Cassandra (write-optimized). Media goes to object store (S3/CDN). Presence via Redis. Group chats fan-out: small groups → fan-out on write; large groups → fan-out on read (pull model).
Delivery semantics: Each message gets a server-assigned ID. Client acks via sequence numbers. Missed messages synced on reconnection.
Core requirement: Upload, process, and stream videos at scale. 500h/minute uploaded.
Pipeline: Upload → object store (S3) → encoding queue (Kafka + workers) → segmented storage (DASH/HLS: .ts segments at multiple bitrates). CDN serves segments to viewers.
Key patterns: Async upload pipeline (durability > speed). Adaptive bitrate (client switches quality based on bandwidth). Pre-warm popular content on CDN edge. Geo-distributed caching — serve from nearest POP.
Core requirement: Match riders with nearby drivers in real-time, handle surge pricing, ETA prediction.
Key challenge: Geospatial indexing (find drivers within 1 mile of rider). Solution: Geohash / QuadTree / S2 Geometry. Each cell in grid has list of active drivers.
Architecture: Rider app → dispatch service (geospatial index) → match service → driver app. Kafka for ride lifecycle events. Redis for real-time driver locations (5s heartbeat). Google S2 Library for geohash. Surge pricing: demand/supply ratio per geohash cell, recalculated every N minutes.
Core requirement: 500M tweets/day, show relevant tweets from followed users. Key decision: Fan-out on write (pre-compute timeline) vs fan-out on read (compute on request).
Hybrid approach: Active users (majority): fan-out on write → pre-populated timeline in Redis sorted set (latest tweet IDs). Celebrities: fan-out on read (too many followers to write to each).
Storage: Tweet content → Cassandra (keyed by tweet ID). Timeline → Redis (sorted sets, per user). Social graph → FlockDB/Graph DB (follows/followers). Search → Elasticsearch.
Core requirement: 300M+ customers, 350M+ products. Product catalog, shopping cart, order processing, payment, fulfillment.
Architecture (SOA → Microservices): Product Service, Cart Service, Order Service, Payment Service, Recommendation Engine. Each service owns its data store. Async via SQS/Kafka for decoupled workflows (payment → fulfillment → shipping).
Key patterns: CQRS (read product catalog from denormalized views). Event Sourcing (order state changes as event stream). Materialized Views (product search index). Read replicas for catalog (read-heavy).
| Approach | What | When | Limits |
|---|---|---|---|
| Vertical | Bigger machine (more CPU/RAM) | Quick fix, simple apps | Hardware cap, expensive at scale |
| Horizontal | More machines behind a load balancer | Stateless apps, web tier | State management complexity |
| Sharding | Split data across DB instances | DB write throughput limit | Cross-shard queries, resharding |
| Read Replicas | Async replicas for read scaling | Read-heavy workloads | Stale reads, replication lag |
| Caching | Store hot data in faster layer | Read-heavy, repetitive queries | Cache invalidation, stale data |
Readiness probe (is service ready for traffic?) + Liveness probe (is service alive?). LB auto-detaches unhealthy instances.
When a dependency fails, degrade the feature rather than show an error. E.g., show cached recommendations if ML service is down.
Proactively inject failures (kill instances, add latency, network partitions) to verify the system recovers. Netflix Chaos Monkey is the canonical example.
Aggregated numerical data. Latency (p50/p99), error rate, throughput, saturation. Prometheus + Grafana.
Structured log events with severity, correlation IDs, and context. ELK Stack (Elastic, Logstash, Kibana) or Loki for log aggregation.
End-to-end request lifecycle across services. OpenTelemetry + Jaeger/Zipkin. Shows where time is spent and where errors occur.
Theoretical foundation. Proposer → Acceptors → Learners. Two phases: prepare (promise) and accept (commit). Correct but famously hard to implement correctly.
Designed for understandability. Leaders, logs, term numbers. Leader election (heartbeats + timeouts). Log replication (leader pushes to followers). Etcd, Consul use Raft.
Leader-based, atomic broadcast order. Used by Zookeeper for coordination. Global leader election via FastLeaderElection. ZXID for ordering.
| Pattern | Consistency | Performance | Complexity |
|---|---|---|---|
| 2PC (Two-Phase Commit) | Strong | Slow (blocking) | Medium |
| 3PC (Three-Phase Commit) | Strong | Slower | High |
| Saga | Eventual | Fast | Medium |
| 2PC + Compensation | Strong eventual | Medium | High |
Logical counters: each node increments on events. C(a) < C(b) means a happened before b. But C(a) < C(b) and C(b) < C(a) means concurrent — no causality info.
Each node tracks its view of all others' clocks. V(a) < V(b) (all components ≤) means causal relationship. Incomparable vectors = concurrent changes (conflict detection). Used in Dynamo/Cassandra.
| Strategy | How It Works | Best Use |
|---|---|---|
| Cache-Aside | App checks cache first. Miss → read from DB → populate cache. | Read-heavy workloads, general purpose |
| Read-Through | Cache is authoritative. Cache reads from DB on miss. | When cache can manage its own DB fallback |
| Write-Through | Write to cache, cache writes to DB synchronously. | Read consistency + write reliability |
| Write-Behind | Write to cache immediately, async write to DB. | Write-heavy, can tolerate DB lag |
| Write-Around | Write directly to DB, invalidate cache. Next read populates. | Write-once, read-rarely data |
Simplest: set a time-to-live. Cache auto-expires. Trade-off: stale data until TTL expires. Best for data that tolerates staleness (profiles, product catalogs).
On write, delete the cached entry. Next read repopulates. Simple but creates "cold start" on each write.
On write, update both DB and cache atomically. Consistent but more complex — cache write can fail separately from DB write.
How CDNs work: Geo-distributed proxy servers cache static content (images, CSS, JS, video) at edge locations closest to users. User DNS resolves to nearest edge server (via anycast or GeoDNS).
Key concepts: Pull CDN (edge fetches from origin on cache miss — simpler) vs Push CDN (origin uploads content to CDN nodes). Cache hit ratio = percentage of requests served from edge (90%+ is good). Tiered caching: L1 (edge) → L2 (regional) → origin.
Popular CDNs: CloudFront (AWS), Cloudflare, Akamai, Fastly. Key differentiators: edge compute (Cloudflare Workers, Lambda@Edge) for dynamic content at the edge.
Functional: What does the system do? "Design Twitter" → post tweets, follow users, view timeline, search. Ask specifically about features — don't assume.
Non-functional: DAU/MAU estimate, latency (real-time vs eventual), consistency requirements, durability (data loss acceptable?), availability SLA.
Scale: "How many users?" "How many writes per day?" "How many reads per write?" Estimate traffic before designing.
Constraints: Budget, team size, timeline? (Unlikely to matter in interviews but worth asking.)
Draw the boxes: Client → CDN/API Gateway → Load Balancer → Web Tier (stateless) → App Tier → Data Tier.
Data flow: Trace the primary user flow. "User posts a tweet → goes to API → write to DB → fan-out to followers → cache updated."
Choose the right data stores: PostgreSQL for transactions, Cassandra for write-heavy, Redis for caching, S3 for blobs, Elasticsearch for search.
Mention key technologies by name: "Kafka for async decoupling, Redis sorted sets for timeline, Cassandra for tweet storage."
Pick the hardest part: For Twitter → "Let's deep dive on the timeline generation. Fan-out on write for active users, fan-out on read for celebrities. Here's how Redis sorted sets work..."
Trade-offs: "Fan-out on write means faster reads but N writes per tweet. That's why we cap followers at 500 for pre-computation and handle the rest at read time."
Scale numbers: "With 500M tweets/day = ~6K writes/second. Timeline reads: 400M DAU reading ~30 timelines/day = 140K reads/second. We need Redis cache (100M timelines fits in ~200GB RAM)."
Summarize: "We designed a Twitter-like system using hybrid fan-out, Redis timeline cache, Cassandra for durable storage, Kafka for async processing."
What would you change for different constraints? "If consistency was critical, I'd use PostgreSQL instead of Cassandra. If we had fewer resources, I'd start with a monolith and extract services one by one (Strangler Fig)."
Alternative approaches: "An alternative is fully serverless — API Gateway + Lambda + DynamoDB for the MVP. Scales automatically, zero ops, but higher per-request cost at scale."
| Operation | Time | Notes |
|---|---|---|
| L1 cache reference | 0.5 ns | CPU level 1 cache |
| RAM access | 100 ns | Main memory |
| SSD random read | 150 μs | ≈ 1000× slower than RAM |
| Disk seek | 10 ms | HDD — avoid for random reads |
| Redis in-memory get | 500 μs | Network + round-trip |
| PostgreSQL query (indexed) | 5–20 ms | Depends on data size |
| Full table scan (1M rows) | 500 ms | Only for analytics, never in path |
| HTTP API call (service-to-service) | 50–200 ms | Includes serialization, network |
| Disk sequential write | 50 MB/s | HDD; SSD ≈ 500 MB/s |
| Network: same DC | 0.5 ms | Within a data center |
| Network: cross-region | 50–100 ms | US West → Europe |
| Trade-off | Choose A if... | Choose B if... |
|---|---|---|
| Consistency vs Availability | Financial transactions, inventory | Content delivery, social feeds |
| Latency vs Throughput | Real-time chat, gaming | Batch processing, analytics |
| Monolith vs Microservices | Small team, simple domain | Large team, independent deploy needed |
| SQL vs NoSQL | Joins, ACID, complex queries | Scale, flexible schema, high write throughput |
| Push vs Pull (event delivery) | Real-time needed, small consumer count | Many consumers, variable load |
| Sync vs Async processing | Immediate result needed | User doesn't need to wait |
Approach: Inspired by DynamoDB/Cassandra. Consistent hashing on the key ring, each node responsible for a range. Replication factor 3 → each key stored on 3 consecutive nodes. Read quorum (R=2), Write quorum (W=2) for strong consistency. Hinted handoff for temporary failures (neighbors accept writes until node recovers). Merkle trees for anti-entropy (detect and repair inconsistencies).
Trade-offs: Eventual consistency by default, tunable for stronger guarantees (R+W > N). Write is fast (no coordinator). Complexity: node addition/removal triggers data migration.
Approach: Token bucket per user/IP/API key. Redis sorted sets for sliding window. Lua script in Redis for atomic increment + TTL. Distributed: use Redis cluster, consistent hashing by user ID so each user's counter is on one node.
Error handling: 429 Too Many Requests with Retry-After header. Client throttling (local cache of remaining quota from X-RateLimit-* headers).
Storage estimate: For 100M users tracking 1 bucket each: 100M * (userID + counter + TTL) ≈ 5GB in Redis. Trivially fits on one node with replication.
Approach: Notification Service (API) → Preference Service (filter by channel/opt-in) → Channel Workers (Email, SMS, Push, In-App). Kafka between stages for decoupling and durability.
Key challenges: Delivery guarantees: at-least-once (dedup via idempotency keys). Batching: aggregate notifications per user ("3 new likes" not "like, like, like"). Template rendering: notification templates + user-specific variables (pre-rendered vs on-demand).
Scale: 10M push notifications/day → ~120/s, easily handled by a few workers. Email and SMS are slower (third-party APIs), so queue depth matters — monitor and scale workers.
Approach: URL Frontier (priority queue) → DNS Resolver → Fetcher (HTTP client) → Parser → Link Extractor → Content Storage. RabbitMQ/Kafka for frontier URL distribution among fetchers.
Politeness: Rate-limit per domain (don't hammer a single site). Robots.txt compliance. Cache DNS lookups (aggressive DNS rate is a problem).
Deduplication: URL seen set (Bloom filter + RocksDB for persistence). 10B URLs → Bloom filter with 1% false positive: ~12GB memory. Canonicalize URLs (normalize trailing slashes, lowercase scheme/host).
Approach: Geohash / QuadTree / S2 Geometry. Geohash: encode lat/lng into string, same prefix = nearby. Query adjacent geohash cells. S2 (used by Google/Uber): 64-bit integer cell IDs, hierarchical spatial indexing.
Data model: Redis GEOADD (for real-time locations with expiry). Or: Cassandra with geohash as partition key (for persistent location history).
Federated approach: Partition the world into grid cells. Each cell's data lives on a shard. Growing cell (city center) → subdivide into smaller cells. Read: given user's lat/lng → find cell → query cell's shard.
ACID
Atomicity, Consistency, Isolation, Durability. Properties of database transactions. Ensures reliable processing even with failures.
BASE
Basically Available, Soft state, Eventual consistency. The NoSQL alternative to ACID — relaxed consistency for higher availability.
Bloom Filter
Probabilistic data structure. Tells you "definitely not in set" or "maybe in set." Space-efficient for dedup at scale. False positives possible, never false negatives.
CDN
Content Delivery Network. Geo-distributed proxy servers that cache and serve static content from edge locations closest to users. Reduces latency and origin load.
CLH
Consistent Hashing. Distributes keys across nodes with minimal reshuffling when nodes join/leave. Uses a hash ring and virtual nodes for balance.
CRDT
Conflict-free Replicated Data Type. Data structure that converges automatically across replicas without coordination. Examples: Grow-only Counters, LWW-Register, OR-Set.
Gossip Protocol
Each node periodically tells others what it knows. Over time, all nodes converge. Used for failure detection, membership (Cassandra), and state dissemination.
HDFS
Hadoop Distributed File System. Splits files into large blocks (128MB), replicates across nodes. Designed for batch processing, not low-latency access.
HSM
Hot, Warm, Cold storage tiers. Data moves based on access frequency. Reduces cost — frequently accessed (hot) on fast storage, archival (cold) on cheap object storage.
Leader Election
Process by which distributed nodes choose one as the leader. Leaders handle writes, coordination. Zookeeper/etcd use Paxos/Raft for this.
MapReduce
Programming model for distributed data processing. Map (transform/filter) → Shuffle (sort/group) → Reduce (aggregate). Used by Hadoop, Spark (more general).
P99 Latency
The 99th percentile latency — 99% of requests complete at or below this time. Critical SLO metric; the "tail at scale" problem (one slow request slows many).
Quorum
Minimum number of nodes that must agree on a read/write in a distributed system. R + W > N for strong consistency. Higher quorum = slower but more consistent.
Sharding
Splitting a database across multiple nodes (horizontal partitioning). Each shard holds a subset of the data. Enables write scaling. Complex: joins, rebalancing, hot spots.
SPOF
Single Point of Failure. A component whose failure causes the entire system to fail. Eliminated through redundancy, load balancing, and failover mechanisms.
Thundering Herd
When many clients simultaneously request a resource that just expired from cache, causing a stampede to the origin. Solution: lock/mutex around cache repopulation, pre-warming.
System Design Handbook — Building Blocks to Complex Architectures
Built for interview prep and real-world reference. Last updated July 2026.