Print this before the round. One card = one thing to recall under pressure.
| Algorithm | Use when | Gotcha |
|---|---|---|
| Round Robin | Stateless servers, uniform requests | Fails with in-memory sessions |
| Least Connection | Long-lived / variable-cost requests (SSR, uploads) | Tracks state on LB |
| IP Hashing | Must reach same server (stateful WebSocket) | Breaks if server dies; uneven distribution |
| Weighted RR | Mixed instance sizes | Manual weight tuning |
Default: round robin + Redis session store. Stateless servers = freely distributable load.
Hashed assets → max-age=31536000, immutable. HTML → no-cache (revalidate every time). Zero network cost on hit.
Cloudflare — largest PoP, Workers for edge logic. CloudFront — AWS-native, Lambda@Edge. Akamai — enterprise SLAs, media. Purge on deploy.
Sub-millisecond reads. Supports TTL, pub/sub, sorted sets, persistence. Shared across all servers. Default over Memcached unless you need pure key-value + max simplicity.
Offload SELECT traffic from primary. Acceptable replication lag for read-heavy workloads.
Caching is a consistency contract. I always state the staleness budget before picking a strategy.
| Redis | Memcached | |
|---|---|---|
| Data types | Rich (lists, sets, sorted sets, hashes, streams) | Strings only |
| Persistence | RDB + AOF | None |
| Pub/Sub | Yes | No |
| Choose | Default — almost always | Simplest possible KV cache only |
| Vertical (scale up) | Horizontal (scale out) | |
|---|---|---|
| How | Bigger machine (CPU/RAM) | More machines behind LB |
| Limit | Physical ceiling, SPOF | Effectively unlimited |
| Requirement | Nothing | Stateless app servers |
| Default for | DBs (until sharding needed) | App servers — always |
Make the app stateless first. Once sessions are in Redis, you can add servers freely — that's horizontal scaling unlocked.
Image = immutable snapshot (app + runtime + deps). Container = running instance. Registry = versioned image store (ECR, DockerHub). "Deploy" = pull image tag X and run it.
| K8s concept | What it does |
|---|---|
| Pod | One or more containers sharing a network namespace |
| Deployment | Desired replica count + rolling update strategy |
| Service | Stable virtual IP that routes to healthy pods |
| Ingress | HTTP router at cluster edge (hostname/path routing) |
| HPA | Horizontal Pod Autoscaler — scale on CPU or custom metric |
| ConfigMap/Secret | Inject env vars without baking into image |
Rolling deploy + readiness probes = zero-downtime. Rollback = kubectl rollout undo — K8s replaces pods with the previous image tag.
Terraform = provision the infra (VPC, the cluster itself, RDS, LB, DNS) — IaC, changes rarely. Docker = package the app into an immutable image — every commit. Kubernetes = run/scale/heal the images on Terraform's nodes — every deploy. Order: TF provisions cluster → Docker builds image → K8s rolls it out.
"Terraform builds the building, Docker is the standardized box, K8s is the dispatcher."
Stateful servers + round robin = random cart wipes. Fix: move session to Redis → all servers are stateless → any algo works.
Cache invalidation is hard. Define your staleness budget first: "5-second stale data is OK" changes the entire strategy.
Don't start with microservices. Start monolith → identify seams → extract. Premature split multiplies ops burden before traffic justifies it ("microservices premium").
Don't self-host K8s. Use managed EKS/GKE. As Lead you need to own the concepts, not the cluster ops.
Terraform / Docker / K8s are not interchangeable. Dividing question = infra cadence or deploy cadence? Never terraform apply to ship an app version (wrong cadence, locks state); never kubectl your VPC. TF stops at the cluster → GitOps (ArgoCD/Flux) or Helm manages in-cluster app state.