Toolmingo
Guides24 min read

50 System Design Interview Questions and Answers (2025)

Top 50 system design interview questions with detailed answers covering scalability, databases, caching, load balancing, microservices, and distributed systems.

System design interviews test your ability to architect large-scale distributed systems. Unlike coding interviews with clear right/wrong answers, system design is open-ended — interviewers evaluate your thought process, trade-offs, and depth of knowledge. This guide covers the 50 most common questions with detailed answers.

Quick Reference: System Design Interview Framework

Step Action Time
1. Clarify requirements Functional + non-functional reqs 5 min
2. Estimate scale Users, QPS, storage, bandwidth 5 min
3. High-level design Core components, API 10 min
4. Deep dive Critical components, bottlenecks 15 min
5. Wrap up Trade-offs, failure modes, improvements 5 min

Fundamentals

1. What is the CAP theorem?

The CAP theorem states that a distributed system can guarantee at most two of three properties simultaneously:

  • Consistency (C): Every read returns the most recent write
  • Availability (A): Every request receives a response (not guaranteed to be latest)
  • Partition tolerance (P): System continues operating despite network partitions

In practice, network partitions are unavoidable, so systems choose between CP (consistent but may be unavailable) or AP (available but may return stale data).

System Choice Example
HBase, ZooKeeper CP Banking, financial
Cassandra, DynamoDB AP Shopping carts, DNS
Traditional RDBMS CA (single node) Not truly distributed

2. What is the difference between horizontal and vertical scaling?

Vertical scaling (scale up): Add more resources (CPU, RAM, disk) to an existing server.

  • Pros: Simple, no application changes
  • Cons: Has hard limits, single point of failure, expensive at high end

Horizontal scaling (scale out): Add more servers to distribute load.

  • Pros: Near-unlimited scale, redundancy, cost-effective
  • Cons: Application must handle distributed state, session management

Most modern systems prefer horizontal scaling with stateless services and shared state in databases/caches.

3. What are the key non-functional requirements to clarify?

Always ask:

  • Scale: Daily active users, requests per second
  • Availability: 99.9% = 8.7h/yr downtime; 99.99% = 52 min/yr
  • Latency: P50, P95, P99 response time targets
  • Consistency: Strong vs eventual consistency
  • Durability: Can data be lost? RPO (Recovery Point Objective)
  • Geography: Single region or global?

4. How do you estimate system capacity?

Use back-of-envelope math:

100M DAU × 10 requests/day = 1B req/day
= ~12,000 req/sec average
= ~60,000 req/sec peak (5× average)

Storage: 1B requests × 1KB payload = 1TB/day
= 30TB/month, 360TB/year

Key numbers to memorize:

  • Disk read: 100MB/s (HDD), 500MB/s (SSD)
  • Network: 1Gbps = 125MB/s
  • RAM: 32GB typical server
  • MySQL: ~1,000 QPS simple queries

5. What is eventual consistency and when should you use it?

Eventual consistency means all replicas will converge to the same value — eventually. Reads may return stale data immediately after a write.

Use when:

  • High availability is critical
  • Users can tolerate brief inconsistency
  • Examples: social media feeds, product catalog, DNS, shopping cart

Use strong consistency when:

  • Financial transactions
  • Inventory counts
  • Authentication tokens

Load Balancing

6. What are the main load balancing algorithms?

Algorithm Description Best For
Round Robin Rotate requests sequentially Homogeneous servers
Weighted Round Robin Weight by server capacity Mixed server specs
Least Connections Route to server with fewest active connections Long-lived connections
IP Hash Hash client IP to server Session persistence
Least Response Time Route to fastest server Performance-sensitive
Random Random server selection Simple stateless services

7. What is the difference between L4 and L7 load balancing?

L4 (Transport layer): Routes based on IP/TCP/UDP. Fast, no content inspection.

  • Used for: high-throughput TCP traffic, when content routing isn't needed

