System Design Fundamentals
Core building blocks every senior interview expects — scalability, CAP, caching, load balancing, databases, CDN, and estimation.
Related video: Distributed Job Scheduler — System Design
① The 45-minute interview framework
System design interviews are structured conversations, not trivia. You have roughly 45 minutes to show you can turn a vague product idea into a production architecture. The framework below is the same skeleton used at Google, Meta, Amazon, and in courses like Hello Interview — but here you will learn what to say at each step with concrete numbers and diagrams.
Why it matters
Without a framework, candidates jump straight to "we need Kafka and Redis" and lose 15 minutes on the wrong problem. Interviewers grade process: clarifying ambiguity, estimating scale, drawing a sane high-level design, then diving deep on two components with trade-offs. A repeatable framework prevents panic and signals seniority — you drive the room instead of waiting for prompts.
Staff-level hires consistently: (1) state assumptions aloud, (2) time-box each phase, (3) check in — "Should I go deeper on the write path or caching?"
Where to use
Use this skeleton for every open-ended design question: URL shortener, Twitter feed, payment system, chat, rate limiter, job scheduler, video streaming. Even when the interviewer says "design X," they are testing whether you can decompose X using the same steps.
Real use cases
- Design a news feed (Meta-style): Clarify read vs write ratio (often 100:1), estimate 500M DAU → ~6K average QPS, peak 60K QPS → CDN + cache for reads, fan-out on write vs pull on read deep dive.
- Design payments: Clarify strong consistency, idempotency, PCI scope → skip CDN on money path → deep dive on DB transactions and saga/outbox.
- Design a file upload service: Clarify max file size (100 MB), 10K uploads/min → estimate bandwidth 17 GB/min → deep dive S3 multipart + metadata DB.
When NOT to use
Do not rigidly recite slides when the interviewer is clearly steering you ("let's skip estimates, go straight to sharding"). Flex the framework — but never skip requirements. Also avoid spending 20 minutes on requirements for a simple LRU cache question; compress clarify + estimate to 5–7 minutes total for smaller scopes.
Alternatives
| Framework | Focus | When to prefer |
|---|---|---|
| REA (Requirements, Estimation, Architecture) | Minimal 3-step | 45-min interviews with strong time pressure |
| Hello Interview 4-step | Requirements → high-level → deep dives → wrap-up | Very similar; merge estimation into requirements |
| Educative RESHADED | Requirements, Estimation, Storage, High-level, API, Data model, Evaluation, Detail | When interviewer wants API + schema early |
| This lesson (6-step + time boxes) | Explicit trade-offs + failure modes | Default for most FAANG-style loops |
Execution / data flow
Walk through the interview clock — say these time boxes out loud:
- Clarify (5 min): functional requirements, non-functional (latency p99, availability %, consistency), explicit out-of-scope
- Estimate (5 min): DAU, QPS (avg + 10× peak), storage, bandwidth — round numbers
- High-level design (10 min): client, CDN, LB, services, cache, DB, async queues
- Deep dive (15 min): pick 2 components — data model, hot path, sharding, failure handling
- Trade-offs (5 min): SQL vs NoSQL, sync vs async, strong vs eventual consistency
- Wrap-up (5 min): failure modes, monitoring, future 10× scale
5 min
5 min
10 min
15 min
5 min
5 min
Vague prompt → Clarify scope → Numbers on paper → Boxes & arrows → Zoom into 2 boxes → Compare options → Failures & metrics
| Minute | You say | Interviewer hears |
|---|---|---|
| 0–5 | "Is search in scope? What's p99 latency target?" | Structured thinking |
| 5–10 | "10M DAU × 20 reads/day ≈ 2,300 QPS, peak ~25K" | Can estimate scale |
| 10–20 | Draw CDN → LB → API → Redis → Postgres | Knows standard patterns |
| 20–35 | "Deep dive: feed generation + caching" | Depth, not breadth only |
| 35–45 | "CP vs AP here; I'd choose eventual for likes" | Trade-off literacy |
② Scalability — vertical vs horizontal
Scalability means your system can handle more load (users, QPS, data) by adding resources — without rewriting the product. This section covers how you scale machines (vertical vs horizontal). NFR scalability targets (10× growth, elasticity) are covered in the NFR lesson.
Why it matters
Every successful product outgrows a single server. Instagram started on one Postgres; within years they needed sharded storage and thousands of app servers. Interviewers want to hear: stateless app tier scales horizontally; databases scale via replicas, partitioning, or different stores. Wrong scaling order (shard before cache) wastes months of engineering.
Concrete trigger numbers: single Postgres often tops out around 5K–10K write QPS and 50K–100K read QPS with replicas — beyond that you need partitioning or a write-optimized store.
Where to use
- App servers: horizontal scale behind a load balancer (stateless REST APIs).
- Read-heavy DB: read replicas + connection pooling before sharding.
- Write-heavy DB: partitioning/sharding, queue-based write absorption, or Cassandra/Dynamo-style scale-out.
- Early startup: vertical scale (bigger instance) is fine until ~$500–2K/month DB tier becomes painful.
Real use cases
- Netflix API tier: thousands of stateless instances; session and preferences in external stores — classic horizontal app scale.
- Shopify peak (Black Friday): auto-scale app + read replicas; cart writes still hit primary — vertical + horizontal mix.
- Discord voice: stateful (UDP rooms) — horizontal scale with consistent hashing so users land on the same gateway; not simple round-robin.
- Internal admin tool (50 users): one t3.medium — vertical scale is enough; horizontal scale adds ops cost with no benefit.
When NOT to use
- Vertical scale only when you need 99.99% availability — one big machine is a single point of failure.
- Horizontal app scale when the app keeps sessions in local memory — sticky sessions are a crutch; fix statelessness first.
- Sharding early at 200 QPS because "we might scale" — operational nightmare; cache and optimize first.
Alternatives
| Approach | How | Pros | Cons | Example scale |
|---|---|---|---|---|
| Vertical scale | Bigger CPU/RAM/disk (r6g.2xlarge → r6g.8xlarge) | Simple, no code changes | Hard ceiling, SPOF, expensive | 0–2K QPS monolith |
| Horizontal scale | More machines + LB | Near-unlimited app tier, fault tolerant | Stateless apps, partitioning, ops | 10K–1M+ QPS APIs |
| Auto-scaling | CPU/latency-driven instance count | Handles spikes (3× daily peak) | Cold start 30–90s, cost tuning | SaaS with diurnal traffic |
| Read replicas | DB copies for reads | 5×–10× read capacity | Replication lag 10ms–1s | Feeds, dashboards |
| Functional scale | Split monolith into services | Team autonomy, isolate hot paths | Network latency, distributed debug | Org > 50 engineers |
Execution / data flow
Standard scale path when traffic grows 10×:
Traffic spike → Profile & optimize (indexes, N+1) → Cache + CDN → Scale reads (replicas) → Scale writes (queue, shard) → Auto-scale app tier
100K concurrent
L7, health checks
auto-scale 10–200
shared session
primary + replicas
1 server 64 GB RAM
8 servers 8 GB each
Numbers example: API at 8K QPS, 50 ms p99 per instance handles ~200 QPS → need ~40 instances at peak (with 2× headroom → 80 instances). DB at 8K reads/s → 2 read replicas (4K each) + 32 GB cache for hot 20% of keys.
③ Back-of-envelope estimation
Back-of-envelope math turns "millions of users" into QPS, storage, and bandwidth so your architecture choices are justified. You are allowed to round aggressively — interviewers care about orders of magnitude, not exactness.
Why it matters
Without estimates you might propose a single MySQL for YouTube-scale video or 50 Kafka clusters for a todo app. Estimates drive: how many app servers, whether you need a CDN, cache size, and sharding strategy. A 2-minute calculation often eliminates half the wrong designs.
Where to use
Every system design interview after clarifying requirements — typically 5 minutes with pen and paper. Also used in RFCs, capacity planning, and cost forecasts ($/month for S3, RDS, egress).
Real use cases
- Twitter-like read-heavy: 300M DAU × 50 timeline reads/day = 15B reads/day ≈ 175K QPS average; 10× peak ≈ 1.7M QPS → CDN + aggressive cache mandatory.
- Photo storage: 500M users × 200 photos × 2 MB = 200 PB raw → S3 + lifecycle to Glacier; metadata in DB ~100 GB.
- Chat messages: 10M users × 100 messages/day × 500 B = 500 GB/day ≈ 6 MB/s write bandwidth → Kafka partition count ~50–100.
When NOT to use
Skip deep estimation when the interviewer says "assume infinite scale" or for tiny scoped problems (design a mutex API). Do not spend 15 minutes on bandwidth if functional design is still unclear.
Alternatives
| Method | Description | Best for |
|---|---|---|
| DAU × actions/day | Most common QPS formula | User-facing APIs |
| Peak factor (5×–10×) | Average × multiplier | Planning capacity, auto-scale max |
| Power-of-2 round | 1M → 1.2M, 86,400 → 100K | Fast mental math |
| Little's Law | Concurrency = QPS × latency | Connection pools, queue depth |
| Spreadsheet model | Detailed cost + growth curves | Production capacity reviews |
Execution / data flow
Worked example — URL shortener:
- 100M DAU, each creates 1 short URL/day + 10 redirects/day
- Writes: 100M/day ≈ 1,200 write/s avg; peak 10× ≈ 12K write/s
- Reads: 1B redirects/day ≈ 12K read/s avg; peak ≈ 120K read/s
- Storage: 100M new URLs/day × 500 B × 365 days × 5 years ≈ 90 TB (+ indexes ~2×)
- Bandwidth: 120K RPS × 1 KB response ≈ 120 MB/s egress at peak
DAU → actions/day → divide by 86,400 → QPS avg → multiply 10× peak → storage = records × size × retention → bandwidth = QPS × payload
| Resource | Formula | Example |
|---|---|---|
| QPS (avg) | DAU × actions/day ÷ 86,400 | 10M DAU × 20 ÷ 86,400 ≈ 2,300 QPS |
| QPS (peak) | Avg × 10 | 2,300 × 10 ≈ 23,000 QPS |
| Storage | records/day × size × retention days | 1B rows × 1 KB × 365 × 3 yr |
| Bandwidth | QPS × avg payload | 5K RPS × 50 KB = 250 MB/s |
| Cache memory | hot % × dataset | 20% of 100 GB = 20 GB Redis |
| DB connections | QPS × query time (Little) | 2K QPS × 20 ms = 40 concurrent |
Reference numbers to memorize: 1 day = 86,400 s ≈ 100K for mental math; 1 MB = 1,000 KB; SSD ~1 GB/s; network cross-region ~50–100 ms; Redis GET ~1 ms; Postgres indexed PK ~1–5 ms; cross-service hop ~5–20 ms.
④ Load balancing
A load balancer (LB) distributes incoming traffic across multiple backend servers so no single machine melts and failed nodes are removed automatically. It is the front door of almost every horizontally scaled system.
Why it matters
Without an LB, one app server gets overloaded, others sit idle, and a crashed server still receives traffic. LBs provide high availability (health checks), SSL termination (offload TLS from apps), and routing (canary 5% to new version). At 50K QPS, a single nginx or AWS ALB can often handle the fan-out — apps scale behind it.
Where to use
- Between clients and stateless API servers (always).
- Between API tier and internal microservices (service mesh / sidecar LB).
- Database read replica routing (PgBouncer, ProxySQL, RDS reader endpoint).
- Global traffic: DNS + GeoDNS or anycast to regional LBs.
Real use cases
- AWS ALB (L7): Route
/api/*to ECS,/static/*to S3; sticky sessions for legacy; weighted target groups for canary. - NGINX (L4/L7): 100K+ concurrent WebSocket connections with
least_connand upstream keepalive. - Consistent hashing (Memcached): key → server mapping minimizes reshuffle when one node added (still used in caches, not primary LB for HTTP).
- Global LB (Cloudflare / AWS Global Accelerator): user in Tokyo → Tokyo region LB → reduces RTT from 200 ms to 20 ms.
When NOT to use
- Single-server deployments (<500 QPS internal tool) — LB adds cost and complexity.
- Stateful protocols without sticky sessions or shared state — random routing breaks in-memory rooms.
- Using LB as database sharding router without understanding hot shards — use application-level sharding keys instead.
Alternatives
| Algorithm | Behavior | Best for | Weak for |
|---|---|---|---|
| Round robin | Rotate evenly | Homogeneous stateless, uniform latency | Long requests pile on one server if times vary |
| Least connections | Fewest active conns | WebSocket, gRPC streams, variable RTT | Slightly higher LB CPU |
| Weighted RR | Capacity-weighted | Mixed instance sizes (c5.xlarge + c5.4xlarge) | Manual weight tuning |
| IP hash / sticky | Same client → same server | Legacy session in memory | |
| Consistent hash | Key → server ring | Cache clusters, minimal remapping | HTTP request LB (limited) |
| L4 (TCP) | IP/port, no HTTP parse | Max throughput, TLS pass-through | Can't route on URL/header |
| L7 (HTTP) | URL, headers, cookies | Microservices, A/B, auth routing | Higher latency ~1–5 ms |
Execution / data flow
Client TLS → LB terminates SSL → health check OK backends only → pick algorithm → forward to app → app responds → LB returns to client
HTTPS
SSL terminate
healthy
healthy
unhealthy — drained
Health checks: HTTP GET /health every 10s; 2 failures → remove from pool; 30s to drain long requests. At 10K QPS across 20 servers, each instance sees ~500 QPS — if one fails, LB redistributes in <30s.
Active-active vs active-passive: Stateless APIs = active-active (all nodes serve traffic). Stateful leader (single writer DB) = active-passive failover with VIP or DNS flip — RTO 30s–5 min typical.
⑤ Caching strategies
Caching stores frequently accessed data in fast memory (Redis, in-process) so you avoid slow disk/network on every request. A good cache can turn 50 ms DB reads into 1 ms and cut DB QPS by 80–95% for read-heavy workloads.
Why it matters
Database is the bottleneck in most systems. At 20K read QPS, Postgres without cache dies; with 90% hit rate, DB sees only 2K QPS. Caching is often the first scale lever after basic indexing — cheaper than sharding.
Numbers: Redis single node ~100K–200K ops/s; hit ratio 80–95% typical for hot keys; TTL 60s–24h depending on freshness needs.
Where to use
- Read-heavy APIs: user profiles, product catalog, feed pages.
- Session storage: JWT validation + server-side session in Redis.
- Rate limiting counters, leaderboard scores, feature flags.
- CDN edge cache for static assets and cacheable GET JSON.
Real use cases
- Facebook memcached layer: billions of keys; cache-aside; invalidation on profile update.
- Amazon product page: CDN + Redis for product metadata; inventory may skip cache or use short TTL (5s) for accuracy.
- Stack Overflow: heavy in-process + Redis; question pages cached; writes invalidate tags.
- Session store: 50M sessions × 2 KB = 100 GB Redis cluster with replication.
When NOT to use
- Strong consistency required on every read (bank balance) — cache adds staleness unless careful read-your-writes routing.
- Data accessed once ever (cold archival) — cache waste.
- Dataset entirely unique per request (random UUID lookups with no repeat) — 0% hit rate.
- When invalidation is harder than the problem (high churn inventory) — consider shorter TTL or no cache on that path.
Alternatives
| Pattern | Read path | Write path | Risk |
|---|---|---|---|
| Cache-aside | App → cache → miss → DB → set cache | Write DB, invalidate/delete cache | Stale if invalidation missed |
| Read-through | Cache loads on miss (library) | Invalidate on write | Cache library dependency |
| Write-through | Read cache | Sync write cache + DB | Higher write latency ~2× |
| Write-behind | Read cache | Write cache, async flush DB | Data loss if cache crashes before flush |
| CDN only | Edge for static/cacheable GET | Purge or versioned URLs | Can't cache personalized POST |
Execution / data flow
Read → Check Redis → Hit: return (1 ms) | Miss → Query DB (10–50 ms) → Set cache with TTL → Return
hit 90%
miss 10%
Hot key problem: 1M QPS on celebrity tweet key — single Redis shard melts. Fixes: local in-process cache (1s TTL), replicate key across shards, pre-warm before event.
Cache stampede: TTL expires, 10K threads hit DB simultaneously. Fixes: singleflight (one thread repopulates), probabilistic early expiration, mutex per key.
| Scenario | QPS | Cache hit | DB QPS |
|---|---|---|---|
| No cache | 20,000 | 0% | 20,000 |
| Redis 90% hit | 20,000 | 90% | 2,000 |
| CDN + Redis | 20,000 | 95% | 1,000 |
⑥ CAP theorem & consistency
The CAP theorem states that in a distributed system during a network partition, you must choose between Consistency (every read sees latest write) and Availability (every request gets a response). Partition tolerance is not optional in real networks — cables fail, regions go dark.
Why it matters
Wrong consistency choice causes lost payments, double bookings, or angry users seeing stale feeds. Interviewers use CAP to test whether you match storage and replication to business rules: money = CP; social likes = AP.
PACELC extension: Even without partition, you trade Latency vs Consistency — sync cross-region replication adds 50–150 ms per write.
Where to use
- Choosing database: Postgres (CP-ish single primary) vs Cassandra (AP tunable).
- Multi-region design: sync replication (CP, higher latency) vs async (AP, eventual).
- Leader election (ZooKeeper/etcd): CP for coordination.
- Shopping cart during partition: often AP — better available cart than error page.
Real use cases
- Bank transfer: CP — single leader, sync replication, reject write if quorum lost; p99 write latency 100–300 ms acceptable.
- Instagram like count: AP/eventual — count may lag 1–5s; available during partial outage.
- DynamoDB / Cassandra: AP with tunable consistency (
QUORUMvsONE). - Google Spanner: CP with TrueTime — strong global consistency at higher cost/latency.
When NOT to use
- Single-node Postgres on one machine — CAP is about distributed trade-offs; don't over-quote CAP for monoliths.
- Claiming "we chose CAP" without naming concrete failure scenario — always tie to partition or replication lag.
- Strong consistency everywhere "because it's safer" — kills availability and latency at global scale.
Alternatives
| Choice | Systems | Consistency | Typical latency |
|---|---|---|---|
| CP | ZooKeeper, etcd, HBase, Spanner | Linearizable / strong | Write 50–300 ms multi-region |
| AP | Cassandra, DynamoDB (default), Riak | Eventual, tunable | Write 5–20 ms local |
| Strong (single leader) | Postgres primary | Read-your-writes on primary | Read replica lag 10ms–1s |
| Eventual | Async replica, CDN | Stale reads possible | Read 1–5 ms from replica |
| Causal | MongoDB sessions, some queues | Ordered per client | Middle ground |
Execution / data flow
Partition scenario: US-East and US-West lose network link. CP system: one side stops accepting writes (or entire cluster read-only) to prevent split-brain. AP system: both sides accept writes; merge conflicts later (vector clocks, last-write-wins — risky for money).
Write → Leader primary → Sync replicas (CP wait) OR Async replicate (AP fast) → Read from primary (strong) OR replica (eventual)
CP: reject writes
AP: accept writes
Numbers: Async replica lag under load: 100 ms–2 s. Sync quorum (3 nodes, write 2): add ~10–30 ms LAN, ~100 ms cross-region. Availability target 99.9% = 8.7 hr downtime/year — CP failover may violate unless multi-AZ.
⑦ Database types — when to use what
No single database wins every workload. Polyglot persistence means using Postgres for transactions, Redis for cache, Elasticsearch for search, S3 for blobs — each optimized for its access pattern.
Why it matters
Picking MongoDB because "it scales" for heavy relational reporting fails. Picking Postgres for 500K write/s time-series fails. Interviewers want access-pattern reasoning: read/write ratio, join needs, consistency, query shape, retention.
Where to use
- OLTP transactions: SQL (Postgres, MySQL).
- High write throughput, wide rows: Cassandra, HBase.
- Flexible document model: MongoDB, DynamoDB.
- Sub-ms session/cache: Redis, Memcached.
- Full-text search / logs: Elasticsearch, OpenSearch.
- Graph traversals (friends-of-friends): Neo4j (or SQL with limits).
- Vector similarity (RAG): Pinecone, pgvector, Weaviate.
Real use cases
- Stripe: Postgres for money (ACID); Redis for idempotency keys; Kafka for events.
- Netflix: Cassandra for viewing history (high write); S3 for video; EV cache.
- Airbnb search: Elasticsearch for listings; MySQL for bookings source of truth.
- OpenAI RAG app: pgvector or Pinecone for embeddings; Postgres for user metadata.
When NOT to use
- Redis as sole source of truth for financial records — persistence optional, not ACID bank.
- Elasticsearch as primary transactional store — not designed for atomic multi-doc updates.
- Graph DB for simple user CRUD at 100M users — ops complexity without graph queries.
- Sharding Postgres before exhausting cache + read replicas — premature sharding pain.
Alternatives
| Type | Examples | Strengths | Weak for | Scale hint |
|---|---|---|---|---|
| SQL | PostgreSQL, MySQL | ACID, joins, constraints | Massive write on one node | ~5K–10K write/s sharded |
| Wide-column | Cassandra, HBase | Write throughput, TTL | Ad-hoc joins | 100K+ write/s cluster |
| Document | MongoDB, DynamoDB | Flexible schema, partition key scale | Cross-shard transactions | Dynamo millions RPS |
| Key-value | Redis, Memcached | Sub-ms, simple ops | Complex queries | 100K–1M ops/s/node |
| Search | Elasticsearch | Full-text, aggregations | Primary OLTP | Billions docs with shards |
| Graph | Neo4j | Relationship queries | Simple CRUD at huge scale | Millions nodes typical |
| Vector | Pinecone, pgvector | Similarity search | Exact PK only workloads | Billions vectors partitioned |
| Object | S3, GCS | Cost per GB, durability | Low-latency indexed queries | Exabytes |
Execution / data flow
API write → Validate → Postgres transaction → Publish event to Kafka → Worker indexes Elasticsearch → Cache invalidation in Redis
orders ACID
cart session
product search
images
Sharding when: single table > 500 GB–1 TB, write QPS > 5K–10K on primary, or index maintenance blocks writes. Shard key: user_id (even spread) not country (hot shard).
| Workload | Read QPS | Write QPS | Pick |
|---|---|---|---|
| Bank ledger | 10K | 2K | Postgres + sync replica |
| IoT metrics | 50K | 500K | Cassandra / Timescale |
| Session | 100K | 20K | Redis |
| Log search | 5K | 200K | Elasticsearch |
⑧ CDN & edge delivery
A Content Delivery Network (CDN) caches static and cacheable content at edge servers (PoPs) worldwide so users download from a nearby city instead of your origin in Virginia. Latency drops from 200 ms to 20–50 ms; origin bandwidth can drop 80–95% for static assets.
Why it matters
At 1M users streaming a 2 MB JS bundle, origin serves 2 TB per full cache miss wave. CDN absorbs repeat traffic. For video (Netflix, YouTube), CDN/edge is non-negotiable — origin cannot serve 100 Gbps peaks.
Cost: egress from cloud origin ~$0.08–0.12/GB vs CDN ~$0.02–0.05/GB at scale.
Where to use
- Static assets: JS, CSS, fonts, images, WASM.
- Cacheable GET APIs: public product catalog, blog posts (with
Cache-Control). - Video/audio segments (HLS/DASH chunks).
- Software downloads, game patches, firmware.
Real use cases
- Cloudflare / Akamai in front of SaaS: global Anycast DNS → nearest PoP; DDoS scrubbing included.
- Spotify album art: S3 origin + CDN; immutable URLs with hash in path.
- API caching: GET
/v1/productswithCache-Control: public, max-age=300— 5 min stale OK. - Live sports: CDN delivers 10 Tbps aggregate during events; origin only encodes streams.
When NOT to use
- Personalized responses (user-specific JSON with auth) — cache miss every time unless edge includes user segment key.
- POST/PUT/DELETE — not cacheable by standard CDN rules.
- Highly dynamic data (<1s freshness): stock ticker — CDN TTL too coarse; use dedicated streaming.
- Internal microservices east-west traffic inside VPC — CDN wrong tool.
Alternatives
| Approach | Latency | Best for |
|---|---|---|
| CDN edge cache | 20–50 ms global | Static + cacheable GET |
| Origin only | 100–300 ms cross-region | Dev/staging, tiny traffic |
| Versioned URLs (hash) | Long max-age, no purge | JS/CSS deploy immutability |
| Purge API | Invalidate on deploy | HTML without hash filenames |
| Edge compute (Workers) | Logic at PoP | A/B, auth at edge, geo routing |
| Multi-region active | Low latency writes+reads | When CDN cache insufficient |
Execution / data flow
Client DNS → CDN edge (hit: return 20 ms) | miss → origin fetch → cache at edge → return to client
Mumbai
Mumbai edge
optional
S3 / API us-east
- Origin — S3 or app server (source of truth for content)
- CDN edge PoPs — 200+ cities; cache hot objects
- DNS / anycast — route client to nearest healthy PoP
- Client — receives cached bytes; origin load drops 90%+ for static
| Asset | Size | 1M users | Without CDN | With CDN (90% hit) |
|---|---|---|---|---|
| JS bundle | 500 KB | 500 GB transfer | Origin 500 GB | Origin 50 GB |
| Hero image | 200 KB | 200 GB | 200 GB | 20 GB |
| API catalog GET | 50 KB | 50 GB @ 1M req | 50 GB | 5 GB + 5 min stale |
app.v2.abc123.js immutable URLs over purge APIs. Say CDN for static and cacheable GET; personalized feeds stay behind API + Redis, not CDN.⑨ End-to-end request path
Tracing one HTTP request from finger tap to database row shows how every fundamental piece connects — DNS, TLS, CDN, LB, app, cache, DB, async workers. Senior candidates narrate this path with a latency budget.
Why it matters
Optimizing the wrong layer wastes effort. If p99 is 800 ms because DB missing index, CDN won't help. Latency budget forces accountability: each hop gets a millisecond cap; sum must meet SLA (often p99 < 200–300 ms for APIs).
Where to use
Explain hot path in every interview after high-level diagram. Production debugging: distributed tracing (Jaeger) shows which span blew the budget.
Real use cases
- Read product page: CDN hit on image (15 ms) + API miss cache → Postgres (40 ms) + ES search sidebar (30 ms) — parallelize ES.
- Post tweet: Write primary (20 ms) + fan-out async to 10M followers impossible sync — queue + batch.
- Login: LB → API → Redis session check (2 ms) → optional Postgres user lookup — keep auth off critical CDN path.
When NOT to use
Don't enumerate every hop for batch jobs or offline ETL — different path (S3 → Spark → warehouse). Don't ignore async: user-facing path should not wait for email/analytics indexing.
Alternatives
| Pattern | Sync path | Async path |
|---|---|---|
| Read-heavy | CDN → cache → DB replica | None on critical path |
| Write + notify | DB commit → return 201 | Kafka → email worker |
| Search indexing | Write DB only | CDC → ES indexer |
| Feed fan-out | Write tweet ID | Workers push to follower caches |
Execution / data flow
Client → DNS (20 ms) → TLS CDN/LB (30 ms) → App (30 ms) → Redis (1 ms) → DB (10 ms) → JSON serialize (10 ms) → Response
return 200 in 80 ms
| Hop | Typical p50 | Typical p99 | Notes |
|---|---|---|---|
| DNS + TCP + TLS | 30 ms | 80 ms | TLS session resumption helps |
| CDN (hit) | 15 ms | 40 ms | Miss adds origin RTT |
| LB | 2 ms | 5 ms | L7 slightly higher |
| App logic | 20 ms | 100 ms | GC pauses, N+1 queries |
| Redis | 0.5 ms | 2 ms | Same AZ |
| Postgres indexed | 2 ms | 15 ms | Seq scan kills p99 |
| Total target | ~80 ms | < 200 ms | Product SLA driven |
⑩ Revision checklist & interview FAQ
Use this section the night before interviews and as a mental close in the last 5 minutes of every mock. Missing items correlate with "lean no" feedback: no estimates, no trade-offs, no failure modes.
Why it matters
Checklists convert broad topics into verifiable signals. Interviewers often score on a rubric — requirements, scale, diagram, depth, trade-offs, ops. Tick each box aloud in practice until automatic.
Where to use
- Final 5 minutes of live interview wrap-up.
- Mock interview self-review.
- RFC peer review ("did we estimate QPS?").
Real use cases
Candidate designs notification system, forgets idempotency — checklist catches "failure modes + retries." Another designs cache without TTL — checklist item "invalidation + stampede" triggers fix before interviewer asks.
When NOT to use
Don't read checklist robotically for 3 minutes while interviewer wants deep dive on sharding. Use as internal mental model; verbalize only gaps relevant to the problem.
Alternatives
Rubric apps (Hello Interview grader), peer mock sheets, or company-specific ladders (Amazon L6 bar). This checklist maps to universal FAANG-style loops.
Execution / data flow
Finish deep dive → Scan checklist mentally → Verbalize 2 gaps you didn't cover → Propose monitoring + scale plan → Ask interviewer for questions
- Opened with functional + non-functional requirements
- Calculated QPS (avg + peak), storage, bandwidth with stated assumptions
- Drew CDN → LB → App → Cache → DB
- Explained vertical vs horizontal scaling with thresholds
- Named caching strategy + TTL + invalidation
- Applied CAP / consistency choice per data type (money vs likes)
- Picked SQL vs NoSQL with access-pattern justification
- Mentioned CDN for static and cacheable GET
- Async queue for non-critical work off critical path
- Failure modes: DB down, cache stampede, hot keys, partition
- Monitoring: metrics, logs, traces, SLOs, alerting
- Future scale: 10× users — what breaks first?
| Interviewer asks | Short answer | Numbers to cite |
|---|---|---|
| How do you start? | Requirements + scale estimate before boxes | DAU → QPS → peak 10× |
| SQL or NoSQL? | Joins + ACID → SQL; 200K writes/s partition → Cassandra | 5K write/s Postgres ceiling |
| When Redis? | Hot reads, sessions, rate limits — not sole money store | 90% hit → 10× DB relief |
| Strong vs eventual? | Money = strong; likes = eventual | Replica lag 100 ms–2 s |
| What breaks at 10×? | DB writes, hot keys, egress cost — in order | Plan cache before shard |
| How monitor? | p99 latency, error rate, saturation, SLO alerts | p99 < 200 ms, 99.9% avail |