◐ system-design/common-tradeoffs.md
47. Cheat Sheet: Common Trade-offs & Patterns
Quick reference. The interviewer rewards reasoning about trade-offs; this distills the recurring ones.
~6 min read·updated 5/29/2026
47. Cheat Sheet: Common Trade-offs & Patterns
Quick reference. The interviewer rewards reasoning about trade-offs; this distills the recurring ones.
47.1 Database choice
| Workload | Pick | Why |
|---|---|---|
| OLTP, relational, < 10 TB | Postgres / MySQL | ACID, joins, mature |
| OLTP, distributed-relational | Spanner, CockroachDB | global ACID |
| OLTP, KV at scale | DynamoDB, Cassandra | infinite horizontal scale |
| Document / flexible schema | Postgres JSONB > MongoDB | one DB to operate |
| Wide-column / time-series | Cassandra, Bigtable | append-mostly, sparse |
| Cache | Redis | rich types, fast |
| Search | Elasticsearch | inverted index + facets |
| Vector / embedding | pgvector / Pinecone | ANN |
| Graph | Neo4j | only when graph-deep |
| Analytics | BigQuery / Snowflake / ClickHouse | columnar, MPP |
| Object blobs | S3 / GCS | cheap, scalable |
Default: Postgres + Redis + S3 covers most early-stage products.
47.2 Consistency vs latency vs availability
- Strong consistency: linearizable. Slow (consensus). Use for: money, locks, leader, sessions.
- Eventual: cheap, fast. Use for: counters, feeds, search results, analytics.
- Per-operation choice: writes via consensus, reads from cache.
PACELC framing:
- Partition: trade A vs C.
- Else: trade L vs C.
47.3 Push vs pull
| Property | Push (write fan-out) | Pull (read fan-out) |
|---|---|---|
| Read latency | Fast | Slow |
| Write cost | High | Low |
| Stale data | Possible | Always fresh |
| Best for | Read-heavy, fixed audience | Many followers, low read |
Hybrid (Twitter): push for ordinary; pull for celebrities.
47.4 SQL vs NoSQL
- SQL when: relational integrity, joins, transactions, ad-hoc queries, < 100 TB.
- NoSQL when: massive scale (100 TB+), simple access patterns, write-heavy, schema flexibility (with care).
Modern distributed SQL collapses many "must use NoSQL" cases.
47.5 Sync vs async
- Sync (REST/gRPC) when: caller needs the result, low latency, simple flow.
- Async (queue/event) when: long-running, decoupled, fan-out, retry-friendly.
A heavy async pipeline for a simple sync need is over-engineered. The reverse is also a bug.
47.6 Monolith vs microservices
- Monolith when: < 30 engineers, single product, tight transactions.
- Microservices when: many teams, independent deploys, divergent scale needs, polyglot needs.
Modular monolith is the pragmatic stepping stone.
47.7 Caching strategies
- Cache-aside: app manages. Default.
- Write-through: writes to both. Simpler; slow writes.
- Write-behind: write to cache, async DB. Risk of loss.
- Read-through: cache library fetches. Cleaner code, less control.
- Refresh-ahead: proactive refresh. Avoids miss spike.
For invalidation: TTL + explicit invalidation + versioning. Pick based on freshness needs.
47.8 Replication
- Single-leader: simple, predictable. Default.
- Multi-leader: high write availability, conflict resolution required.
- Leaderless (Dynamo): tunable consistency, write any node, read repair.
Sync ack vs async: sync = no data loss, slow under follower issues; async = fast, possible data loss on failover.
47.9 Partitioning
- Hash: uniform load, no range queries.
- Range: range queries, hot partition risk.
- Hybrid: hash prefix + sort key (Cassandra clustering).
- Geo: locality, multi-region.
Choose partition key for: balanced load + access pattern affinity + stability.
47.10 Index choice
| Need | Index |
|---|---|
| Equality / range on one column | B-tree |
| Multi-column equality / range | Composite B-tree |
| Avoid table fetch | Covering index |
| Filter on subset | Partial index |
| Full-text | GIN trigram or Elasticsearch |
| JSONB | GIN |
| Geo | GiST + PostGIS, or H3 / S2 |
47.11 Queue choice
- Kafka: huge throughput, log retention, replay.
- RabbitMQ: complex routing, lower throughput.
- SQS: managed AWS, simple.
- Redis Streams: in-stack, low-volume.
Default to Kafka unless you specifically need RabbitMQ's routing or SQS's managed simplicity.
47.12 Event delivery
- At-most-once: send and forget.
- At-least-once + idempotent consumer = effectively once. The production pattern.
- "Exactly-once delivery" is a marketing term.
Outbox pattern always.
47.13 Real-time push
- Polling: simple, wasteful.
- Long polling: better, still HTTP.
- SSE: server → client, simple.
- WebSocket: bidirectional, complex.
- gRPC streams: internal use.
For chat: WS. For dashboards: SSE. For mobile push: APNS/FCM.
47.14 Auth model
- API key: server-to-server, simple.
- JWT (short-lived) + refresh: web/mobile sessions.
- OAuth 2.0 + OIDC: third-party / SSO.
- mTLS: zero-trust internal.
- Session cookie: classical web.
For new web app: short-lived JWT + refresh + HTTP-only Secure cookies.
47.15 Hot key mitigations
- Replicate hot key to multiple shards.
- Local in-process cache for top-N.
- CDN-cache the response.
- Rate limit aggressors.
- Compute approximate (Count-Min) instead of exact.
47.16 Counters at scale
- Don't INCR a Postgres row at 100K/sec.
- Stream events → aggregate → materialized counter.
- Sharded counters (N counters per logical key, sum on read).
- HyperLogLog for unique counts.
- Redis sorted sets for leaderboards.
47.17 Geographic / multi-region
| Pattern | When |
|---|---|
| Single-region | Most early-stage |
| Active-passive (DR) | RTO minutes-hours |
| Active-active reads | Read locality, single-region writes |
| Active-active multi-master | Highest availability; conflict resolution required |
| Distributed SQL (Spanner) | Strong consistency globally |
For most: single-region + DR plan.
47.18 ID generation
- UUID v4: random, no order.
- UUID v7 / ULID / KSUID: time-prefixed; sortable.
- Snowflake: 64-bit, time-prefixed, machine-id, sequence.
- DB autoincrement: simple, single-DB only.
- KGS: pre-allocated pools per app server.
For sharded systems: time-prefixed (Snowflake, ULID) so primary key doesn't fragment indexes.
47.19 File / blob storage
- < 1 MB and frequently accessed: maybe DB.
-
1 MB or large catalog: object storage (S3) + CDN.
- Chunk + content-address (Dropbox-style) for dedup + sync.
Never store images in your DB.
47.20 Search
- Full-text small data: Postgres + GIN trigram.
- Full-text + facets: Elasticsearch.
- Massive scale + ranking: Vespa.
- Vector / semantic: pgvector / Pinecone / Weaviate.
- Hybrid (lexical + vector): preferred for modern search UX.
47.21 Failure handling primitives
- Retry with exponential backoff + jitter.
- Circuit breaker: fail fast when downstream broken.
- Bulkhead: isolate connection pools.
- Timeout: every external call.
- Idempotency keys: every external write.
- Outbox: DB write + event atomically.
- DLQ: poison messages.
- Health checks + draining: zero-downtime ops.
- Hedging: dup request to two replicas; first wins.
47.22 Cost levers (prod)
- CDN bandwidth: ~10× cheaper than direct.
- Cache hit ratio: directly cuts DB load and storage IOPS.
- Right-sizing: monitor actual; don't over-provision.
- Spot / preemptible: 60-80% cheaper for stateless workloads.
- Tiered storage: hot (SSD) + cold (S3 IA / Glacier).
- Compression: bandwidth + storage; choose Zstd / Brotli.
- Reserved / committed use: 30-50% off for steady workloads.
47.23 What "scaling" means concretely
| Bottleneck | Mitigation |
|---|---|
| CPU on app | More instances (stateless) |
| DB read load | Read replicas; cache |
| DB write load | Sharding; queue + batch |
| Network bandwidth | CDN; compression |
| Storage | Object storage; tiered |
| Hot key | Replicate; local cache |
| Tail latency | Hedging; cache; warm pools |
| Cross-region latency | Multi-region; edge compute |
47.24 Things to mention to score points
- Observability: metrics + tracing + logging.
- SLOs / error budgets.
- Idempotency keys.
- Backpressure.
- Circuit breakers.
- Failure isolation (per-tenant, per-shard).
- Backups (with tested restores).
- Security: TLS, mTLS, KMS, secrets, OWASP.
- Compliance if domain-relevant: GDPR, PCI, HIPAA.
47.25 Things NOT to over-mention
- Microservices everywhere.
- Kubernetes for everything.
- Specific cloud product names ("we'd use AWS DocumentDB"). Talk patterns; mention products as instances.
- New shiny tech without justification.
- Re-implementing existing primitives unless asked.
Key takeaways
- Trade-offs > tools. Pick a thing because of what it gives up, not because it's hot.
- Keep a mental matrix: workload → store → consistency → scale lever.
- Defaults (Postgres + Redis + S3, push fan-out, JWT + refresh) cover most.
- Show you know the failure modes and the operational cost, not just the happy path.
// 0 views