Fundamentals — Cheat Sheet
System Design · 7 topics. Download the PDF or the Instagram carousel and share it.
Horizontal vs Vertical Scaling
Vertical scaling adds more power (CPU/RAM) to a single machine; horizontal scaling adds more machines behind a load balancer. Most large-scale systems rely on horizontal scaling for elasticity and fault tolerance.
- ✓Vertical scaling = bigger machine; horizontal scaling = more machines.
- ✓Horizontal scaling requires stateless app design — push state to Redis, DB, or object storage.
- ✓Most cloud-native systems scale horizontally at the app tier and use database sharding when vertical limits are hit.
- ✓Kubernetes HPA automates horizontal scaling based on CPU, memory, or custom metrics.
- ✓Start simple (vertical) and evolve to horizontal as traffic demands grow.
// Vertical scaling example // Before: 4 CPU cores, 16 GB RAM → handles 1,000 req/s // After: 32 CPU cores, 128 GB RAM → handles ~6,000 req/s // Pros: // - Zero code changes // - No distributed-systems complexity // - Single data copy (no consistency issues) // Cons: // - Hardware ceiling (biggest EC2 = 448 vCPU / 24 TB RAM) // - Single point of failure // - Downtime for upgrades (usually) // - Cost grows faster than linearly
CAP Theorem
The CAP theorem states that a distributed system can guarantee at most two of three properties: Consistency, Availability, and Partition Tolerance. Since network partitions are inevitable, the real choice is between consistency and availability during a partition.
- ✓CAP: pick two of Consistency, Availability, Partition Tolerance — but P is mandatory in distributed systems.
- ✓CP systems sacrifice availability during partitions (e.g. MongoDB majority reads, HBase, etcd).
- ✓AP systems sacrifice consistency during partitions (e.g. Cassandra, DynamoDB eventually consistent reads).
- ✓PACELC extends CAP to cover latency vs consistency trade-offs during normal operation.
- ✓Many modern databases offer tunable consistency — choose per query or per table.
// CAP visualisation // // Consistency (C) // / \ // / \ // CP systems CA systems // (HBase, (single-node // MongoDB, RDBMS — not // etcd) distributed) // \ / // \ / // Partition Tolerance (P) // / \ // / \ // AP systems // (Cassandra, DynamoDB, // CouchDB, Riak) // \ // Availability (A) // Network partitions are INEVITABLE in distributed systems // → the real choice is C vs A during a partition.
Load Balancing
A load balancer distributes incoming traffic across multiple backend servers using algorithms like round-robin, least connections, or consistent hashing. It improves throughput, reduces latency, and provides fault tolerance.
- ✓L4 load balancers are fast (TCP level); L7 load balancers enable content-based routing (HTTP).
- ✓Common algorithms: round-robin, weighted round-robin, least connections, IP hash, consistent hashing.
- ✓Health checks automatically remove unhealthy backends and re-add them when recovered.
- ✓DNS-based load balancing provides global traffic management across regions.
- ✓Always deploy at least two load balancers for high availability (active-passive or active-active).
// L4 load balancer — TCP level
// Client → LB (picks backend by IP:port) → Backend
// Fast, simple, but no content awareness
// L7 load balancer — HTTP level (NGINX example)
upstream api_servers {
least_conn; # algorithm
server api1.internal:8080;
server api2.internal:8080;
server api3.internal:8080;
}
upstream static_servers {
server cdn1.internal:80;
server cdn2.internal:80;
}
server {
listen 443 ssl;
# Path-based routing (L7 feature)
location /api/ {
proxy_pass http://api_servers;
}
location /static/ {
proxy_pass http://static_servers;
}
}Caching Strategies
Caching stores frequently accessed data in a fast layer (memory) to reduce latency and database load. Strategies include cache-aside, read-through, write-through, write-behind, and refresh-ahead.
- ✓Cache-aside (lazy loading) is the most common strategy — app manages cache reads and invalidation.
- ✓Write-through ensures consistency but adds write latency; write-behind is faster but risks data loss.
- ✓LRU is the default eviction policy in most caches; always set a TTL to bound staleness.
- ✓Multi-layer caching (L1 in-process + L2 distributed) combines low latency with shared invalidation.
- ✓Cache invalidation is one of the hardest problems — prefer TTL-based expiry with event-driven invalidation.
// Cache-aside with Redis + Spring Boot
@Service
public class ProductService {
private final RedisTemplate<String, Product> redis;
private final ProductRepository repo;
public Product getProduct(String id) {
String key = "product:" + id;
// 1. Check cache
Product cached = redis.opsForValue().get(key);
if (cached != null) return cached; // cache HIT
// 2. Cache miss → read from DB
Product product = repo.findById(id)
.orElseThrow(() -> new NotFoundException(id));
// 3. Populate cache with TTL
redis.opsForValue().set(key, product, Duration.ofMinutes(30));
return product;
}
public Product updateProduct(String id, ProductUpdateDTO dto) {
Product updated = repo.save(/* ... */);
redis.delete("product:" + id); // invalidate cache
return updated;
}
}Content Delivery Network (CDN)
A CDN is a geographically distributed network of edge servers that cache and serve static content close to users, reducing latency and offloading origin servers.
- ✓CDNs cache content at edge servers close to users — reducing latency from hundreds of ms to single-digit ms.
- ✓Pull CDNs fetch on demand (simpler); Push CDNs distribute proactively (better for large static assets).
- ✓Cache-Control headers (max-age, s-maxage) control what CDNs cache and for how long.
- ✓Edge compute (Workers, Lambda@Edge) enables running logic at the CDN layer without origin round-trips.
- ✓CDNs also provide DDoS protection, TLS termination, and compression.
// CDN request flow
//
// User (Mumbai) → DNS → CDN Edge (Mumbai PoP)
// │
// ▼
// Cache HIT? ──yes──→ Serve from edge (< 20ms)
// │
// no
// │
// ▼
// Fetch from Origin (us-east-1) → Cache at edge → Serve user
//
// Subsequent requests from Mumbai region → served from edge cache
// Cache-Control headers control CDN behaviour
Cache-Control: public, max-age=86400, s-maxage=604800
// max-age=86400 → browser caches for 1 day
// s-maxage=604800 → CDN caches for 7 days
// public → CDN is allowed to cache this
// Invalidation
// POST /invalidation { paths: ["/images/*", "/css/main.css"] }DNS & Domain Resolution
DNS translates human-readable domain names (api.example.com) into IP addresses. Understanding DNS is essential for system design because it is the first hop of every request and enables load balancing, failover, and service discovery.
- ✓DNS is hierarchical: root → TLD → authoritative nameserver, with caching at every level.
- ✓TTL controls how long DNS responses are cached — lower TTL = faster failover but more DNS queries.
- ✓DNS-based load balancing (weighted, latency, geo) is the first layer of global traffic management.
- ✓Health-checked DNS records enable automatic regional failover.
- ✓DNS propagation delays mean changes are not instant — plan for TTL expiry during migrations.
// DNS resolution step by step // // 1. Browser cache (Chrome: chrome://net-internals/#dns) // 2. OS cache (macOS: scutil --dns) // 3. Recursive resolver (ISP / 8.8.8.8 / 1.1.1.1) // └─→ 4. Root server (.) → returns .com TLD server // └─→ 5. TLD server (.com) → returns authoritative NS for example.com // └─→ 6. Authoritative NS → returns A record: 93.184.216.34 // 7. Response cached at resolver (TTL = 300s) // 8. Response returned to OS → browser → connection to IP // dig command to inspect DNS $ dig api.example.com +trace // Shows each hop: root → .com → example.com → A record // Common record types: // A → IPv4 address (api.example.com → 1.2.3.4) // AAAA → IPv6 address // CNAME → alias to another name (www → api.example.com) // MX → mail server // TXT → verification, SPF, DKIM // NS → nameserver delegation
Latency vs Throughput
Latency is the time to complete a single request; throughput is the number of requests processed per unit time. Optimising one often impacts the other — understanding this trade-off is fundamental to system design.
- ✓Latency = time for one operation; throughput = operations per unit time.
- ✓Know key latency numbers: RAM ~100ns, SSD ~100μs, same-DC network ~500μs, cross-region ~80ms.
- ✓Batching improves throughput but increases latency; caching can improve both.
- ✓SLAs should define both latency (p50, p95, p99) and throughput (RPS) targets.
- ✓Tail latency (p99, p99.9) matters more than average in distributed systems.
// Latency numbers every programmer should know (2024) // // Operation | Latency // ───────────────────────────────────────── // L1 cache reference | 1 ns // L2 cache reference | 4 ns // RAM reference | 100 ns // SSD random read | 100 μs // HDD seek | 4,000 μs (4 ms) // Network: same datacenter | 500 μs (0.5 ms) // Network: cross-region | ~80 ms // Network: cross-continent | ~150 ms // Redis GET | ~0.5 ms // PostgreSQL simple query | ~2 ms // S3 GET (same region) | ~20 ms // External API call | 50-500 ms // Rule of thumb: memory is 1000x faster than disk, // same-DC network is 100x faster than cross-region.