L7 (Application layer): Routes based on HTTP headers, URLs, cookies. More flexible.

  • Route /api/* to API servers, /static/* to file servers
  • Can terminate SSL/TLS
  • Cookie-based session affinity

Most modern systems use L7 (nginx, HAProxy, AWS ALB).

8. How do you achieve zero-downtime deployments?

Blue-Green Deployment:

  • Two identical environments (blue = live, green = new)
  • Deploy to green, test, then switch traffic
  • Instant rollback by switching back

Canary Deployment:

  • Route small % of traffic (1-5%) to new version
  • Monitor metrics, gradually increase
  • Roll back if errors spike

Rolling Deployment:

  • Replace instances one at a time
  • Load balancer routes around unhealthy instances

Databases

9. When should you use SQL vs NoSQL?

Use SQL when:

  • Complex queries, JOINs, aggregations
  • ACID transactions required
  • Schema is stable and well-defined
  • Examples: banking, e-commerce orders, ERP

Use NoSQL when:

  • Flexible/evolving schema
  • Extreme write/read throughput
  • Horizontal sharding required
  • Examples: user profiles, product catalogs, logs, IoT data
NoSQL Type Examples Best For
Document MongoDB, DynamoDB JSON-like hierarchical data
Key-Value Redis, DynamoDB Caching, sessions, leaderboards
Wide Column Cassandra, HBase Time series, logs, analytics
Graph Neo4j, Amazon Neptune Social graphs, recommendations

10. What is database sharding?

Sharding splits data across multiple database instances. Each shard holds a subset of rows.

Sharding strategies:

Horizontal (row-based):
  Shard 1: user_id 1-1M
  Shard 2: user_id 1M-2M
  
Hash-based:
  shard = hash(user_id) % num_shards
  
Directory-based:
  Lookup table maps key → shard location

Trade-offs:

  • Pros: Scales writes and storage horizontally
  • Cons: Cross-shard queries are expensive, rebalancing is hard, loses JOIN capabilities

11. What is database replication and what are the patterns?

Master-Slave (Primary-Replica):

  • All writes go to master
  • Reads distributed across replicas
  • Async or sync replication
  • Cons: replica lag, manual failover

Master-Master:

  • Writes accepted by multiple nodes
  • Conflict resolution required
  • Higher complexity

Multi-Region:

  • Replicas in multiple geographic regions
  • Latency-optimized reads
  • Strong consistency hard to achieve globally

12. What is an index and when should you add one?

An index is a data structure (B-tree or hash) that speeds up data retrieval at the cost of additional storage and slower writes.

Add indexes on:

  • Primary keys (automatic)
  • Foreign keys
  • Columns used in WHERE clauses
  • Columns used in ORDER BY / GROUP BY
  • High-cardinality columns

Don't index:

  • Low-cardinality columns (boolean, enum with few values)
  • Tables with very high write rates
  • Small tables (full scan may be faster)
-- Composite index: order matters (leftmost prefix rule)
CREATE INDEX idx_user_status_created ON orders(user_id, status, created_at);

-- This query uses the index:
SELECT * FROM orders WHERE user_id = 1 AND status = 'pending';

-- This does NOT fully use it (skips user_id):
SELECT * FROM orders WHERE status = 'pending';

13. How does database connection pooling work?

Creating a new DB connection is expensive (~100ms). Connection pools maintain a set of reusable connections.

Application → Connection Pool (10-100 connections) → Database
  • Pool size: typically 2× CPU cores for CPU-bound workloads
  • Too small: requests queue waiting for connection
  • Too large: DB overwhelmed, context switching overhead

Tools: PgBouncer (PostgreSQL), ProxySQL (MySQL).


Caching

14. What are the main caching strategies?

Strategy Description When to Use
Cache-aside (Lazy) App checks cache first; on miss, loads from DB and populates cache Read-heavy, cache failures are tolerable
Write-through Write to cache and DB synchronously Data must always be consistent
Write-behind (Write-back) Write to cache, async flush to DB Write-heavy, some data loss acceptable
Read-through Cache loads from DB automatically on miss Transparent caching

Cache-aside is most common:

def get_user(user_id):
    cached = cache.get(f"user:{user_id}")
    if cached:
        return cached
    
    user = db.query("SELECT * FROM users WHERE id = ?", user_id)
    cache.set(f"user:{user_id}", user, ttl=3600)
    return user

15. What is cache eviction and what are the policies?

When cache is full, eviction removes entries to make room:

Policy Description Best For
LRU (Least Recently Used) Remove least recently accessed General purpose
LFU (Least Frequently Used) Remove least accessed overall Stable hot-key workloads
FIFO Remove oldest entry Simple, ordered data
TTL (Time-to-Live) Remove after expiry Data with known freshness
Random Remove random entry Simple, low overhead

Redis default: LRU with maxmemory-policy allkeys-lru.

16. What is cache stampede and how do you prevent it?

Cache stampede (dogpile effect): When a cached item expires, many concurrent requests simultaneously miss the cache and all hit the database.

Solutions:

# 1. Mutex lock - only one request populates cache
def get_data(key):
    value = cache.get(key)
    if value: return value
    
    lock = cache.lock(f"lock:{key}", timeout=10)
    if lock.acquire(blocking=False):
        try:
            value = db.fetch(key)
            cache.set(key, value, ttl=300)
        finally:
            lock.release()
    else:
        time.sleep(0.1)  # wait for lock holder
        value = cache.get(key)
    return value

# 2. Probabilistic early expiry (XFetch algorithm)
# Recompute before expiry with probability based on cost

# 3. Background refresh - refresh cache before it expires

17. What is a CDN and when should you use it?

A Content Delivery Network (CDN) caches static assets (images, CSS, JS, videos) at edge nodes geographically close to users.

Use CDN for:

  • Static assets (images, CSS, JS)
  • Large file downloads
  • Video streaming
  • API responses that are globally cacheable

Benefits:

  • Reduced latency (edge is 10-50ms vs origin 100-300ms)
  • Reduced origin server load
  • DDoS protection (absorbs traffic at edge)
  • High availability

Examples: Cloudflare, AWS CloudFront, Fastly.


Messaging and Event Systems

18. What is a message queue and when should you use it?

A message queue decouples producers from consumers and enables async processing.

Use message queues for:

  • Async work (email sending, image processing, notifications)
  • Absorbing traffic spikes (queue buffers load)
  • Reliable delivery with retry
  • Decoupling services
User creates order
  → Order Service publishes to queue
  → Email Service consumes: send confirmation
  → Inventory Service consumes: reserve stock
  → Analytics Service consumes: record event

19. What is the difference between Kafka and RabbitMQ?

Feature Kafka RabbitMQ
Model Log-based (pull) Queue-based (push)
Retention Retain messages on disk Delete after ack
Replay Yes — reread from offset No
Order Guaranteed per partition Not guaranteed (without extra config)
Throughput Millions/sec Thousands/sec
Use case Event streaming, analytics Task queues, RPC
Consumers Multiple groups read same messages Competing consumers consume once

20. What is the fan-out problem and how do you solve it?

Fan-out problem: When one event must be delivered to millions of recipients (e.g., tweet from celebrity with 50M followers).

Solutions:

  • Push model: Write to each follower's feed (write-heavy, read is fast)

    • Problem: Posting takes seconds for celebrities
  • Pull model: Each user fetches followed accounts' posts at read time (read-heavy)

    • Problem: Slow reads, many DB queries
  • Hybrid model: Pull for high-follower accounts, push for low-follower accounts

    • Celebrity tweets are fetched on read; regular user tweets are pushed

Twitter uses this hybrid approach.


Microservices and API Design

21. What are the trade-offs between monolith and microservices?

Monolith Microservices
Development speed Fast initially Fast at scale with many teams
Deployment Deploy entire app Deploy independently
Scaling Scale whole app Scale individual services
Debugging Easy (single process) Complex (distributed tracing)
Data Shared DB, simple transactions Each service owns its data
Team Single team Multiple autonomous teams
When to use Early stage, small team 50+ engineers, product-market fit

Start with a monolith; extract services when team/scale demands it.

22. How do microservices communicate?

Synchronous (request-response):

  • REST over HTTP: Simple, widely understood
  • gRPC: Binary protocol, type-safe, streaming, 10× faster than REST
  • GraphQL: Flexible queries, reduces over-fetching

Asynchronous (event-driven):

  • Message queues (Kafka, RabbitMQ): Decoupled, async
  • Event streaming: One publisher, many consumers

When to use which:

  • Sync: User-facing reads that need immediate results
  • Async: Background tasks, notifications, cross-service updates

23. What is the API Gateway pattern?

An API Gateway is a single entry point for all client requests that handles:

  • Authentication and authorization
  • Rate limiting
  • Request routing to backend services
  • SSL termination
  • Request/response transformation
  • Logging and monitoring
  • Circuit breaking
Client → API Gateway → Service A
                     → Service B  
                     → Service C

Examples: AWS API Gateway, Kong, nginx, Envoy.

24. What is a circuit breaker pattern?

Problem: When a downstream service is slow/down, callers accumulate slow requests, exhausting thread pools — cascading failure.

Circuit Breaker monitors failures and "opens" the circuit to fail fast:

CLOSED (normal) → failures exceed threshold → OPEN (fail fast)
OPEN (fail fast) → timeout expires → HALF-OPEN (test)
HALF-OPEN → success → CLOSED | failure → OPEN
class CircuitBreaker:
    def __init__(self, failure_threshold=5, timeout=60):
        self.state = "CLOSED"
        self.failures = 0
        self.threshold = failure_threshold
        self.opened_at = None
        
    def call(self, fn):
        if self.state == "OPEN":
            if time.time() - self.opened_at > self.timeout:
                self.state = "HALF-OPEN"
            else:
                raise Exception("Circuit open")
        
        try:
            result = fn()
            if self.state == "HALF-OPEN":
                self.state = "CLOSED"
                self.failures = 0
            return result
        except Exception:
            self.failures += 1
            if self.failures >= self.threshold:
                self.state = "OPEN"
                self.opened_at = time.time()
            raise

25. What is service discovery?

Service discovery allows services to find each other's network locations dynamically without hardcoded IPs.

Client-side discovery: Client queries registry (Consul, Eureka), gets list of instances, load balances itself.

Server-side discovery: Client calls load balancer; load balancer queries registry.

In Kubernetes, DNS-based service discovery is built-in:

http://payment-service.default.svc.cluster.local:8080

Storage Systems

26. How would you design a distributed file storage system?

High-level components (similar to Amazon S3):

Client → API Layer → Metadata Store (object ID → location)
                   → Storage Nodes (chunked data)
                   → Replication Manager

Key decisions:

  • Chunk size: 64MB (GFS/HDFS default) — balance between metadata size and overhead
  • Replication factor: 3 copies for durability
  • Consistency: Usually eventual — write to leader, async replicate
  • Erasure coding: More space-efficient than 3× replication for cold storage

27. What is consistent hashing?

Problem: When adding/removing servers in a hash ring, standard hashing requires redistributing almost all data.

Consistent hashing: Servers and keys are mapped to a ring (0 to 2³²). Each key is assigned to the next clockwise server.

Ring: 0 ────── Server A ──── Server B ──── Server C ──── 2³²
                   ↑                ↑
               key "foo"       key "bar"

When a server is added/removed, only keys in that arc are remapped (~K/N keys, where K = keys, N = servers).

Virtual nodes: Each physical server has 100-200 virtual positions on the ring for better load distribution.

Used by: Cassandra, DynamoDB, Memcached.


Classic System Design Questions

28. Design a URL shortener (like bit.ly)

Requirements:

  • Shorten URLs (7 character alias)
  • Redirect short URL → original in < 10ms
  • 100M shortened URLs/day, 10B reads/day

Core design:

POST /shorten → generate 7-char base62 ID → store in DB
GET /{alias}  → cache lookup → DB lookup → 301 redirect

ID generation:

  • Counter-based (auto-increment): simple, sequential, guessable
  • Hash (MD5 first 7 chars): collision risk
  • Nanoid/UUID: random, unique

Data model:

CREATE TABLE urls (
  alias VARCHAR(7) PRIMARY KEY,
  original_url TEXT NOT NULL,
  created_at TIMESTAMP,
  expires_at TIMESTAMP,
  user_id BIGINT
);

Scale: Cache popular URLs in Redis (80% of traffic = 20% of URLs). Cache read-through with 24h TTL.

29. Design a rate limiter

Requirements: Limit each user to N requests per time window.

Algorithms:

Algorithm Pros Cons
Fixed window Simple Burst at window boundaries
Sliding window log Accurate Memory: O(requests)
Sliding window counter Accurate, O(1) space Slightly approximate
Token bucket Allows controlled bursts Complex
Leaky bucket Smooth output rate No bursting

Token bucket implementation (Redis):

-- Redis Lua script (atomic)
local key = KEYS[1]
local rate = tonumber(ARGV[1])
local capacity = tonumber(ARGV[2])
local now = tonumber(ARGV[3])

local bucket = redis.call('HMGET', key, 'tokens', 'last_refill')
local tokens = tonumber(bucket[1]) or capacity
local last_refill = tonumber(bucket[2]) or now

-- Refill tokens based on elapsed time
local elapsed = now - last_refill
tokens = math.min(capacity, tokens + elapsed * rate)

if tokens >= 1 then
    tokens = tokens - 1
    redis.call('HMSET', key, 'tokens', tokens, 'last_refill', now)
    redis.call('EXPIRE', key, 3600)
    return 1  -- allowed
else
    return 0  -- rejected
end

30. Design a notification system

Requirements: Send push, email, SMS notifications to 100M users.

Architecture:

Event producers → Message Queue (Kafka) → Notification Service
                                        → Push Notification (FCM/APNs)
                                        → Email (SendGrid/SES)
                                        → SMS (Twilio)

Key decisions:

  • Deduplication: Use idempotency keys to prevent duplicate sends
  • Priority queues: Urgent (security alerts) vs normal (marketing)
  • User preferences: Store notification settings per channel per user
  • Retry logic: Exponential backoff with dead-letter queue
  • Batching: Group email/SMS by provider for efficiency

31. Design a key-value store

Requirements: GET/SET/DELETE with 10ms P99, 1B keys, 1PB total data.

Architecture:

Client → Load Balancer → Nodes (consistent hashing ring)
Each node: in-memory hash map (hot data) + SSTable on disk (cold)
WAL (Write-Ahead Log) for durability

Key design decisions:

  • Storage engine: LSM tree (write-optimized, like Cassandra) vs B-tree (read-optimized, like InnoDB)
  • Replication: 3 replicas with quorum writes (W+R > N)
  • Eviction: LRU for in-memory portion
  • Compaction: Merge SSTables periodically (background)

32. Design a web crawler

Requirements: Crawl the entire web (~5B pages), refresh pages monthly.

Architecture:

Seed URLs → URL Frontier (priority queue) → Fetcher → Parser
               ↑___________________________________|

Components:

  • URL Frontier: Prioritized queue (page rank, freshness)
  • DNS Resolver: Cache DNS lookups to avoid bottleneck
  • Fetcher: Worker pool downloading pages
  • Robots.txt Handler: Respect crawl rules
  • Duplicate Detection: Bloom filter or SimHash for near-duplicates

Politeness: Limit requests per domain (1 req/sec per host). Distributed crawl respects robots.txt.


Reliability and Consistency

33. What is the difference between RTO and RPO?

  • RPO (Recovery Point Objective): Maximum acceptable data loss. If RPO = 1 hour, backups must be taken hourly.
  • RTO (Recovery Time Objective): Maximum acceptable downtime. If RTO = 30 minutes, recovery must complete in 30 min.

Lower RPO/RTO = more expensive infrastructure.

34. What is idempotency and why does it matter?

An operation is idempotent if applying it multiple times has the same effect as applying it once.

Critical for distributed systems because retries are common (network timeouts, failures).

# Non-idempotent: creates duplicate payment
def process_payment(amount):
    return db.insert("INSERT INTO payments VALUES (?)", amount)

# Idempotent: safe to retry
def process_payment(payment_id, amount):
    return db.upsert("""
        INSERT INTO payments (id, amount) VALUES (?, ?)
        ON CONFLICT (id) DO NOTHING
    """, payment_id, amount)

Idempotency key: Client generates unique key per request. Server stores it and ignores duplicates.

35. What is a saga pattern for distributed transactions?

Problem: ACID transactions don't span multiple microservices. How to maintain consistency?

Saga: Sequence of local transactions. If one fails, compensating transactions undo previous steps.

Order Saga:
1. Create Order          → compensate: Cancel Order
2. Reserve Inventory     → compensate: Release Inventory
3. Process Payment       → compensate: Refund Payment
4. Update Loyalty Points → compensate: Remove Points

If step 3 fails: run compensate(2), compensate(1)

Choreography: Services react to events (no central coordinator) Orchestration: Saga orchestrator directs each step (easier to track state)


Performance and Optimization

36. What is N+1 query problem?

N+1 problem: Fetching a list of N items and then making N additional queries for each item's related data.

# N+1: 1 query for users + N queries for orders
users = db.query("SELECT * FROM users")
for user in users:
    orders = db.query("SELECT * FROM orders WHERE user_id = ?", user.id)

# Solution: JOIN or batch fetch
users_with_orders = db.query("""
    SELECT users.*, orders.* 
    FROM users 
    LEFT JOIN orders ON orders.user_id = users.id
""")

In ORMs: use include/preload/eager_load to fetch related data in one query.

37. How does database query optimization work?

Query execution plan: Database optimizer chooses access method (index scan vs full table scan) and join order.

-- EXPLAIN shows execution plan
EXPLAIN SELECT * FROM orders 
WHERE user_id = 123 AND status = 'pending'
ORDER BY created_at DESC;

-- Look for:
-- Seq Scan → consider adding index
-- Nested Loop with large rows → JOIN order issue
-- Sort → consider index on sort column

Common optimizations:

  • Add composite index matching WHERE + ORDER BY
  • SELECT only needed columns (avoid SELECT *)
  • Avoid functions on indexed columns in WHERE (WHERE YEAR(created_at) = 2025 kills index)
  • Use LIMIT on large result sets

38. What is denormalization and when should you use it?

Normalization (3NF): Eliminate redundancy, split data into related tables. Good for write performance and consistency.

Denormalization: Introduce controlled redundancy to avoid expensive JOINs. Good for read performance.

-- Normalized: requires JOIN for every order list
orders: (id, user_id, amount)
users: (id, name, email)

-- Denormalized: user_name stored in orders
orders: (id, user_id, user_name, amount)
-- Trade-off: if user changes name, orders show old name

Use denormalization in:

  • Read-heavy analytics tables
  • Search indexes (Elasticsearch stores denormalized docs)
  • Materialized views for complex aggregations

Searching and Real-Time Systems

39. How would you build a search autocomplete system?

Requirements: Return top 5 suggestions within 100ms as user types.

Offline component:

  • Analyze search logs to compute top queries per prefix
  • Build Trie or prefix hash map: "sta" → ["starbucks", "stack overflow", "starbucks near me"]

Online component:

User types "sta" → Check cache → Query trie service → Return top 5

Data structure:

  • Trie: Memory-efficient, O(L) lookup where L = prefix length
  • Prefix hash map: O(1) lookup, more memory

Scale:

  • Cache popular prefixes in Redis
  • Shard trie by first character
  • Update trie asynchronously (log → batch → rebuild)

40. How would you design a real-time leaderboard?

Requirements: Top 100 players globally, update in real-time.

Solution using Redis Sorted Sets:

import redis
r = redis.Redis()

# Update score
def update_score(user_id: str, score: int):
    r.zadd("leaderboard", {user_id: score})

# Get top 100
def get_top_100():
    return r.zrevrange("leaderboard", 0, 99, withscores=True)

# Get user rank
def get_rank(user_id: str):
    return r.zrevrank("leaderboard", user_id)

Redis Sorted Sets: O(log N) for updates, O(log N + K) for range queries. Handles millions of entries easily.


Security and Operations

41. How do you design authentication for a distributed system?

Stateless auth with JWT:

Login → Server validates credentials → Issues JWT (signed with secret)
Request → Client sends JWT in header → Server verifies signature → Trusts claims

Pros: No session store needed, works across services Cons: Can't revoke before expiry without denylist

Hybrid approach:

  • Short-lived JWT (15 min) + long-lived refresh token (stored in DB)
  • Refresh tokens can be revoked
  • JWT validates at API level without DB hit

42. What is the OAuth 2.0 flow?

Authorization Code Flow (for web apps with backend):

1. User clicks "Login with Google"
2. Browser redirects to Google with client_id + redirect_uri + state
3. User logs in at Google, grants permission
4. Google redirects back with authorization code
5. Backend exchanges code for access token (server-to-server)
6. Backend uses access token to fetch user info

PKCE (for SPAs/mobile): Adds code_verifier/code_challenge to prevent code interception attacks.

43. How do you prevent DDoS attacks?

Layers of defense:

  1. CDN: Absorb traffic at edge (Cloudflare, AWS Shield)
  2. Rate limiting: Limit by IP, user, or endpoint
  3. WAF (Web Application Firewall): Block malicious patterns
  4. IP blacklisting: Block known bad actors
  5. CAPTCHAs: For account creation, forms
  6. Anycast routing: Distribute DDoS traffic across many PoPs

Advanced Topics

44. What is the two-phase commit protocol?

2PC coordinates distributed transactions across multiple nodes:

Phase 1 (Prepare):

  • Coordinator sends "prepare" to all participants
  • Each participant executes transaction, logs to WAL, replies "yes" or "no"

Phase 2 (Commit/Abort):

  • If all replied "yes": coordinator sends "commit" to all
  • If any replied "no": coordinator sends "abort" to all

Problem: Coordinator failure after Phase 1 can leave participants in uncertain state (blocking). Modern systems prefer sagas or eventual consistency.

45. What is CQRS?

CQRS (Command Query Responsibility Segregation): Separate models for reading and writing data.

Write side (Commands): Handles mutations → Updates write DB + publishes events
Read side (Queries):   Handles reads → Reads from optimized read DB (updated via events)

Example:
PlaceOrder command → Order aggregate → OrderPlaced event → 
  → Update inventory read model
  → Update user order history read model
  → Update analytics model

Benefits:

  • Read models can be optimized independently (denormalized, cached)
  • Write models can enforce business rules
  • Independent scaling of read vs write

46. How does Cassandra handle writes so fast?

Cassandra uses an LSM (Log-Structured Merge) tree:

  1. Write → WAL (Write-Ahead Log) for durability
  2. Write → MemTable (in-memory sorted structure) → very fast
  3. When MemTable fills → flush to SSTable (immutable sorted file on disk)
  4. Background compaction merges SSTables

No random disk writes — all disk I/O is sequential → very high write throughput.

Reads: More expensive — may need to check multiple SSTables + Bloom filters to minimize disk reads.

47. What is the Raft consensus algorithm?

Raft achieves distributed consensus (all nodes agree on the same value):

  1. Leader election: Nodes start as followers. If no heartbeat from leader → become candidate → request votes → if majority vote → become leader
  2. Log replication: Leader receives writes → appends to log → sends AppendEntries to followers → commits when majority acknowledge
  3. Safety: Only leader with the most up-to-date log can be elected → no data loss

Used by: etcd, CockroachDB, TiKV.

48. What is a bloom filter?

A Bloom filter is a probabilistic data structure that answers "is this element in the set?" with:

  • False negatives: Never (if it says "no", it's definitely not there)
  • False positives: Possible (if it says "yes", it might be wrong)

Memory efficient: 10 bits per element gives ~1% false positive rate.

from pybloom_live import BloomFilter
bf = BloomFilter(capacity=1_000_000, error_rate=0.001)
bf.add("user:123")
print("user:123" in bf)  # True (definitely)
print("user:456" in bf)  # False (probably not there)

Use cases: Check if URL was crawled, if cache has item (before DB query), if email is in spam list.

49. What is tail latency and why does it matter?

Tail latency (P99, P999): The slowest 1% or 0.1% of requests.

In microservices, a single user request might fan out to 100 services. If each has 1% slow requests:

P(all fast) = 0.99^100 = 0.366
P(at least one slow) = 63.4%

Even 1% tail latency means 63% of user requests hit a slow call.

Solutions:

  • Hedged requests: Send same request to 2 servers, use first response, cancel second
  • Timeout + retry: Abandon slow requests early with fallback
  • Reduce GC pauses: Use off-heap storage, tune GC
  • Avoid head-of-line blocking: Use connection multiplexing (HTTP/2, gRPC)

50. How would you design a distributed cache?

Requirements: 10M QPS, 1ms P99, 100TB capacity.

Architecture:

Client → Client Library (consistent hashing) → Cache Cluster
                                             (100+ nodes, Redis/Memcached)
                                             → Replication (optional)

Key decisions:

Decision Option A Option B
Partitioning Consistent hashing (less rebalancing) Range-based (simpler queries)
Eviction LRU (general) LFU (hot-key workloads)
Replication Single copy (simple) Master-replica (high availability)
Protocol Redis (rich data types) Memcached (simple, faster)
Serialization JSON (debuggable) Protobuf/MessagePack (efficient)

Hotspot mitigation: If single key is overwhelmed → replicate hot keys across multiple nodes → route requests to different replicas.


Common Mistakes Table

Mistake Why It Matters Better Approach
Premature optimization Wrong bottlenecks assumed Profile first, optimize measured bottlenecks
Ignoring failure modes Systems fail unexpectedly Design for failure from the start
Synchronous everywhere Cascading failures Use async + circuit breakers for non-critical paths
Single point of failure One node down = outage Redundancy at every layer
No caching strategy DB overwhelmed at scale Cache read-heavy data at multiple layers
Ignoring consistency model Stale data causes bugs Define consistency requirements early
Over-engineering Complexity without need Start simple, scale when needed
Ignoring monitoring Can't debug production Metrics, logs, traces from day one

System Design Interview Tips

  1. Ask clarifying questions first — don't design the wrong system
  2. State your assumptions — "I'll assume 1M DAU"
  3. Estimate scale explicitly — numbers show design thinking
  4. Start with high-level design — get feedback before diving deep
  5. Identify bottlenecks — where will the system break?
  6. Discuss trade-offs — no perfect solution exists
  7. Know your numbers — latency, throughput, storage estimates
  8. Practice common designs — URL shortener, chat, feed, search

FAQ

Q: Should I always design for millions of users? A: Only if asked or if requirements imply it. Premature scaling is a red flag. Start with reasonable scale, then discuss how to scale.

Q: How much depth should I go into? A: Breadth first (cover all components), then depth on what the interviewer is most interested in. They'll ask follow-up questions on areas they care about.

Q: What if I don't know something? A: Say "I'm not certain, but I'd approach it by..." and reason through it. Interviewers value structured thinking over memorized answers.

Q: Is there a "correct" answer to system design questions? A: No. Different companies optimize for different things. The key is demonstrating you understand trade-offs and can justify your choices.

Q: How do I practice? A: Study common designs (URL shortener, YouTube, WhatsApp, Uber, Google Search), then practice whiteboarding without notes. Explain your reasoning out loud.

Q: What's the difference between this and coding interviews? A: Coding interviews have right/wrong answers. System design is evaluated on communication, breadth of knowledge, trade-off analysis, and ability to handle ambiguity — not a perfect answer.

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools