System Design Mastery Journey
A 180-day, 540-hour roadmap from estimation fluency through distributed systems theory, streaming, product-system design, ML infrastructure, and reliability engineering — closing with a full mock-interview loop simulation.
Roadmap Overview
- System Design MasterySYSTEM DESIGN MASTERY JOURNEY
- 180-Day Roadmap📍 START — Day 0: Setup
- 📍 START — Day 0: SetupInstall Excalidraw / draw.io for diagramming
- 📍 START — Day 0: SetupCreate markdown notes repo (git-tracked)
- 📍 START — Day 0: SetupSet up screen+audio recording for self-review
- 📍 START — Day 0: SetupOrder/download: Designing Data-Intensive Applications
- 📍 START — Day 0: SetupBlock 3 hours/day in calendar — non-negotiable
- 180-Day Roadmap🌳 PHASE 1 — FOUNDATIONS (Days 1–25)
- 🌳 PHASE 1 — FOUNDATIONS (Days 1–25)Branch 1.1 — Estimation Fluency (Days 1–3)
- 🌳 PHASE 1 — FOUNDATIONS (Days 1–25)Branch 1.2 — Network Layer (Days 4–11)
- Branch 1.2 — Network Layer (Days 4–11)Day 4 · TCP internals: handshake, congestion control, Nagle
- Branch 1.2 — Network Layer (Days 4–11)Day 5 · UDP, QUIC — when to abandon TCP
- Branch 1.2 — Network Layer (Days 4–11)Day 6 · TLS: handshake, resumption, mTLS, cert chains
- Branch 1.2 — Network Layer (Days 4–11)Day 7 · HTTP/1.1 → HTTP/2 → HTTP/3, head-of-line blocking
- Branch 1.2 — Network Layer (Days 4–11)Day 8 · DNS: resolution, TTL, anycast, GeoDNS
- Branch 1.2 — Network Layer (Days 4–11)Day 9 · CDN architecture: PoPs, origin shield, invalidation
- Branch 1.2 — Network Layer (Days 4–11)Day 10 · Load balancing L4 vs L7, algorithms, health checks
- Branch 1.2 — Network Layer (Days 4–11)Day 11 · Reverse proxies, API gateways, service mesh basics
- 🌳 PHASE 1 — FOUNDATIONS (Days 1–25)Branch 1.3 — API Design (Days 12–15)
- Branch 1.3 — API Design (Days 12–15)Day 12 · REST: resources, idempotency, pagination patterns
- Branch 1.3 — API Design (Days 12–15)Day 13 · gRPC, protobuf, streaming RPC, schema evolution
- Branch 1.3 — API Design (Days 12–15)Day 14 · GraphQL: resolvers, N+1, federation
- Branch 1.3 — API Design (Days 12–15)Day 15 · Versioning, deprecation, contract testing
- 🌳 PHASE 1 — FOUNDATIONS (Days 1–25)Branch 1.4 — Caching Layer (Days 16–21)
- Branch 1.4 — Caching Layer (Days 16–21)Day 16 · Strategies: aside, through, behind, refresh-ahead
- Branch 1.4 — Caching Layer (Days 16–21)Day 17 · Eviction: LRU, LFU, ARC, W-TinyLFU; hit-rate math
- Branch 1.4 — Caching Layer (Days 16–21)Day 18 · Failure modes: stampede, hot key, penetration
- Branch 1.4 — Caching Layer (Days 16–21)Day 19 · Redis internals: structures, memory, RDB vs AOF
- Branch 1.4 — Caching Layer (Days 16–21)Day 20 · Redis Cluster, Sentinel, Streams, Lua
- Branch 1.4 — Caching Layer (Days 16–21)Day 21 · Multi-tier caching + coherence problems
- 🌳 PHASE 1 — FOUNDATIONS (Days 1–25)Branch 1.5 — Relational Internals (Days 22–24)
- 🌳 PHASE 1 — FOUNDATIONS (Days 1–25)🎯 GATE 1 — Day 25 · MOCK #1: URL Shortener
- 180-Day Roadmap🌳 PHASE 2 — DATA LAYER MASTERY (Days 26–50)
- 🌳 PHASE 2 — DATA LAYER MASTERY (Days 26–50)Branch 2.1 — Postgres in Production (Days 26–30)
- Branch 2.1 — Postgres in Production (Days 26–30)Day 26 · Connection pooling, PgBouncer modes, sizing math
- Branch 2.1 — Postgres in Production (Days 26–30)Day 27 · Read replicas, replication lag, read-your-writes
- Branch 2.1 — Postgres in Production (Days 26–30)Day 28 · HA: streaming replication, Patroni, split-brain
- Branch 2.1 — Postgres in Production (Days 26–30)Day 29 · Query optimization: EXPLAIN ANALYZE, join strategies
- Branch 2.1 — Postgres in Production (Days 26–30)Day 30 · Normalization vs denormalization — when to duplicate
- 🌳 PHASE 2 — DATA LAYER MASTERY (Days 26–50)Branch 2.2 — Storage Engines (Days 31–35)
- Branch 2.2 — Storage Engines (Days 31–35)Day 31 · LSM trees: memtable, SSTable, compaction
- Branch 2.2 — Storage Engines (Days 31–35)Day 32 · B-tree vs LSM: write/read/space amplification
- Branch 2.2 — Storage Engines (Days 31–35)Day 33 · Cassandra: ring, tunable consistency, hinted handoff
- Branch 2.2 — Storage Engines (Days 31–35)Day 34 · DynamoDB: partition keys, GSI/LSI, single-table design
- Branch 2.2 — Storage Engines (Days 31–35)Day 35 · Hot partitions and write-sharding mitigation
- 🌳 PHASE 2 — DATA LAYER MASTERY (Days 26–50)Branch 2.3 — Non-Relational & Files (Days 36–40)
- Branch 2.3 — Non-Relational & Files (Days 36–40)Day 36 · Document stores: MongoDB, embedded vs referenced
- Branch 2.3 — Non-Relational & Files (Days 36–40)Day 37 · Object storage: S3 internals, multipart, lifecycle
- Branch 2.3 — Non-Relational & Files (Days 36–40)Day 38 · Content-addressed storage, chunking, Rabin dedup
- Branch 2.3 — Non-Relational & Files (Days 36–40)Day 39 · Distributed FS: GFS, HDFS, Colossus
- Branch 2.3 — Non-Relational & Files (Days 36–40)Day 40 · Distributed SQL: Spanner, CockroachDB, TiDB, Vitess
- 🌳 PHASE 2 — DATA LAYER MASTERY (Days 26–50)Branch 2.4 — Search Infrastructure (Days 41–45)
- Branch 2.4 — Search Infrastructure (Days 41–45)Day 41 · Inverted indexes, postings, compression, skip lists
- Branch 2.4 — Search Infrastructure (Days 41–45)Day 42 · Tokenization, analyzers, stemming, n-grams
- Branch 2.4 — Search Infrastructure (Days 41–45)Day 43 · Scoring: TF-IDF, BM25, precision vs recall
- Branch 2.4 — Search Infrastructure (Days 41–45)Day 44 · Elasticsearch architecture, shard sizing math
- Branch 2.4 — Search Infrastructure (Days 41–45)Day 45 · ES at scale: refresh, bulk index, hot-warm-cold
- 🌳 PHASE 2 — DATA LAYER MASTERY (Days 26–50)Branch 2.5 — Probabilistic & Hashing (Days 46–49)
- Branch 2.5 — Probabilistic & Hashing (Days 46–49)Day 46 · Vector search: embeddings, HNSW, IVF, hybrid
- Branch 2.5 — Probabilistic & Hashing (Days 46–49)Day 47 · Bloom, Cuckoo, quotient filters; false-positive math
- Branch 2.5 — Probabilistic & Hashing (Days 46–49)Day 48 · HyperLogLog, Count-Min Sketch
- Branch 2.5 — Probabilistic & Hashing (Days 46–49)Day 49 · Consistent hashing, jump hash, rendezvous hashing
- 🌳 PHASE 2 — DATA LAYER MASTERY (Days 26–50)🎯 GATE 2 — Day 50 · MOCK #2: Distributed Key-Value Store
- 180-Day Roadmap🌳 PHASE 3 — DISTRIBUTED SYSTEMS THEORY (Days 51–75)
- 🌳 PHASE 3 — DISTRIBUTED SYSTEMS THEORY (Days 51–75)Branch 3.1 — Consistency Foundations (Days 51–53)
- Branch 3.1 — Consistency Foundations (Days 51–53)Day 51 · CAP — what it actually says, and common misuses
- Branch 3.1 — Consistency Foundations (Days 51–53)Day 52 · PACELC; classify five real systems
- Branch 3.1 — Consistency Foundations (Days 51–53)Day 53 · Full spectrum: linearizable → eventual; session guarantees
- 🌳 PHASE 3 — DISTRIBUTED SYSTEMS THEORY (Days 51–75)Branch 3.2 — Replication & Partitioning (Days 54–59)
- Branch 3.2 — Replication & Partitioning (Days 54–59)Day 54 · Single-leader mechanics, failover pitfalls, lost updates
- Branch 3.2 — Replication & Partitioning (Days 54–59)Day 55 · Multi-leader, conflict detection, geo-distributed writes
- Branch 3.2 — Replication & Partitioning (Days 54–59)Day 56 · Leaderless (Dynamo-style), quorums, W+R>N math
- Branch 3.2 — Replication & Partitioning (Days 54–59)Day 57 · Anti-entropy, Merkle trees, gossip protocols
- Branch 3.2 — Replication & Partitioning (Days 54–59)Day 58 · Secondary indexes in partitioned data: local vs global
- Branch 3.2 — Replication & Partitioning (Days 54–59)Day 59 · Rebalancing, request routing, ZooKeeper/etcd
- 🌳 PHASE 3 — DISTRIBUTED SYSTEMS THEORY (Days 51–75)Branch 3.3 — Consensus (Days 60–63)
- Branch 3.3 — Consensus (Days 60–63)Day 60 · Paxos conceptually; safety vs liveness
- Branch 3.3 — Consensus (Days 60–63)Day 61 · Raft: election, log replication, membership change
- Branch 3.3 — Consensus (Days 60–63)Day 62 · Split brain, fencing tokens, STONITH + real postmortems
- Branch 3.3 — Consensus (Days 60–63)Day 63 · Distributed locks, lease expiry, the Redlock debate
- 🌳 PHASE 3 — DISTRIBUTED SYSTEMS THEORY (Days 51–75)Branch 3.4 — Time & Causality (Days 64–66)
- 🌳 PHASE 3 — DISTRIBUTED SYSTEMS THEORY (Days 51–75)Branch 3.5 — Transactions Across Services (Days 67–70)
- Branch 3.5 — Transactions Across Services (Days 67–70)Day 67 · 2PC: protocol, blocking problem, why it's avoided
- Branch 3.5 — Transactions Across Services (Days 67–70)Day 68 · Sagas: choreography vs orchestration, compensation
- Branch 3.5 — Transactions Across Services (Days 67–70)Day 69 · Outbox pattern, transactional messaging, CDC correctness
- Branch 3.5 — Transactions Across Services (Days 67–70)Day 70 · Idempotency keys, dedup windows, "effectively-once"
- 🌳 PHASE 3 — DISTRIBUTED SYSTEMS THEORY (Days 51–75)Branch 3.6 — Failure Reasoning (Days 71–74)
- Branch 3.6 — Failure Reasoning (Days 71–74)Day 71 · Failure detection, phi-accrual, timeouts vs correctness
- Branch 3.6 — Failure Reasoning (Days 71–74)Day 72 · Byzantine faults — and why they usually don't matter
- Branch 3.6 — Failure Reasoning (Days 71–74)Day 73 · Invariants, safety and liveness properties
- Branch 3.6 — Failure Reasoning (Days 71–74)Day 74 · Consolidation: explain all of Phase 3 aloud, no notes
- 🌳 PHASE 3 — DISTRIBUTED SYSTEMS THEORY (Days 51–75)🎯 GATE 3 — Day 75 · MOCK #3: Distributed Transaction / Booking System
- 180-Day Roadmap🌳 PHASE 4 — STREAMING & EVENT-DRIVEN (Days 76–95)
- 🌳 PHASE 4 — STREAMING & EVENT-DRIVEN (Days 76–95)Branch 4.1 — Messaging Fundamentals (Days 76–77)
- 🌳 PHASE 4 — STREAMING & EVENT-DRIVEN (Days 76–95)Branch 4.2 — Kafka Deep Dive (Days 78–81)
- Branch 4.2 — Kafka Deep Dive (Days 78–81)Day 78 · Architecture: partitions, segments, ISR, controller
- Branch 4.2 — Kafka Deep Dive (Days 78–81)Day 79 · Producers: batching, acks, idempotent producer
- Branch 4.2 — Kafka Deep Dive (Days 78–81)Day 80 · Consumer groups, rebalancing, sticky assignment
- Branch 4.2 — Kafka Deep Dive (Days 78–81)Day 81 · Log compaction, retention, tiered storage
- 🌳 PHASE 4 — STREAMING & EVENT-DRIVEN (Days 76–95)Branch 4.3 — Stream Processing (Days 82–86)
- Branch 4.3 — Stream Processing (Days 82–86)Day 82 · Kafka Streams / Flink, local state stores
- Branch 4.3 — Stream Processing (Days 82–86)Day 83 · Windowing: tumbling, sliding, session; watermarks
- Branch 4.3 — Stream Processing (Days 82–86)Day 84 · Event sourcing: replay, snapshots, tradeoffs
- Branch 4.3 — Stream Processing (Days 82–86)Day 85 · CQRS: read/write separation, projection lag
- Branch 4.3 — Stream Processing (Days 82–86)Day 86 · Exactly-once in streams; Flink checkpointing
- 🌳 PHASE 4 — STREAMING & EVENT-DRIVEN (Days 76–95)Branch 4.4 — Operational Streaming (Days 87–89)
- Branch 4.4 — Operational Streaming (Days 87–89)Day 87 · Schema registry, Avro/Protobuf compatibility modes
- Branch 4.4 — Operational Streaming (Days 87–89)Day 88 · DLQs, poison pills, retry topics
- Branch 4.4 — Operational Streaming (Days 87–89)Day 89 · Pulsar, NATS, SQS/SNS, Kinesis — selection criteria
- 🌳 PHASE 4 — STREAMING & EVENT-DRIVEN (Days 76–95)Branch 4.5 — Analytics Storage (Days 90–94)
- Branch 4.5 — Analytics Storage (Days 90–94)Day 90 · Lambda vs Kappa vs unified; reprocessing strategy
- Branch 4.5 — Analytics Storage (Days 90–94)Day 91 · Lakehouse, Iceberg/Delta table formats
- Branch 4.5 — Analytics Storage (Days 90–94)Day 92 · Parquet, ORC, encoding, predicate pushdown
- Branch 4.5 — Analytics Storage (Days 90–94)Day 93 · ClickHouse, Druid, Pinot
- Branch 4.5 — Analytics Storage (Days 90–94)Day 94 · Time-series: downsampling, cardinality, retention
- 🌳 PHASE 4 — STREAMING & EVENT-DRIVEN (Days 76–95)🎯 GATE 4 — Day 95 · MOCK #4: Real-Time Analytics Pipeline
- 180-Day Roadmap🌳 PHASE 5 — PRODUCT SYSTEMS I (Days 96–120)
- 🌳 PHASE 5 — PRODUCT SYSTEMS I (Days 96–120)Branch 5.1 — Feed & Social Graph (Days 96–99)
- Branch 5.1 — Feed & Social Graph (Days 96–99)Day 96 · Fanout-on-write vs read vs hybrid; celebrity problem
- Branch 5.1 — Feed & Social Graph (Days 96–99)Day 97 · Ranking: freshness decay, engagement signals
- Branch 5.1 — Feed & Social Graph (Days 96–99)Day 98 · Social graph storage, adjacency, TAO-style design
- Branch 5.1 — Feed & Social Graph (Days 96–99)Day 99 · Graph DBs, traversal cost, denormalized edges
- 🌳 PHASE 5 — PRODUCT SYSTEMS I (Days 96–120)🎯 CHECKPOINT — Day 100 · MOCK #5: News Feed (Twitter/Instagram)
- 🌳 PHASE 5 — PRODUCT SYSTEMS I (Days 96–120)Branch 5.2 — Realtime & Messaging (Days 101–110)
- Branch 5.2 — Realtime & Messaging (Days 101–110)Day 101 · WebSocket, SSE, long-poll — connection scaling
- Branch 5.2 — Realtime & Messaging (Days 101–110)Day 102 · Connection gateways, sticky routing, the C10M problem
- Branch 5.2 — Realtime & Messaging (Days 101–110)Day 103 · Message IDs, ordering, gap detection, sequence numbers
- Branch 5.2 — Realtime & Messaging (Days 101–110)Day 104 · Delivery receipts, read state, multi-device fanout
- Branch 5.2 — Realtime & Messaging (Days 101–110)Day 105 · Offline queues, sync protocol, cold start
- Branch 5.2 — Realtime & Messaging (Days 101–110)Day 106 · Group fanout, large groups, broadcast amplification
- Branch 5.2 — Realtime & Messaging (Days 101–110)Day 107 · Presence & typing indicators — cheap approximations
- Branch 5.2 — Realtime & Messaging (Days 101–110)Day 108 · E2E encryption: Signal protocol, design implications
- Branch 5.2 — Realtime & Messaging (Days 101–110)Day 109 · Push infra: APNs/FCM, tokens, retries, priorities
- Branch 5.2 — Realtime & Messaging (Days 101–110)Day 110 · Notification dedup, batching, digest, quiet hours
- 🌳 PHASE 5 — PRODUCT SYSTEMS I (Days 96–120)🎯 CHECKPOINT — Day 111 · MOCK #6: WhatsApp / Messenger
- 🌳 PHASE 5 — PRODUCT SYSTEMS I (Days 96–120)Branch 5.3 — Search & Crawl (Days 112–115)
- Branch 5.3 — Search & Crawl (Days 112–115)Day 112 · Autocomplete: tries, top-k, prefix sharding
- Branch 5.3 — Search & Crawl (Days 112–115)Day 113 · Ranking pipeline: retrieval → ranking → blending
- Branch 5.3 — Search & Crawl (Days 112–115)Day 114 · Web crawler: frontier, politeness, freshness
- Branch 5.3 — Search & Crawl (Days 112–115)Day 115 · Near-duplicate detection: SimHash, MinHash, shingling
- 🌳 PHASE 5 — PRODUCT SYSTEMS I (Days 96–120)Branch 5.4 — Traffic Control & Abuse (Days 116–119)
- Branch 5.4 — Traffic Control & Abuse (Days 116–119)Day 116 · Token/leaky bucket, sliding window — comparison
- Branch 5.4 — Traffic Control & Abuse (Days 116–119)Day 117 · Distributed rate limiting: local+global hybrid
- Branch 5.4 — Traffic Control & Abuse (Days 116–119)Day 118 · Bot detection, fingerprinting, CAPTCHA tradeoffs
- Branch 5.4 — Traffic Control & Abuse (Days 116–119)Day 119 · DDoS mitigation layers, scrubbing, edge rules
- 🌳 PHASE 5 — PRODUCT SYSTEMS I (Days 96–120)🎯 GATE 5 — Day 120 · MOCK #7: Distributed Rate Limiter + Abuse Defense
- 180-Day Roadmap🌳 PHASE 6 — PRODUCT SYSTEMS II (Days 121–145)
- 🌳 PHASE 6 — PRODUCT SYSTEMS II (Days 121–145)Branch 6.1 — Video & Streaming (Days 121–126)
- Branch 6.1 — Video & Streaming (Days 121–126)Day 121 · Chunked resumable upload, validation, ingest
- Branch 6.1 — Video & Streaming (Days 121–126)Day 122 · Transcoding: ladders, codecs, GPU farms, orchestration
- Branch 6.1 — Video & Streaming (Days 121–126)Day 123 · Packaging: HLS, DASH, CMAF, DRM basics
- Branch 6.1 — Video & Streaming (Days 121–126)Day 124 · Adaptive bitrate: player heuristics, buffer models, QoE
- Branch 6.1 — Video & Streaming (Days 121–126)Day 125 · Netflix Open Connect, ISP embedding, prepositioning
- Branch 6.1 — Video & Streaming (Days 121–126)Day 126 · Live: ingest, LL-HLS, WebRTC, fanout tree, latency budget
- 🌳 PHASE 6 — PRODUCT SYSTEMS II (Days 121–145)🎯 CHECKPOINT — Day 127 · MOCK #8: YouTube / Netflix
- 🌳 PHASE 6 — PRODUCT SYSTEMS II (Days 121–145)Branch 6.2 — Geospatial & Matching (Days 128–131)
- Branch 6.2 — Geospatial & Matching (Days 128–131)Day 128 · Geohash, quadtree, S2, H3 — query patterns
- Branch 6.2 — Geospatial & Matching (Days 128–131)Day 129 · Proximity search, k-nearest, dynamic objects
- Branch 6.2 — Geospatial & Matching (Days 128–131)Day 130 · Ride matching: supply/demand, dispatch, surge
- Branch 6.2 — Geospatial & Matching (Days 128–131)Day 131 · ETA prediction, routing, map-matching
- 🌳 PHASE 6 — PRODUCT SYSTEMS II (Days 121–145)🎯 CHECKPOINT — Day 132 · MOCK #9: Uber / Lyft Dispatch
- 🌳 PHASE 6 — PRODUCT SYSTEMS II (Days 121–145)Branch 6.3 — Money & Correctness (Days 133–136)
- Branch 6.3 — Money & Correctness (Days 133–136)Day 133 · Inventory: holds, TTL reservations, oversell policy
- Branch 6.3 — Money & Correctness (Days 133–136)Day 134 · Double-entry ledger, immutability, reconciliation
- Branch 6.3 — Money & Correctness (Days 133–136)Day 135 · Auth, capture, refund, chargeback; idempotency keys
- Branch 6.3 — Money & Correctness (Days 133–136)Day 136 · Fraud: rules + ML, velocity checks, graph signals
- 🌳 PHASE 6 — PRODUCT SYSTEMS II (Days 121–145)🎯 CHECKPOINT — Day 137 · MOCK #10: Payment / Ledger System
- 🌳 PHASE 6 — PRODUCT SYSTEMS II (Days 121–145)Branch 6.4 — Collaboration & Sync (Days 138–141)
- Branch 6.4 — Collaboration & Sync (Days 138–141)Day 138 · Operational transform mechanics (Google Docs lineage)
- Branch 6.4 — Collaboration & Sync (Days 138–141)Day 139 · CRDTs: state-based vs op-based, convergence
- Branch 6.4 — Collaboration & Sync (Days 138–141)Day 140 · Cursor/presence sync, undo in collaborative context
- Branch 6.4 — Collaboration & Sync (Days 138–141)Day 141 · File sync: delta sync, conflict resolution, versioning
- 🌳 PHASE 6 — PRODUCT SYSTEMS II (Days 121–145)Branch 6.5 — Orchestration (Days 142–144)
- 🌳 PHASE 6 — PRODUCT SYSTEMS II (Days 121–145)🎯 GATE 6 — Day 145 · MOCK #11: Google Drive / Collaborative Docs
- 180-Day Roadmap🌳 PHASE 7 — ML & MODERN INFRASTRUCTURE (Days 146–160)
- 🌳 PHASE 7 — ML & MODERN INFRASTRUCTURE (Days 146–160)Branch 7.1 — Recommendation & Serving (Days 146–150)
- Branch 7.1 — Recommendation & Serving (Days 146–150)Day 146 · Candidate gen → ranking → policy (multi-stage)
- Branch 7.1 — Recommendation & Serving (Days 146–150)Day 147 · Feature stores, online/offline parity, training-serving skew
- Branch 7.1 — Recommendation & Serving (Days 146–150)Day 148 · Embedding retrieval at scale, ANN serving
- Branch 7.1 — Recommendation & Serving (Days 146–150)Day 149 · Model serving: batching, GPU utilization, latency budgets
- Branch 7.1 — Recommendation & Serving (Days 146–150)Day 150 · A/B infra: assignment, guardrails, interference
- 🌳 PHASE 7 — ML & MODERN INFRASTRUCTURE (Days 146–160)🎯 CHECKPOINT — Day 151 · MOCK #12: Recommendation System
- 🌳 PHASE 7 — ML & MODERN INFRASTRUCTURE (Days 146–160)Branch 7.2 — LLM Infrastructure (Days 152–155)
- Branch 7.2 — LLM Infrastructure (Days 152–155)Day 152 · KV cache, continuous batching, speculative decoding
- Branch 7.2 — LLM Infrastructure (Days 152–155)Day 153 · RAG: chunking, retrieval, reranking, evaluation
- Branch 7.2 — LLM Infrastructure (Days 152–155)Day 154 · Vector DB internals: HNSW tuning, filtering, freshness
- Branch 7.2 — LLM Infrastructure (Days 152–155)Day 155 · Prompt/context pipelines, caching, cost control
- 🌳 PHASE 7 — ML & MODERN INFRASTRUCTURE (Days 146–160)🎯 CHECKPOINT — Day 156 · MOCK #13: LLM-Powered Product (RAG at scale)
- 🌳 PHASE 7 — ML & MODERN INFRASTRUCTURE (Days 146–160)Branch 7.3 — Platform & Economics (Days 157–160)
- Branch 7.3 — Platform & Economics (Days 157–160)Day 157 · Kubernetes for design interviews: scheduling, HPA, operators
- Branch 7.3 — Platform & Economics (Days 157–160)Day 158 · Service mesh, sidecars, mTLS — and when it's overkill
- Branch 7.3 — Platform & Economics (Days 157–160)Day 159 · Serverless, cold starts, edge compute — fit and misfit
- Branch 7.3 — Platform & Economics (Days 157–160)Day 160 · Cost engineering: unit economics, egress, tiering, spot
- 180-Day Roadmap🌳 PHASE 8 — RELIABILITY & OPERATIONS (Days 161–175)
- 🌳 PHASE 8 — RELIABILITY & OPERATIONS (Days 161–175)Branch 8.1 — Measuring Reliability (Days 161–164)
- Branch 8.1 — Measuring Reliability (Days 161–164)Day 161 · SLI/SLO/SLA, error budgets, nines arithmetic
- Branch 8.1 — Measuring Reliability (Days 161–164)Day 162 · Metrics vs logs vs traces; cardinality traps, telemetry cost
- Branch 8.1 — Measuring Reliability (Days 161–164)Day 163 · Distributed tracing, sampling, context propagation
- Branch 8.1 — Measuring Reliability (Days 161–164)Day 164 · Alerting: symptom vs cause, on-call, runbooks, incident command
- 🌳 PHASE 8 — RELIABILITY & OPERATIONS (Days 161–175)Branch 8.2 — Failure Engineering (Days 165–169)
- Branch 8.2 — Failure Engineering (Days 165–169)Day 165 · Cascading failures, retry storms, thundering herd, jitter
- Branch 8.2 — Failure Engineering (Days 165–169)Day 166 · Load shedding, admission control, priority queues, brownout
- Branch 8.2 — Failure Engineering (Days 165–169)Day 167 · Circuit breakers, bulkheads, timeout hierarchies
- Branch 8.2 — Failure Engineering (Days 165–169)Day 168 · Chaos engineering, fault injection, game days
- Branch 8.2 — Failure Engineering (Days 165–169)Day 169 · Capacity planning, autoscaling, headroom, load testing
- 🌳 PHASE 8 — RELIABILITY & OPERATIONS (Days 161–175)Branch 8.3 — Change & Recovery (Days 170–172)
- Branch 8.3 — Change & Recovery (Days 170–172)Day 170 · Blue-green, canary, progressive rollout, auto-rollback
- Branch 8.3 — Change & Recovery (Days 170–172)Day 171 · Online schema migration, expand-contract, dual-write, backfill
- Branch 8.3 — Change & Recovery (Days 170–172)Day 172 · DR: RPO/RTO, backups, region evacuation, drills
- 🌳 PHASE 8 — RELIABILITY & OPERATIONS (Days 161–175)Branch 8.4 — Security (Days 173–174)
- 🌳 PHASE 8 — RELIABILITY & OPERATIONS (Days 161–175)🎯 GATE 8 — Day 175 · MOCK #14: Monitoring / Observability Platform
- 180-Day Roadmap🌳 PHASE 9 — INTERVIEW CRAFT & LOOP SIMULATION (Days 176–180)
- 🌳 PHASE 9 — INTERVIEW CRAFT & LOOP SIMULATION (Days 176–180)Branch 9.1 — Performance Mechanics (Day 176)
- 🌳 PHASE 9 — INTERVIEW CRAFT & LOOP SIMULATION (Days 176–180)Branch 9.2 — Your Story (Day 177)
- 🌳 PHASE 9 — INTERVIEW CRAFT & LOOP SIMULATION (Days 176–180)Branch 9.3 — Company Calibration (Days 178–179)
- 🌳 PHASE 9 — INTERVIEW CRAFT & LOOP SIMULATION (Days 176–180)🏁 FINAL GATE — Day 180
- 180-Day Roadmap🔁 PARALLEL TRACKS — run alongside all 180 days
Click any node to jump to that step ↓
Steps
SYSTEM DESIGN MASTERY JOURNEY
What: A complete, self-paced curriculum for reaching system-design interview mastery in 180 days at 3 hours/day (540 hours total), ending in 20 scored mock interviews.
How to complete: Work top to bottom: Day 0 setup, then Phases 1–9 in strict order (each gates the next), running the 3 parallel tracks every week throughout. Legend: ⭐ = your existing strength (rehearse articulation, don't re-learn) · 🎯 = scored mock interview · 🔑 = phase gate.
📍 START — Day 0: Setup
What: The one-time logistics day before the clock starts — every tool and habit you'll lean on for the next 180 days gets set up once, here, so it never becomes friction later.
How to complete: Work through all five setup items today, before Day 1. None of them are graded — you're done when the tools are installed and the calendar block exists.
Install Excalidraw / draw.io for diagramming
What: A whiteboarding tool for sketching system diagrams — boxes, arrows, databases, queues — the same visual language interviewers expect on a whiteboard.
How to complete: Install one (Excalidraw is faster to start with, browser-based, no account needed) and draw one throwaway diagram today just to learn the shortcuts.
Create markdown notes repo (git-tracked)
What: A single git repository where every day's notes live as markdown files, giving you a searchable, versioned record of 180 days of learning.
How to complete: Create a repo (e.g. system-design-notes), one markdown file per day or topic, and commit at the end of every study session — even short notes.
Set up screen+audio recording for self-review
What: A way to record yourself talking through a design out loud, so you can watch it back later the way an interviewer would experience it.
How to complete: Install OBS (or QuickTime/any screen recorder) and test it once now — record 60 seconds of you explaining any diagram, then play it back.
Order/download: Designing Data-Intensive Applications
What: The single most-referenced system design book, covering storage engines, replication, partitioning, and consistency in more depth than any blog post.
How to complete: Get a copy today (physical or ebook) — you'll be reading targeted chapters alongside Phases 1–3, not cover to cover in one sitting.
Block 3 hours/day in calendar — non-negotiable
What: The actual time budget this entire 180-day plan is built on — without it reserved, every other day slips.
How to complete: Open your calendar right now and create a recurring 3-hour daily block for the next 180 days before you close this tab.
🌳 PHASE 1 — FOUNDATIONS (Days 1–25)
Phase 1 হলো পুরো System Design Mastery-এর সবচেয়ে গুরুত্বপূর্ণ ভিত্তি। এটি তোমার পুরো ১৮০ দিনের যাত্রার নোঙ্গর (Anchor)।
একজন সাধারণ সফটওয়্যার ডেভেলপার এবং একজন সিস্টেম আর্কিটেক্টের মধ্যে প্রধান পার্থক্য তৈরি হয় এই ২৫ দিনে। কারণ এখানে আমরা সিস্টেম ডিজাইনের Fundamental Building Blocks বা মৌলিক উপাদানগুলো এমনভাবে আয়ত্ত করব যেন যেকোনো প্রশ্নের উত্তর দেওয়ার সময় তোমার যুক্তি গাণিতিকভাবে এবং টেকনিক্যালি নিখুঁত হয়।
🎯 Phase 1-এর মূল লক্ষ্য (Primary Goal)
এই ২৫ দিনের মূল লক্ষ্য হলো Estimation, Networking, Caching, এবং Relational Database Internals-এ এমন দক্ষতা তৈরি করা যাতে যেকোনো সিস্টেম হ্যান্ডেল করার ক্ষমতা তোমার নখদর্পণে থাকে।
**Phase 1 Exit Criteria (২৫ দিন পর তোমার যোগ্যতা যা হতে হবে):**১. যেকোনো সিস্টেমের স্কেল (QPS, Storage, Bandwidth) কোনো নোট ছাড়া খাতার পাতায় ৫ মিনিটের মধ্যে নির্ভুলভাবে হিসাব (Size) করতে পারা।২. একটি HTTP Request ব্রাউজার থেকে শুরু করে লোড ব্যালেন্সার, এপিআই গেটওয়ে, ক্যাশ পার হয়ে ডেটাবেজ পর্যন্ত কীভাবে যায় এবং উত্তর কীভাবে ফিরে আসে—তার পুরো পথ নোটিশ ছাড়া নিখুঁতভাবে ব্যাখ্যা করতে পারা।
Branch 1.1 — Estimation Fluency (Days 1–3)
System Design Mastery Curriculum — Phase 1, Day 0 (Prerequisite Module) এই ডকুমেন্ট Day 1 (Latency Numbers)-এর আগে পড়ার জন্য। এখানে system-design-specific কিছু নেই (সেটা Day 1-3-এ আসবে) — এখানে শুধু সেই মৌলিক গাণিতিক ও চিন্তার স্কিলগুলো আছে যেগুলো ছাড়া Day 1-3-এর কোনো সংখ্যাই সহজে আয়ত্ত হবে না।
সূচিপত্র
- Back-of-the-Envelope / Fermi Estimation আসলে কী, এবং কেন এটা একটা আলাদা স্কিল
- Powers of Ten — সংখ্যার সাথে সাবলীলতা (এখানেই ভিত্তি তৈরি হয়)
- Scientific Notation দিয়ে দ্রুত গুণ-ভাগ করা
- Order-of-Magnitude চিন্তাভাবনা — নির্ভুলতার বদলে সঠিক দিক
- Assumption বলার শৃঙ্খলা (Discipline of Stating Assumptions)
- General Fermi Problems — সিস্টেম ডিজাইনের বাইরে, বিশুদ্ধ অনুশীলন
- Sanity-Check করার মানসিকতা
- Self-Diagnostic — Day 1 শুরু করার আগে নিজেকে যাচাই করো
১. Back-of-the-Envelope / Fermi Estimation আসলে কী
পদার্থবিজ্ঞানী Enrico Fermi বিখ্যাত ছিলেন এমন প্রশ্নের প্রায়-নির্ভুল উত্তর কয়েক মিনিটে বের করার জন্য যেগুলোর কোনো সরাসরি ডেটা নেই — যেমন "শিকাগো শহরে কতজন পিয়ানো টিউনার আছে?" এই টেকনিকের মূল দর্শন:
একটা জটিল, অজানা সংখ্যাকে কয়েকটা ছোট ছোট, অনুমানযোগ্য সংখ্যার গুণফলে ভেঙে ফেলো, যেখানে প্রতিটা ছোট সংখ্যা তুমি reasonably অনুমান করতে পারো।
এটা "গণনা" (calculation) না, এটা "structured guessing" — আর এই পার্থক্যটা বোঝা জরুরি। তুমি সঠিক উত্তর চাইছো না, তুমি চাইছো সঠিক অর্ডার অফ ম্যাগনিটিউড (যেমন উত্তরটা কি হাজারে, নাকি লাখে, নাকি কোটিতে) — আর সেই উত্তরে পৌঁছানোর যুক্তিটা স্পষ্ট ও defensible হওয়া।
কেন সিস্টেম ডিজাইন ইন্টারভিউতে এই একই টেকনিক ব্যবহার হয়: "আমাদের সিস্টেমে কত QPS আসবে?" প্রশ্নটা আসলে "শিকাগোতে কতজন পিয়ানো টিউনার" প্রশ্নের মতোই — তোমার কাছে সরাসরি ডেটা নেই, কিন্তু তুমি এটাকে ছোট ছোট অনুমানযোগ্য অংশে ভেঙে (DAU × actions/user/day ÷ seconds/day) একটা defensible সংখ্যায় পৌঁছাতে পারো।
তিনটা মূলনীতি যা পুরো curriculum জুড়ে কাজে লাগবে:
- বিভাজন (Decomposition) — বড় অজানা প্রশ্নকে ছোট ছোট জানা/অনুমানযোগ্য প্রশ্নে ভাঙো
- অনুমানে সততা (Honest Assumptions) — প্রতিটা অনুমান জোরে বলো, লুকিয়ে রেখো না
- নির্ভুলতা না, দিক ঠিক রাখা (Direction over Precision) — 3 নাকি 3.5 সেটা নিয়ে সময় নষ্ট না করে, উত্তরটা 10-এর কোন power-এ পড়ছে সেটাই গুরুত্বপূর্ণ
২. Powers of Ten — সংখ্যার সাথে সাবলীলতা
এটাই সবচেয়ে গুরুত্বপূর্ণ ফাউন্ডেশনাল স্কিল। Day 1-3-এর প্রতিটা হিসেব powers-of-ten notation-এ হবে, তাই এখানে সাবলীল হওয়া মানে বাকি সব কিছু সহজ হয়ে যাওয়া।
বেসিক টেবিল — মুখস্থ করো, চোখ বন্ধ করেও বলতে পারতে হবে
| Power | সংখ্যা | নাম (আন্তর্জাতিক) |
|---|---|---|
| 10⁰ | 1 | এক |
| 10³ | 1,000 | হাজার (thousand) |
| 10⁶ | 1,000,000 | মিলিয়ন (দশ লাখ) |
| 10⁹ | 1,000,000,000 | বিলিয়ন (একশ কোটি) |
| 10¹² | 1,000,000,000,000 | ট্রিলিয়ন (দশ লাখ কোটি) |
| 10¹⁵ | ... | কোয়াড্রিলিয়ন (পেটা-স্কেল) |
গুরুত্বপূর্ণ সতর্কতা — বাংলা সংখ্যা পদ্ধতির সাথে conflict: বাংলায় আমরা লাখ (10⁵), কোটি (10⁷) ব্যবহার করি, কিন্তু আন্তর্জাতিক টেক ইন্ডাস্ট্রি এবং ইন্টারভিউ সবসময় million/billion (10⁶/10⁹) স্কেলে কথা বলে। ইন্টারভিউতে সবসময় million/billion-এ চিন্তা করার অভ্যাস করো, মাঝপথে লাখ-কোটিতে রূপান্তর করলে confusion এবং ভুল হওয়ার ঝুঁকি বাড়ে।
1 million = 10⁶ = 10 লাখ
1 billion = 10⁹ = 100 কোটি
দ্রুত গুণের নিয়ম — Exponent যোগ করো
10^a × 10^b = 10^(a+b)
উদাহরণ: 10³ × 10⁴ = 10⁷
কোনো সংখ্যাকে coefficient × 10^n আকারে লিখলে (যেমন 3 × 10⁵), গুণ করার সময়:
(3 × 10⁵) × (2 × 10⁴) = (3×2) × 10^(5+4) = 6 × 10⁹
এই একটা নিয়ম জানা থাকলে বড় বড় সংখ্যা মাথায় মাথায় গুণ করা সম্ভব হয়ে যায়, ক্যালকুলেটর ছাড়াই।
দ্রুত ভাগের নিয়ম — Exponent বিয়োগ করো
10^a ÷ 10^b = 10^(a-b)
উদাহরণ: (6 × 10⁸) ÷ (10⁵) = 6 × 10^(8-5) = 6 × 10³ = 6,000
এটাই Day 2-তে "daily total ÷ 10⁵ সেকেন্ড = QPS" হিসেবের ঠিক ভিত্তি — এখন বুঝবে কেন এই ভাগটা এত দ্রুত করা যায়।
অনুশীলন (নিজে মুখে মুখে করো)
১. 4 × 10⁶ × 5 × 10³ = ?
২. (9 × 10⁹) ÷ (3 × 10⁵) = ?
৩. 2.5 × 10⁷ কে million-এ প্রকাশ করো
৪. 800,000,000 কে scientific notation-এ লেখো
৫. 10¹² ÷ 10⁶ = ? (এবং এটা কোন নাম, million নাকি billion?)
(উত্তর নিচে §8-এ)
৩. Scientific Notation দিয়ে দ্রুত গুণ-ভাগ করা — বাস্তব উদাহরণ দিয়ে
চলো একটা সম্পূর্ণ, সিস্টেম-ডিজাইন-নিরপেক্ষ (non-system-design) উদাহরণ দিয়ে পুরো প্রক্রিয়াটা practice করি, যাতে Day 1-এ পৌঁছানোর আগেই তুমি এই যান্ত্রিকতায় (mechanics) সাবলীল হয়ে যাও।
প্রশ্ন: একটা বইয়ের দোকান চেইনে সারা দেশে 2,000টা শাখা আছে। প্রতিটা শাখায় গড়ে দিনে 300 জন কাস্টমার আসে। প্রতিটা কাস্টমার গড়ে $15 খরচ করে। বছরে (365 দিন) মোট রেভিনিউ কত হবে scientific notation-এ?
সমাধান, ধাপে ধাপে:
ধাপ ১: দৈনিক মোট কাস্টমার = 2,000 × 300 = 600,000 = 6 × 10⁵
ধাপ ২: দৈনিক মোট রেভিনিউ = (6 × 10⁵) × $15 = 9 × 10⁶ ($9 মিলিয়ন/দিন)
ধাপ ৩: বার্ষিক রেভিনিউ = (9 × 10⁶) × 365
365 ≈ 3.65 × 10² (রাউন্ড করে সহজ করে ফেলছি)
= (9 × 3.65) × 10^(6+2)
= 32.85 × 10⁸
= 3.285 × 10⁹ (≈ $3.3 বিলিয়ন/বছর)
লক্ষ্য করো — পুরো হিসেবটা কখনোই "600000 × 15 × 365"-এর মতো বড় সংখ্যা লিখে গুণ করতে হয়নি। প্রতি ধাপে coefficient (ছোট সংখ্যা, ১ ডিজিটের কাছাকাছি) আলাদা রেখে power যোগ/বিয়োগ করে কাজ চালানো হয়েছে — এটাই মাথায় মাথায় (mental math) বড় সংখ্যা নিয়ে কাজ করার আসল কৌশল।
৪. Order-of-Magnitude চিন্তাভাবনা — নির্ভুলতার বদলে সঠিক দিক
কেন "প্রায়" সঠিক হওয়াই যথেষ্ট
Back-of-envelope estimation-এর লক্ষ্য কখনোই decimal-point নির্ভুলতা না। লক্ষ্য হলো উত্তরটা সঠিক 10-এর power-এ পড়ছে কিনা — অর্থাৎ উত্তর কি হাজারে, লাখে, নাকি কোটিতে। এই পার্থক্যটা practice-এ কেমন দেখায়:
"86,400 সেকেন্ড/দিন"-কে "10⁵ সেকেন্ড" ধরা → ~13.6% ভুল, কিন্তু order of magnitude ঠিক আছে ✓ (গ্রহণযোগ্য)
"6,000 QPS"-কে ভুলে "60,000 QPS" বলে ফেলা → 10x ভুল, order of magnitude ভুল ✗ (গুরুতর সমস্যা)
প্রথম ভুলটা (১৩.৬%) সিস্টেম ডিজাইনে প্রায় কোনো প্রভাব ফেলে না — সিস্টেম যেভাবেই হোক 20-30% বাফার নিয়ে ডিজাইন হয়। কিন্তু দ্বিতীয় ভুলটা (10x) মানে তুমি হয়তো বলছো "single server যথেষ্ট" যেখানে আসলে distributed system দরকার, বা উল্টোটা — এটা পুরো architecture সিদ্ধান্তকে ভুল পথে নিয়ে যায়।
একটা মানসিক মডেল — "কত ডিজিট" প্রশ্ন করো
যেকোনো সংখ্যা অনুমান করার সময়, প্রথমে নিজেকে জিজ্ঞেস করো: "এই উত্তরটা কি ৩ ডিজিট, ৬ ডিজিট, নাকি ৯ ডিজিটের কাছাকাছি হবে?" এই একটা প্রশ্নই অনেক ভুল আগে থেকে ধরিয়ে দেয় — যদি তুমি হিসেব করে "30" পাও কিন্তু ইনটুইশন বলে এটা "কয়েক হাজার" হওয়া উচিত, তাহলে বুঝবে কোথাও একটা গুণ/ভাগের ধাপ miss হয়ে গেছে।
৫. Assumption বলার শৃঙ্খলা (Discipline of Stating Assumptions)
Fermi estimation-এর সবচেয়ে গুরুত্বপূর্ণ, কিন্তু প্রায়ই উপেক্ষিত অংশ — প্রতিটা সংখ্যা যেটা তুমি "ধরে নিচ্ছো" (assumed), সেটা জোরে বলা, নীরবে মাথায় ধরে নিয়ে সরাসরি ফলাফলে চলে যাওয়া না।
কেন এটা এত গুরুত্বপূর্ণ (দুইটা কারণ)
কারণ ১ — Verifiability: যদি তুমি বলো "answer হলো 50,000 QPS", কেউ চেক করতে পারবে না এটা ঠিক কিনা। কিন্তু যদি বলো "আমি ধরে নিচ্ছি 500M DAU, প্রতি ইউজার দিনে 10 বার action করে, তাই QPS = 500M×10/10⁵ = 50,000" — এখন প্রতিটা assumption আলাদাভাবে challenge/correct করা যায়। ইন্টারভিউয়ার যদি বলে "না, DAU আসলে 100M ধরো", তুমি সহজেই শুধু সেই একটা সংখ্যা বদলে বাকি হিসেব রিইউজ করতে পারবে।
কারণ ২ — এটাই আসল দক্ষতা যা টেস্ট হচ্ছে: ইন্টারভিউয়ার তোমার "সঠিক সংখ্যা মুখস্থ থাকা" টেস্ট করছে না (এটা impossible, কেউ জানে না সত্যিকারের DAU কত হবে) — সে টেস্ট করছে তুমি reasonable, defensible assumption নিতে পারো কিনা। Assumption চেপে গিয়ে সরাসরি উত্তর দিলে এই মূল্যায়নযোগ্য অংশটাই হারিয়ে যায়।
একটা প্র্যাকটিক্যাল টেমপ্লেট — যেভাবে জোরে বলবে
"আমি ধরে নিচ্ছি [X]। এই assumption-টা ঠিক আছে, নাকি আপনার কাছে ভিন্ন কোনো সংখ্যা আছে?"
এই ছোট্ট বাক্যটাই তিনটা কাজ করে — assumption declare করে, ইন্টারভিউয়ারকে correction দেওয়ার সুযোগ দেয়, এবং দেখায় তুমি collaborative, নিজের অনুমানে অন্ধভাবে অটল না।
৬. General Fermi Problems — বিশুদ্ধ অনুশীলন (System Design-এর বাইরে)
Day 1-এ যাওয়ার আগে, এখানে কিছু ক্লাসিক Fermi-স্টাইল প্রশ্ন দেওয়া হলো যেগুলোর সাথে সিস্টেম ডিজাইনের কোনো সম্পর্ক নেই — উদ্দেশ্য শুধু "বিভাজন করে অনুমান করা" স্কিলটা যাচাই করা, যাতে Day 1-এ পৌঁছেই তুমি সরাসরি সিস্টেম-নির্দিষ্ট সংখ্যায় মনোযোগ দিতে পারো, "কীভাবে অনুমান করবো" এই মৌলিক স্কিল নিয়ে না আটকে যাও।
Problem 1 — ঢাকা শহরে মোট কতটা রিকশা আছে?
একটা সম্ভাব্য সমাধান-পথ (তোমার নিজেরটা ভিন্ন হতে পারে, সমস্যা নেই):
ঢাকার জনসংখ্যা ≈ 2 কোটি (2 × 10⁷)
ধরি প্রতি 50 জনে ১টা রিকশা প্রয়োজন হয় (এভারেজ পরিবহন চাহিদা)
রিকশা সংখ্যা ≈ (2 × 10⁷) / 50 = 4 × 10⁵ = 400,000
(বাস্তব সংখ্যা হয়তো ভিন্ন, কিন্তু order-of-magnitude — কয়েক লাখ — সাধারণত সঠিক থাকে)
Problem 2 — বাংলাদেশে প্রতিদিন কত কাপ চা বিক্রি হয়?
নিজে চেষ্টা করো — জনসংখ্যা থেকে শুরু করো, তারপর "কত শতাংশ মানুষ চা পান করে" এবং "গড়ে দিনে কত কাপ" — এই দুইটা ধরে হিসেব করো।
Problem 3 — একটা স্ট্যান্ডার্ড স্কুল বাসের ভেতর কতগুলো টেনিস বল রাখা যাবে?
এটা ক্লাসিক (মাইক্রোসফট/গুগলের পুরনো ইন্টারভিউ প্রশ্ন) — bus-এর volume অনুমান করো, একটা টেনিস বলের volume অনুমান করো, packing efficiency (গোলাকার বস্তু একসাথে রাখলে ~74% স্পেস ব্যবহার হয়, বাকিটা ফাঁকা থাকে) বিবেচনা করো।
কেন এই "অ-প্রাসঙ্গিক" প্রশ্নগুলো গুরুত্বপূর্ণ
এই প্রশ্নগুলোতে কোনো সিস্টেম-ডিজাইন jargon নেই, তাই তুমি সরাসরি core skill-টা (বিভাজন + অনুমান + যুক্তিসঙ্গত রাউন্ডিং) প্র্যাকটিস করতে পারো, ডোমেইন-নলেজের বোঝা ছাড়াই। যদি তুমি এই ধরনের প্রশ্নে comfortable হও, Day 1-3-এর "DAU × actions/user/day ÷ seconds/day" ফ্রেমওয়ার্ক তোমার কাছে নতুন কোনো cognitive challenge মনে হবে না — শুধু একটা নতুন domain-এ পুরোনো skill প্রয়োগ মনে হবে।
৭. Sanity-Check করার মানসিকতা
Fermi estimation-এর শেষ ধাপ সবসময় একটা প্রশ্ন: "এই সংখ্যাটা কি বাস্তবসম্মত মনে হচ্ছে?"
তিনটা সাধারণ sanity-check কৌশল
কৌশল ১ — পরিচিত রেফারেন্স পয়েন্টের সাথে তুলনা করো। যদি তুমি হিসেব করে পাও একটা দেশের জনসংখ্যা 5 বিলিয়ন, কিন্তু তুমি জানো বিশ্বের মোট জনসংখ্যাই ~৮ বিলিয়ন — তাহলে বুঝবে কোথাও একটা বড় ভুল হয়েছে।
কৌশল ২ — Upper/lower bound বসিয়ে দেখো। "ঢাকায় কতগুলো রিকশা?" প্রশ্নে যদি তোমার হিসেব 400 আসে (খুবই কম) বা 40 কোটি আসে (শহরের জনসংখ্যার চেয়ে বেশি!) — উভয়ই তাৎক্ষণিকভাবে অবাস্তব, পুনরায় হিসেব করা দরকার।
কৌশল ৩ — Unit আবার চেক করো। অনেক ভুল আসে ভুল unit ব্যবহার করা থেকে (যেমন সেকেন্ডের বদলে মিনিট ব্যবহার করে ফেলা, বা KB-র বদলে MB)। প্রতিটা চূড়ান্ত সংখ্যার সাথে unit স্পষ্টভাবে লিখে/বলে রাখা (শুধু "50,000" না, "50,000 QPS" বা "50,000 users") এই ভুল ধরিয়ে দেয়।
৮. Self-Diagnostic — Day 1 শুরু করার আগে নিজেকে যাচাই করো
নিচের প্রশ্নগুলো নিজে সমাধান করো, ক্যালকুলেটর ছাড়া। যদি সবগুলো ৫ মিনিটের মধ্যে (কাগজে, মাথায় মাথায়) করতে পারো, তুমি Day 1-এর জন্য প্রস্তুত।
§2-এর "অনুশীলন" অংশের ৫টা প্রশ্নের উত্তর দাও:
- 4×10⁶ × 5×10³ = ? (উত্তর: 2×10¹⁰)
- (9×10⁹) ÷ (3×10⁵) = ? (উত্তর: 3×10⁴)
- 2.5×10⁷ = কত মিলিয়ন? (উত্তর: 25 মিলিয়ন)
- 800,000,000 = ? scientific notation (উত্তর: 8×10⁸)
- 10¹²÷10⁶ = ? (উত্তর: 10⁶ = 1 million)
উপরের বইয়ের দোকান উদাহরণ (§3) নিজে কাগজ ছাড়া, শুধু মাথায় মাথায় পুনরায় সমাধান করো — একই উত্তর (≈$3.3 বিলিয়ন) পাও কিনা চেক করো।
§6-এর Problem 2 (চায়ের কাপ) এবং Problem 3 (টেনিস বল) সম্পূর্ণ সমাধান করো, প্রতিটা assumption জোরে বলে (রেকর্ড করে)।
নিজের ভাষায় ব্যাখ্যা করো: "Order of magnitude সঠিক থাকা" আর "সংখ্যা একদম নির্ভুল হওয়া" — এই দুইটার মধ্যে পার্থক্য কী, এবং ইন্টারভিউতে কোনটা গুরুত্বপূর্ণ কেন?
Assumption জোরে বলার দুইটা কারণ (§5) নিজের ভাষায় ব্যাখ্যা করো — একটা বাস্তব উদাহরণ কল্পনা করো যেখানে assumption না বলাতে ইন্টারভিউ খারাপ হতে পারতো।
এই মডিউল সম্পূর্ণ করার পর তুমি প্রস্তুত: Day 1 (Latency Numbers & Orders of Magnitude)-এ যাওয়ার জন্য, যেখানে এই একই powers-of-ten fluency এবং Fermi-estimation discipline সরাসরি latency numbers এবং সিস্টেম-নির্দিষ্ট হিসেবে প্রয়োগ হবে।
Day 1 · Latency numbers, orders of magnitude
১. কেন এটা কারিকুলামের প্রথম দিন
সিস্টেম ডিজাইন ইন্টারভিউয়ে প্রতিটা সিদ্ধান্তের পেছনে একটাই মৌলিক প্রশ্ন থাকে: "এই কাজটা করতে কত সময় লাগবে, আর সেটা কি গ্রহণযোগ্য?"
তুমি যদি না জানো RAM read আর SSD read-এর মধ্যে পার্থক্য ঠিক কত অর্ডার অফ ম্যাগনিটিউড, তাহলে "cache ব্যবহার করবো" বলাটা একটা ফাঁকা বুলি হয়ে যায় — সংখ্যা ছাড়া কোনো justification নেই। Appendix A রুব্রিকে Tradeoff articulation dimension-এ 4-5 পেতে হলে দরকার: "Names both sides, picks one, states the cost of the choice" — আর এই "cost" প্রায়ই latency-তে মাপা হয়। তাই latency numbers মুখস্থ থাকা মানে প্রতিটা ট্রেডঅফ আলোচনায় তুমি সংখ্যা দিয়ে যুক্তি দিতে পারবে, শুধু "এটা দ্রুত" / "এটা ধীর" বলে না।
আরেকটা কারণ: Deep dive সেগমেন্টে (15-20 মিনিট, রুব্রিকে "three layers down unprompted") যখন ইন্টারভিউয়ার জিজ্ঞেস করবে "এই component-এ latency কোথা থেকে আসছে?", তখন তোমাকে এই টেবিলের সংখ্যাগুলো থেকে ব্যাখ্যা তৈরি করতে হবে — কাগজ দেখে না, মুখস্থ থেকে।
২. মূল ল্যাটেন্সি টেবিল (সম্পূর্ণ, মুখস্থ করার মতো)
এই টেবিলটা প্রথম প্রকাশ করেছিলেন Jeff Dean (Google), এবং প্রতি বছর hardware উন্নত হওয়ায় সংখ্যাগুলো আপডেট হয়। নিচে ২০২৫-২৬ সময়ের approximate আধুনিক hardware অনুযায়ী মান দেওয়া হলো।
| # | অপারেশন | সময় (approx) | নোটেশন |
|---|---|---|---|
| 1 | L1 cache reference | 0.5 ns | 5 × 10⁻¹⁰ s |
| 2 | Branch mispredict | 3 ns | 3 × 10⁻⁹ s |
| 3 | L2 cache reference | 7 ns | 7 × 10⁻⁹ s |
| 4 | Mutex lock/unlock | 20 ns | 2 × 10⁻⁸ s |
| 5 | Main memory (RAM) reference | 100 ns | 10⁻⁷ s |
| 6 | Compress 1 KB with fast compressor | ~2,000 ns (2 μs) | 2 × 10⁻⁶ s |
| 7 | Send 1 KB over 10 Gbps network | ~1,000 ns (1 μs) | 10⁻⁶ s |
| 8 | Read 1 MB sequentially from RAM | ~3,000 ns (3 μs) | 3 × 10⁻⁶ s |
| 9 | SSD random read | ~16,000 ns (16 μs) | 1.6 × 10⁻⁵ s |
| 10 | Read 1 MB sequentially from SSD | ~50,000–100,000 ns (50–100 μs) | ~10⁻⁴ s |
| 11 | Round trip within same datacenter | ~500,000 ns (500 μs) | 5 × 10⁻⁴ s |
| 12 | Disk seek (HDD, spinning) | 2,000,000–10,000,000 ns (2–10 ms) | ~10⁻² s |
| 13 | Read 1 MB sequentially from network (same region) | ~10,000,000 ns (10 ms) | 10⁻² s |
| 14 | Read 1 MB sequentially from HDD | ~30,000,000 ns (30 ms) | 3 × 10⁻² s |
| 15 | Round trip between continents (US ↔ Asia) | ~150,000,000 ns (150 ms) | 1.5 × 10⁻¹ s |
লক্ষ্য করো: #1 থেকে #15 পর্যন্ত সময় বেড়েছে প্রায় ৩০ কোটি গুণ (0.5 ns থেকে 150 ms)। এই বিশাল রেঞ্জটাই বুঝতে হবে — কম্পিউটিং-এর প্রতিটা স্তরে (CPU cache থেকে ইন্টারকন্টিনেন্টাল নেটওয়ার্ক পর্যন্ত) latency-র differences এত বড় যে একটা ভুল architectural সিদ্ধান্ত পুরো সিস্টেমকে ১০০-১০০০ গুণ ধীর করে দিতে পারে।
৩. প্রতিটা স্তর থেকে যেই ইনটুইশন বের করতে হবে (উদাহরণ সহ)
৩.১ CPU Cache Levels (L1 → L2 → RAM)
সংখ্যা: L1 = 0.5 ns, L2 = 7 ns (L1-এর ~14x ধীর), RAM = 100 ns (L1-এর ~200x, L2-এর ~14x ধীর)।
উদাহরণ: ধরো তুমি একটা hot loop লিখছো যেটা একটা বড় array বারবার scan করে। যদি array-টা L2 cache-এ (সাধারণত কয়েকশ KB-কয়েক MB) ফিট করে, প্রতিটা access ~7ns। কিন্তু array যদি cache-এর চেয়ে বড় হয় এবং প্রতিবার RAM থেকে আনতে হয়, প্রতিটা access ~100ns — অর্থাৎ ১৪ গুণ ধীর। এটাই কারণ কেন cache-friendly data structures (contiguous arrays বনাম linked lists, যেগুলো memory-তে ছড়ানো থাকে) performance-critical কোডে গুরুত্বপূর্ণ।
এটা সরাসরি সিস্টেম ডিজাইন ইন্টারভিউতে কম আসে (এটা বেশি low-level performance engineering-এর বিষয়), কিন্তু ইনটুইশন গড়ার জন্য দরকারি — যেন তুমি বুঝতে পারো cache hierarchy কনসেপ্টটা শুধু Redis/CDN-এ না, হার্ডওয়্যার লেভেলেও একই প্যাটার্নে repeat হয়।
৩.২ RAM vs SSD — সবচেয়ে গুরুত্বপূর্ণ ইনসাইট (Redis/caching-এর মূল যুক্তি)
সংখ্যা: RAM = 100 ns, SSD random read = 16,000 ns (16 μs)।
Ratio = 16,000 / 100 = 160x
উদাহরণ ১ (তোমার ⭐ Redis experience-এর সাথে যুক্ত): ধরো একটা user profile lookup — যদি এটা Postgres থেকে disk read করে আনতে হয় (SSD random read + query processing overhead ধরে মোট হয়তো ~1-5 ms), আর একই ডেটা Redis (RAM-backed) থেকে আনলে ~0.5-1 ms (network round trip সহ, কারণ Redis সাধারণত আলাদা সার্ভারে থাকে)। যদি একটা API request-এ ১০টা এমন lookup করতে হয় sequentially, Postgres দিয়ে করলে ~10-50ms, Redis দিয়ে করলে ~5-10ms — এই পার্থক্যটাই p99 latency SLA (Day 161)-তে পাস/ফেল নির্ধারণ করে দিতে পারে।
উদাহরণ ২: একটা leaderboard সিস্টেম (গেম বা কনটেস্ট) — যদি প্রতিটা score update-এ Postgres-এ ORDER BY করে rank বের করতে হয় (disk-backed B-tree scan), সেটা হাজার হাজার concurrent user-এর জন্য স্কেল করবে না। কিন্তু Redis Sorted Set (RAM-backed, তোমার ⭐ area) ব্যবহার করলে rank lookup O(log N) এবং সম্পূর্ণ RAM-এ, তাই মিলিসেকেন্ডের নিচে।
৩.৩ Sequential vs Random I/O — LSM-tree ডিজাইনের ভিত্তি
সংখ্যা: SSD random read = 16 μs, কিন্তু 1 MB sequential read from SSD মাত্র ~50-100 μs — মানে 1 MB ডেটা (যেটা প্রায় ৬৪টা ৪KB পেজ, যদি random হতো তাহলে 64 × 16μs = ~1000μs লাগতো) sequential-ভাবে পড়লে মাত্র 50-100μs, প্রায় ১০-২০ গুণ দ্রুত।
উদাহরণ: এইজন্যই Cassandra, RocksDB, LevelDB-এর মতো ডাটাবেসগুলো LSM-tree (Log-Structured Merge tree) ব্যবহার করে (Day 31-32-এ বিস্তারিত)। এই ডিজাইনে writes সবসময় sequentially একটা append-only log-এ যায় (memtable → SSTable flush), কখনো in-place random write হয় না। ফলে write throughput অনেক বেশি — এমনকি HDD-তেও (যেখানে random vs sequential-এর পার্থক্য SSD-এর চেয়ে আরও বেশি, প্রায় ১০০-১০০০x, কারণ disk head physically move করতে হয়)।
বিপরীত উদাহরণ: B-tree ভিত্তিক ডাটাবেস (Postgres-এর default index) update-এর সময় in-place random write করে — এইজন্য write-heavy workload-এ (Day 32-এ read/write amplification আলোচনা) LSM-tree প্রায়ই জেতে, কিন্তু read-এর সময় LSM-tree-কে একাধিক SSTable check করতে হতে পারে (read amplification) — এটাই classic tradeoff, যেটা তুমি ইন্টারভিউতে "cost of the choice" হিসেবে বলবে।
৩.৪ Network Round Trip — Same Datacenter vs Cross-Continent
সংখ্যা: same-DC round trip = 500 μs, cross-continent round trip = 150 ms।
Ratio = 150,000 / 500 = 300x
উদাহরণ ১ (Microservices architecture): ধরো একটা API request প্রসেস করতে ৫টা আলাদা microservice call করতে হয় (auth → user service → inventory service → pricing service → payment service), sequentially (একটার পর একটা)। যদি সবগুলো একই datacenter-এ থাকে: 5 × 500μs = 2.5 ms (নেটওয়ার্ক ওভারহেড হিসেবে, acceptable)। কিন্তু যদি ভুলবশত ২টা service আলাদা region-এ ডিপ্লয় হয়ে যায় (যেমন pricing service ইউরোপে, বাকিগুলো এশিয়ায়): সেই একটা hop-ই যোগ করবে ~150ms — পুরো request-এর latency ৬০ গুণ বেড়ে যাবে। এটাই কারণ কেন service mesh/microservice architecture-এ "region affinity" এত গুরুত্বপূর্ণ (Day 11, 158)।
উদাহরণ ২ (Database replication): যদি একটা write-এর পরে synchronous replication-এ অপেক্ষা করতে হয় একটা cross-region replica confirm করার জন্য (strong consistency-এর জন্য, Day 54-55), প্রতিটা write অন্তত ~150ms নেবে — এটাই কারণ multi-region ডাটাবেস (Spanner, CockroachDB, Day 40, 66) এত জটিল ইঞ্জিনিয়ারিং সমস্যা, এবং কেন অনেক সিস্টেম asynchronous replication বেছে নেয় (eventual consistency-এর বিনিময়ে latency বাঁচানোর জন্য) — classic CAP-theorem-adjacent tradeoff (Day 51-এ বিস্তারিত)।
উদাহরণ ৩ (CDN-এর মূল যুক্তি): ধরো একজন ইউজার ঢাকা থেকে একটা ভিডিও দেখছে, কিন্তু origin server আছে যুক্তরাষ্ট্রে (US-East)। প্রতিটা chunk request-এ ~150-200ms latency যোগ হবে যদি সরাসরি origin থেকে আসে। কিন্তু যদি সিঙ্গাপুর বা মুম্বাইয়ে একটা CDN PoP (Point of Presence, Day 9) থেকে সার্ভ হয়, latency নেমে আসবে ~20-40ms-এ। এই পার্থক্যটাই ভিডিও buffering আর smooth playback-এর মধ্যে পার্থক্য তৈরি করে।
৩.৫ Disk Seek (HDD) — কেন এখনো এটা জানা জরুরি
সংখ্যা: HDD disk seek = 2-10 ms। এটা SSD random read (16μs)-এর চেয়ে ~১০০-৬০০ গুণ ধীর, কারণ HDD-তে একটা physical read/write head ঘুরে ঘুরে সঠিক track-এ যেতে হয় (mechanical movement), যেখানে SSD-তে কোনো moving part নেই (electrical signal)।
উদাহরণ: যদিও আজকাল বেশিরভাগ প্রোডাকশন সিস্টেম SSD ব্যবহার করে, HDD এখনো ব্যবহার হয় cold storage / archival ক্ষেত্রে (S3 Glacier-এর ব্যাকএন্ডে, ব্যাকআপ সিস্টেমে) কারণ HDD storage cost per GB SSD-এর চেয়ে অনেক কম। এইজন্যই tiered storage strategy-তে (Day 160) "hot data → SSD, cold data → HDD/tape" এই বিভাজন করা হয় — latency ট্রেডঅফ করে cost বাঁচানো হয়, যেহেতু cold data কম access হয়।
৪. "১ সেকেন্ড" Analogy — ইন্টারভিউতে ব্যবহার করার মতো একটা শক্তিশালী টুল
যদি L1 cache access (0.5 ns)-কে scale up করে ১ সেকেন্ড ধরি, তাহলে বাকি সব operation কত সময়ে হবে (স্কেল ফ্যাক্টর ~2 × 10⁹):
| অপারেশন | Scaled সময় (মানুষের অনুভবযোগ্য) |
|---|---|
| L1 cache reference | ১ সেকেন্ড |
| L2 cache reference | ১৪ সেকেন্ড |
| Main memory (RAM) reference | ~৩ মিনিট ২০ সেকেন্ড |
| SSD random read | ~৯ ঘণ্টা |
| Same-datacenter round trip | ~১১.৫ দিন |
| Cross-continent round trip | ~৯.৫ বছর |
কেন এই analogy ইন্টারভিউতে শক্তিশালী: যদি তুমি বলো "cross-continent network call করা মানে, RAM access-এর তুলনায়, প্রায় সাড়ে ৯ বছর অপেক্ষা করার সমান" — ইন্টারভিউয়ার তৎক্ষণাৎ বুঝে যায় তুমি সংখ্যাগুলো শুধু মুখস্থ করোনি, প্রকৃত ইনটুইশন গড়ে তুলেছো। এটাই রুব্রিকের "Communication — structured, well-paced, effective" dimension-এ পয়েন্ট এনে দেয়, কারণ জটিল টেকনিক্যাল কনসেপ্ট সহজ ভাষায় বোঝানোর ক্ষমতা দেখায়।
৫. একটা সম্পূর্ণ Worked Example — Request Path Latency Budget
চলো একটা বাস্তব ইন্টারভিউ-স্টাইল প্রশ্ন সম্পূর্ণ সমাধান করি: "একজন ইউজার একটা সোশ্যাল মিডিয়া পোস্ট লোড করছে — তার feed-এর প্রথম ২০টা পোস্ট। এই request-এর latency budget কীভাবে হিসেব করবে?"
ধাপে ধাপে path:
১. ইউজারের ডিভাইস → CDN/Load Balancer (নেটওয়ার্ক, একই region ধরলে)
≈ 20-50 ms (public internet + TLS handshake, Day 6)
২. Load Balancer → App Server (same DC)
≈ 0.5 ms (500 μs, same-datacenter round trip)
৩. App Server → Redis (feed cache lookup, cache HIT হলে)
≈ 0.5-1 ms
[যদি cache MISS হয়:]
৩ক. App Server → Postgres/Cassandra (feed data fetch, disk থেকে)
≈ 5-20 ms (query complexity + disk I/O নির্ভর করে)
৪. App Server → একাধিক downstream service (user info, like counts ইত্যাদি, parallel call করলে)
≈ 5-10 ms (parallel হলে সবচেয়ে ধীর call-টাই dominant, sequential হলে যোগ হয়)
৫. Response সার্ভার থেকে ইউজারে ফেরত (নেটওয়ার্ক)
≈ 20-50 ms
মোট latency estimate:
- Cache HIT path: ~50-100 ms (acceptable, ভালো UX)
- Cache MISS path: ~55-130 ms (এখনও acceptable, কিন্তু লক্ষণীয়ভাবে ধীর)
এখান থেকে ডিজাইন সিদ্ধান্ত:
- Feed cache hit ratio 90%+ রাখা critical, কারণ 10% মিসেও p95/p99 latency (Day 161) বাজেভাবে বেড়ে যেতে পারে
- ধাপ ৪-এর downstream calls অবশ্যই parallel করতে হবে, sequential করলে (5×10ms = 50ms) মোট latency প্রায় দ্বিগুণ হয়ে যাবে
- CDN/edge presence (ধাপ ১ ও ৫) সবচেয়ে বড় ফিক্সড cost — এখানে অপ্টিমাইজেশনের সুযোগ কম যদি না geo-distributed edge servers থাকে
এই ধরনের latency budget breakdown ঠিক Deep Dive সেগমেন্টে (Mock Interview Spec) ইন্টারভিউয়ার যা দেখতে চায় — প্রতিটা component-এর cost আলাদা করে চেনা এবং bottleneck identify করা (রুব্রিক dimension: "Identifies the true bottleneck, not the obvious one")।
৬. আরেকটা Worked Example — যেখানে ভুল latency assumption বিপর্যয় ডেকে আনে
দৃশ্যকল্প: একজন ইঞ্জিনিয়ার একটা নোটিফিকেশন সিস্টেম ডিজাইন করছে (তোমার ⭐ area-এর সাথে সম্পর্কিত)। ডিজাইনে প্রতিটা নোটিফিকেশন পাঠানোর আগে একটা "user preference check" করা হয় — যেটা একটা রিমোট config service-কে call করে, আর সেই config service আরেকটা রিজিওনে ডিপ্লয় করা (ভুলবশত)।
প্রতি নোটিফিকেশনে extra latency = ~150 ms (cross-continent round trip)
যদি সিস্টেমে দৈনিক 100M নোটিফিকেশন পাঠাতে হয় (তোমার ⭐ 100M+/day scale, Day 109-110):
Total extra time (যদি sequential/single-threaded হতো) = 100,000,000 × 150ms = 1.5 × 10¹⁰ ms ≈ 173 দিন!
এটা অবশ্যই parallel/batched হবে বাস্তবে, কিন্তু এই হিসেবটাই দেখায় — একটা ছোট্ট ভুল latency assumption (রিজিওন মিসপ্লেসমেন্ট) পুরো সিস্টেমের throughput কে ধ্বংস করে দিতে পারে, যদি না প্রতিটা hop-এর latency আগে থেকে হিসেব করে দেখা হয়। এইজন্যই Day 1-এর latency numbers মুখস্থ থাকাটা শুধু থিওরি না — এটা production-এ real bug prevent করার টুল।
৭. Sanity-Check হিউরিস্টিক (ইন্টারভিউতে নিজেকে যাচাই করার জন্য)
যেকোনো latency-সম্পর্কিত সিদ্ধান্ত নেওয়ার আগে নিজেকে জিজ্ঞেস করো:
- এই operation কি memory-bound নাকি network-bound নাকি disk-bound? — প্রতিটার latency profile সম্পূর্ণ আলাদা, এবং optimization strategy-ও আলাদা (memory-bound হলে algorithm optimize করো, network-bound হলে hop কমাও বা caching করো, disk-bound হলে access pattern sequential করার চেষ্টা করো)
- এই call কি sequential নাকি parallel হতে পারে? — sequential হলে latency যোগ হয়, parallel হলে max(latencies) হয় — এই একটা সিদ্ধান্তই ৫-১০ গুণ পার্থক্য তৈরি করতে পারে
- এই latency কি p50 (typical) নাকি p99 (worst case) এর কথা বলছি? — cache miss, GC pause, network retry — এগুলো p99 কে p50-এর চেয়ে অনেক খারাপ করে দেয় (Day 161-এ SLI/SLO আলোচনায় ফিরে আসবো)
৮. আজকের Application Exercise (কাগজে/হোয়াইটবোর্ডে করো, নোট না দেখে)
Exercise ১: User Profile Fetch — চারটা পথের তুলনা
একটা "user profile fetch" request-এর জন্য নিচের চারটা ক্ষেত্রে approximate end-to-end latency হিসেব করো:
- (ক) L1/L2 CPU cache-এ hit করে (একই প্রসেসের মধ্যে ইতিমধ্যে loaded ডেটা)
- (খ) Application server-এর RAM-এ (in-process cache) hit করে
- (গ) Redis থেকে আসে (network hop সহ, same datacenter)
- (ঘ) Postgres থেকে disk থেকে আসে (SSD random read + query processing)
প্রতিটার জন্য approximate সংখ্যা লেখো এবং ratio বের করো (ক থেকে ঘ পর্যন্ত কত গুণ পার্থক্য)।
Exercise ২: Multi-Region API Latency Budget
একটা API-তে ৩টা microservice hop লাগে। তিনটা ভিন্ন পরিস্থিতি হিসেব করো:
- (ক) সব ৩টা service একই datacenter-এ, sequential call
- (খ) সব ৩টা service একই datacenter-এ, কিন্তু ২টা call parallel করা যায় (৩য়টা প্রথম দুটোর result-এর উপর নির্ভরশীল)
- (গ) ৩টার মধ্যে ১টা service অন্য continent-এ (accidentally মিসপ্লেসড)
প্রতিটা পরিস্থিতির total latency বের করো এবং তুলনা করো কোনটা কত গুণ ধীর।
Exercise ৩: নিজের ভাষায় "১ সেকেন্ড" Analogy তৈরি করো
উপরের টেবিলের অন্তত ৫টা অপারেশন নিয়ে নিজের মতো একটা analogy তৈরি করো (স্কেল ফ্যাক্টর আলাদা ব্যবহার করতে পারো, যেমন RAM access = ১ সেকেন্ড ধরে বাকিগুলো scale করো) — এবং জোরে বলে (রেকর্ড করে) নিজেকে explain করো।
৯. Active Recall প্রশ্ন — উত্তর দাও (লিখে বা ভয়েসে)
- RAM access আর SSD random read-এর মধ্যে approximate ratio কত, এবং এটা কীভাবে Redis-এর মতো টুল ব্যবহারের যুক্তি প্রতিষ্ঠা করে? তোমার নিজের production experience থেকে একটা উদাহরণ দাও।
- Sequential disk read আর random disk read-এর পার্থক্য কীভাবে LSM-tree ডিজাইনের মূল কারণ হয়ে দাঁড়ায় — এক প্যারাগ্রাফে ব্যাখ্যা করো, এবং এর বিপরীতে B-tree কেন read-heavy workload-এ ভালো করে সেটাও বলো।
- "Same datacenter round trip" (500 μs) vs "cross-continent round trip" (150 ms) — এই পার্থক্য কীভাবে microservice architecture ডিজাইনে region-placement সিদ্ধান্তে প্রভাব ফেলে? একটা বাস্তব bug scenario কল্পনা করে বলো।
- উপরের তিনটা Exercise সম্পূর্ণ করো — সংখ্যাগুলো এবং তোমার analogy আমাকে দাও, রিভিউ করে দেবো।
- "Memory-bound vs network-bound vs disk-bound" — এই তিন ধরনের bottleneck-এর জন্য optimization strategy কীভাবে আলাদা হয়, একটা করে উদাহরণ দিয়ে ব্যাখ্যা করো।
Day 2 · Back-of-envelope: QPS, storage, bandwidth
১. কেন এই স্কিলটা সবচেয়ে বেশি গুরুত্বপূর্ণ
ইন্টারভিউয়ের প্রথম ৫-৮ মিনিট (Requirements + Estimation সেগমেন্ট, দেখো Mock Interview Spec) সবচেয়ে বেশি ফার্স্ট-ইমপ্রেশন তৈরি করে। ইন্টারভিউয়ার তোমার চূড়ান্ত সংখ্যা সঠিক কিনা সেটা নিয়ে চিন্তিত না — সে দেখতে চায়:
- তুমি assumption স্পষ্টভাবে বলছো কিনা (assumption না বলে সরাসরি সংখ্যায় ঝাঁপ দিলে সেটা red flag)
- তুমি মাথায় মাথায় (mental math) দ্রুত হিসেব করতে পারো কিনা
- তোমার সংখ্যা থেকে তুমি একটা ডিজাইন সিদ্ধান্ত (decision) বের করতে পারো কিনা — যেমন "read:write ratio 10:1, তাই caching লাগবে"
Appendix A রুব্রিক অনুযায়ী Estimation dimension-এ 4-5 পেতে হলে: "Fast, correct, states assumptions, sanity-checks results"। এই চারটা জিনিসই আজকের ফোকাস।
২. মূল ইউনিট ও শর্টকাট (মুখস্থ রাখো — কাগজ ছাড়া বলতে পারতে হবে)
সময়ের ইউনিট
| ইউনিট | মান | মনে রাখার approximation |
|---|---|---|
| ১ দিন | ৮৬,৪০০ সেকেন্ড | ~১০⁵ সেকেন্ড |
| ১ মাস | ~৩০ দিন | ৩০ × ৮৬,৪০০ ≈ ২.৬ × ১০⁶ সেকেন্ড |
| ১ বছর | ৩১,৫৩৬,০০০ সেকেন্ড | ~π × ১০⁷ সেকেন্ড (৩.১৪ × ১০⁷) |
কেন 10⁵ সেকেন্ড/দিন এত উপকারী? কারণ "daily total" থেকে "per-second average" বের করতে তোমাকে শুধু একটা power-of-10 দিয়ে ভাগ করলেই হয়ে যায় — ক্যালকুলেটর ছাড়া মাথায় করা যায়।
সাইজের ইউনিট (ইন্টারভিউতে decimal approximation ব্যবহার করো, 1024-ভিত্তিক না)
| ইউনিট | মান |
|---|---|
| 1 KB | 10³ bytes |
| 1 MB | 10⁶ bytes |
| 1 GB | 10⁹ bytes |
| 1 TB | 10¹² bytes |
| 1 PB | 10¹⁵ bytes |
দ্রুত mental-math ট্রিকস
- গুণ করার সময় exponent যোগ করো: 6 × 10³ × 2 × 10⁵ = (6×2) × 10^(3+5) = 12 × 10⁸ = 1.2 × 10⁹
- রাউন্ড আপ/ডাউন করো সাহসের সাথে — 86,400 কে 10⁵ ধরলে answer এ মাত্র ~15% ভুল আসবে, যেটা back-of-envelope এ সম্পূর্ণ গ্রহণযোগ্য
- সবসময় ইউনিট বলে বলে হিসেব করো (dimensional analysis) — "users × photos/user/day = photos/day", এতে ভুল হওয়ার সম্ভাবনা কমে যায়
৩. QPS (Queries Per Second) হিসেবের সম্পূর্ণ ফ্রেমওয়ার্ক
ধাপে ধাপে প্রসেস
ধাপ ১: DAU (Daily Active Users) নির্ধারণ করো — ইন্টারভিউয়ারকে জিজ্ঞেস করো, না দিলে reasonable assumption নাও
ধাপ ২: প্রতি ইউজার প্রতিদিন কতবার এই action করে (read/write আলাদা আলাদা)
ধাপ ৩: Total daily requests = DAU × actions/user/day
ধাপ ৪: Average QPS = Total daily requests / 10⁵ (86400 সেকেন্ড)
ধাপ ৫: Peak QPS = Average QPS × peak factor (সাধারণত 2-3x, ইন্টারভিউয়ারকে বলো এটা diurnal traffic pattern ধরে)
বিস্তারিত উদাহরণ ১ — Photo-Sharing Service (Instagram-স্টাইল)
Assumptions (জোরে বলে নাও, ইন্টারভিউয়ারকে কনফার্ম করো):
- 300M DAU
- প্রতি ইউজার গড়ে দিনে 2টা ছবি আপলোড করে (write action)
- প্রতি ইউজার গড়ে দিনে 20টা ছবি দেখে/স্ক্রল করে (read action)
- Peak factor 3x (কোনো বিশেষ hint না থাকলে standard diurnal assumption)
Write QPS হিসেব:
Total daily writes = 300,000,000 × 2 = 600,000,000 writes/day
= 6 × 10⁸ writes/day
Average write QPS = 6 × 10⁸ / 10⁵ = 6 × 10³ = 6,000 QPS
Peak write QPS = 6,000 × 3 = 18,000 QPS
Read QPS হিসেব:
Total daily reads = 300,000,000 × 20 = 6,000,000,000 reads/day
= 6 × 10⁹ reads/day
Average read QPS = 6 × 10⁹ / 10⁵ = 6 × 10⁴ = 60,000 QPS
Peak read QPS = 60,000 × 3 = 180,000 QPS
গুরুত্বপূর্ণ ইনসাইট — Read:Write Ratio
Read QPS : Write QPS = 60,000 : 6,000 = 10 : 1
এই একটা সংখ্যা (10:1) থেকেই সরাসরি ডিজাইন সিদ্ধান্ত বের হয়:
- সিস্টেম read-heavy, তাই read replica, CDN, এবং aggressive caching (Day 16-21) প্রায়োরিটি
- Write path relatively কম stress-এ, তাই write-optimization (batching ইত্যাদি) নিয়ে অতিরিক্ত চিন্তার দরকার নেই প্রথমেই
- Cache hit ratio যদি 90%+ রাখা যায়, তাহলে database-এ আসল read load 60,000 QPS থেকে নেমে মাত্র ~6,000 QPS-এ চলে আসবে — এটাই caching-এর পুরো যুক্তি একটা বাক্যে
বিস্তারিত উদাহরণ ২ — একটা কম-QPS System (তুলনার জন্য)
ধরো একটা B2B invoicing tool:
- 50,000 DAU (ছোট এন্টারপ্রাইজ ইউজার বেস)
- প্রতি ইউজার দিনে গড়ে 5টা invoice তৈরি করে (write)
- প্রতি ইউজার দিনে গড়ে 15টা invoice দেখে (read)
Write: 50,000 × 5 = 250,000/day → 250,000/10⁵ = 2.5 QPS (average)
Read: 50,000 × 15 = 750,000/day → 750,000/10⁵ = 7.5 QPS (average)
এখানে peak factor 3x ধরলেও Peak read মাত্র ~22.5 QPS — এটা একটা single well-configured Postgres instance-ই সামলাতে পারবে, distributed system এর দরকারই নেই। এই তুলনাটা গুরুত্বপূর্ণ কারণ — ইন্টারভিউতে "appropriately simple for stated requirements" (Appendix A রুব্রিক) দেখানোর মানেই হলো স্কেল বুঝে ওভার-ইঞ্জিনিয়ারিং না করা।
৪. Storage হিসেবের সম্পূর্ণ ফ্রেমওয়ার্ক
ধাপে ধাপে প্রসেস
ধাপ ১: প্রতিটা object-এর average size ধরো (raw + metadata + thumbnail/derivative ভুলো না)
ধাপ ২: Daily new objects সংখ্যা বের করো
ধাপ ৩: Daily storage = daily objects × average size
ধাপ ৪: Retention period অনুযায়ী গুণ করো (কত বছর রাখতে হবে?)
ধাপ ৫: Replication factor (সাধারণত 3x, durability-এর জন্য) দিয়ে গুণ করো
বিস্তারিত উদাহরণ — Photo Service (Storage)
Assumptions:
- Daily uploads = 600M photos (আগের QPS হিসেব থেকে)
- প্রতি ছবির average compressed size = 200 KB (মূল ছবি) + 20 KB (thumbnail) = 220 KB/photo
- Retention: ৫ বছর (কোম্পানি পলিসি অনুযায়ী কখনো ডিলিট হয় না ধরে নিলাম)
- Replication factor: 3x
হিসেব:
Daily storage (raw) = 600,000,000 × 220 KB
= 1.32 × 10¹¹ KB
= 1.32 × 10⁸ MB
= 132,000 GB
= 132 TB/day
বার্ষিক storage = 132 TB × 365 ≈ 48,180 TB ≈ 48.2 PB/year
৫ বছরের storage (raw) = 48.2 PB × 5 ≈ 241 PB
Replication (3x) সহ total storage = 241 PB × 3 ≈ 723 PB
এই সংখ্যা থেকে ডিজাইন সিদ্ধান্ত:
- ৭২৩ PB — এটা কোনোভাবেই single-server বা এমনকি single-datacenter storage সিস্টেমে রাখা সম্ভব না
- এই স্কেলে object storage (S3-স্টাইল, Day 37) লাগবেই — filesystem-ভিত্তিক storage অসম্ভব
- Metadata (কে আপলোড করেছে, কখন, কোথায়) আলাদাভাবে ছোট এবং fast একটা ডাটাবেসে (Postgres/DynamoDB) রাখতে হবে, actual image bytes আলাদা object store-এ — এটাই classic pattern
একটা ছোট Twist — Tiered Storage Consideration
সিনিয়র-লেভেল উত্তর এখানে যোগ হয়: সব ছবি কি একই গুরুত্বের? বাস্তবে না — বেশিরভাগ ছবি আপলোডের প্রথম কয়েকদিনেই বেশি দেখা হয় (view count decay করে)। তাই:
- Recent photos (< 30 দিন) → hot storage, SSD-backed
- পুরনো photos → cold storage (S3 Glacier-স্টাইল), সস্তা কিন্তু slower retrieval
এটা Phase 8 (Day 160, Cost engineering)-এ আমরা আরও গভীরে যাবো, কিন্তু estimation-এর সময়েই এটা মেনশন করলে ইন্টারভিউয়ার বুঝে যায় তুমি শুধু সংখ্যা গুণ করছো না, cost-conscious ডিজাইনও ভাবছো।
৫. Bandwidth হিসেবের সম্পূর্ণ ফ্রেমওয়ার্ক
ধাপে ধাপে প্রসেস
Ingress bandwidth (আপলোড/write দিক) = Write QPS × average object size
Egress bandwidth (ডাউনলোড/read দিক) = Read QPS × average object size
বিস্তারিত উদাহরণ — Photo Service (Bandwidth)
Ingress (আপলোড):
Average ingress = 6,000 QPS × 220 KB = 1,320,000 KB/sec = 1.32 GB/sec
Peak ingress (3x) = 1.32 × 3 = 3.96 GB/sec ≈ 4 GB/sec
Egress (ডাউনলোড):
Average egress = 60,000 QPS × 220 KB = 13,200,000 KB/sec = 13.2 GB/sec
Peak egress (3x) = 13.2 × 3 = 39.6 GB/sec ≈ 40 GB/sec
মূল ইনসাইট: Egress (40 GB/sec) আর Ingress (4 GB/sec)-এর মধ্যে 10x পার্থক্য, ঠিক read:write ratio-এর মতোই (এটা কাকতালীয় না — bandwidth সরাসরি QPS × size থেকে আসে, আর size একই থাকে দুই দিকেই)।
এই থেকে সরাসরি সিদ্ধান্ত:
- CDN মূলত egress-এর জন্য দরকার, কারণ egress-ই বড় সমস্যা — একটা viral ছবি লক্ষ লক্ষ বার serve হতে পারে, আর CDN সেই repeated egress load-কে origin server থেকে সরিয়ে edge-এ নিয়ে যায়
- Ingress bandwidth তুলনামূলক ছোট, তাই upload path-এ আলাদা fancy infrastructure দরকার কম (যদিও resumable upload, chunking — Day 121 — অন্য কারণে দরকার হতে পারে)
৬. Peak vs Average — কখন কোনটা ব্যবহার করবে (সারাংশ টেবিল)
| ক্ষেত্র | কোনটা ব্যবহার করবে | কেন |
|---|---|---|
| Server/capacity provisioning | Peak | সিস্টেমকে সবচেয়ে ব্যস্ত মুহূর্ত সামলাতে হবে, নাহলে outage |
| Storage total | Average/cumulative total | Storage time-sensitive না, এটা জমা হওয়া (accumulated) ভলিউম |
| Cost estimation | দুটোই | Compute cost peak-নির্ভর, storage cost accumulated-নির্ভর |
| Bandwidth provisioning (network link) | Peak | Network link saturate হলে packet loss/latency spike হয় |
| Database connection pool sizing | Peak | Connection pool exhaust হলে পুরো সিস্টেম stall করে (Day 26-এ বিস্তারিত) |
সতর্কতা: Day 3-তে আমরা দেখবো "3x" একটা oversimplification — event-driven spike (viral post, breaking news) অনেক বেশি হতে পারে (10-50x)। কিন্তু আজকের জন্য baseline হিসেবে 2-3x যথেষ্ট এবং ইন্টারভিউতে গ্রহণযোগ্য standard assumption।
৭. সম্পূর্ণ Worked Example — শেষ থেকে শুরু পর্যন্ত (Video Streaming Service)
চলো একটা তৃতীয়, সম্পূর্ণ আলাদা ডোমেইনের উদাহরণ পুরোটা একসাথে করি, যাতে ফ্রেমওয়ার্কটা তোমার মাথায় গেঁথে যায়।
সিস্টেম: একটা video streaming platform (YouTube-স্টাইল, ছোট স্কেলে)
Assumptions:
- 100M DAU
- প্রতি ইউজার গড়ে দিনে 1টা ভিডিও আপলোড করে (মাত্র সংখ্যালঘু ইউজার আপলোড করে ধরলে প্রকৃত সংখ্যা কম হবে, কিন্তু simplification-এর জন্য এভাবে ধরছি)
- প্রতি ইউজার গড়ে দিনে 10টা ভিডিও দেখে (প্রতিটা average 5 মিনিট)
- Video average size (আপলোডের সময়, transcoding-এর আগে): 500 MB
- Streamed video-এর bitrate: 5 Mbps (adaptive bitrate-এর মাঝারি quality ধরে)
- Retention: ৩ বছর, Replication 3x
QPS:
Write QPS (avg) = 100M × 1 / 10⁵ = 1,000 QPS (video upload requests)
Read QPS (avg) = 100M × 10 / 10⁵ = 10,000 QPS (video play requests)
Read:Write = 10:1 (এখানেও read-heavy!)
Storage:
Daily raw upload storage = 100M × 500 MB = 5 × 10¹⁰ MB = 5 × 10⁷ GB = 50,000 TB = 50 PB/day (raw, transcoding আগে)
এখানে একটা বাস্তবতা মেনশন করা জরুরি: transcoding-এর পরে multiple resolution ladder (240p, 480p, 720p, 1080p) তৈরি হয় (Day 122), যা storage আরও ~2-3x বাড়ায় — কিন্তু compression-ও (H.264/H.265) সাইজ কমায়। ইন্টারভিউতে এই nuance মেনশন করলেই যথেষ্ট, exact number দরকার নেই যতক্ষণ না ইন্টারভিউয়ার push করে।
৩ বছরে (raw, replication ছাড়া) = 50 PB × 365 × 3 ≈ 54,750 PB ≈ 54.75 EB (exabyte!)
এই সংখ্যা দেখেই বোঝা যায় — video storage-এ raw upload রাখা অসম্ভব ব্যয়বহুল, তাই aggressive compression, tiered/cold storage, এবং হয়তো পুরনো কম-দেখা ভিডিও ডিলিট বা lower-resolution-এ downgrade করার পলিসি লাগবে (Day 160, cost engineering-এর প্রিভিউ)।
Bandwidth (এখানে সবচেয়ে ইন্টারেস্টিং অংশ — streaming bandwidth storage থেকে সম্পূর্ণ আলাদাভাবে হিসেব হয়):
Concurrent viewers estimation:
যদি average ভিডিও-দেখা সময় 5 মিনিট (300 সেকেন্ড) হয়, আর daily views 10,000 QPS (avg) হারে আসে,
তাহলে concurrent viewers (Little's Law: L = λ × W)
= 10,000 views/sec × 300 sec = 3,000,000 concurrent streams (average)
Egress bandwidth = concurrent streams × bitrate per stream
= 3,000,000 × 5 Mbps
= 15,000,000 Mbps
= 15 Tbps (average!)
Peak (3x) = 45 Tbps
এটাই সবচেয়ে গুরুত্বপূর্ণ শিক্ষা: video-এর মতো সিস্টেমে egress bandwidth photo/text সিস্টেমের চেয়ে অর্ডার-অফ-ম্যাগনিটিউড বেশি, কারণ প্রতিটা request দীর্ঘ সময় ধরে continuous data স্ট্রিম করে (একটা QPS ≠ একটা instant transfer)। এইজন্যই Netflix নিজস্ব CDN (Open Connect, Day 125) বানিয়েছে — সাধারণ CDN প্রোভাইডারের কাছে এই স্কেলের egress কেনা আর্থিকভাবে অসম্ভব হয়ে যেত।
নতুন শেখা টুল: Little's Law (L = λW) — concurrent users/items বের করার জন্য এটা মনে রাখো: (arrival rate) × (average time spent in system) = (average number in system)। এটা শুধু bandwidth না, connection pool sizing (Day 26), thread pool sizing — যেকোনো জায়গায় কাজে লাগে।
৮. Sanity-Check করার অভ্যাস (রুব্রিকের "sanity-checks results" অংশ)
যেকোনো বড় সংখ্যা পাওয়ার পরে নিজেকে জিজ্ঞেস করো:
- এই সংখ্যাটা কি বাস্তব-জগতের কোনো পরিচিত কোম্পানির সাথে তুলনীয়? (যেমন, "Netflix-এর মোট bandwidth নাকি প্রায় global internet traffic-এর 15%" — এটা জানা থাকলে নিজের হিসেবকে reality-check করা যায়)
- সংখ্যাটা কি এত বড় যে এটা কোনো একক component-এর পক্ষে অসম্ভব? (যেমন, single Postgres ~10,000-50,000 QPS-এর বেশি সহজে সামলাতে পারে না — যদি তোমার হিসেব তার চেয়ে বেশি আসে, distributed solution দরকার সেটা নিশ্চিত)
- Order of magnitude ঠিক আছে তো? (একটা 10x ভুল হয়ে গেলে পুরো architecture সিদ্ধান্ত ভুল হয়ে যাবে)
৯. আজকের Application Exercise (নিজে কাগজে করো, ক্যালকুলেটর ছাড়া)
Exercise: Chat Service (WhatsApp-স্টাইল)
Assumptions:
- 500M DAU
- প্রতি ইউজার গড়ে দিনে 40টা মেসেজ পাঠায় (text)
- প্রতি মেসেজ average 100 bytes
- ২০% মেসেজে image attachment থাকে, average attachment size 150 KB
তোমাকে বের করতে হবে:
- Write QPS (average + peak, 3x factor)
- দৈনিক text storage (attachment বাদে)
- দৈনিক attachment storage যোগ করে total storage
- ২ বছরের total storage (3x replication সহ)
- Ingress bandwidth (average, text + attachment মিলিয়ে)
১০. Active Recall প্রশ্ন — উত্তর দাও
- Read:Write ratio কীভাবে সরাসরি caching strategy এবং infrastructure সিদ্ধান্তে প্রভাব ফেলে — Photo service উদাহরণ দিয়ে ব্যাখ্যা করো।
- কেন storage হিসেবের সময় "peak factor" প্রয়োগ করা হয় না, কিন্তু bandwidth আর server capacity-তে করা হয়?
- Little's Law (L = λW) কী, এবং video streaming bandwidth হিসেবে এটা কেন দরকার হলো যেটা QPS দিয়ে সরাসরি হিসেব করা যায়নি?
- উপরের Chat Service exercise সম্পূর্ণ করো — সব সংখ্যা লিখে ফেলো।
পরবর্তী: Day 3 — Peak vs average, growth modeling (আলাদা ফাইলে)
Day 3 · Peak vs average, growth modeling
১. কেন এই টপিকটা Day 2-এর পরপরই দরকার
Day 2-তে আমরা peak factor হিসেবে flat "3x" ব্যবহার করেছিলাম। এটা ইন্টারভিউতে গ্রহণযোগ্য baseline, কিন্তু যদি ইন্টারভিউয়ার একটু গভীরে চাপ দেয় ("এই 3x কোথা থেকে আসলো?", "সবসময় কি 3x?") — তখন তোমাকে peak traffic-এর প্রকৃত স্তরবিন্যাস জানতে হবে। একইভাবে, "এই ডিজাইন কি ভবিষ্যতে টিকবে?" প্রশ্নের উত্তর দিতে গেলে growth modeling দরকার। রুব্রিকে (Appendix A) এই দুইটা জিনিস সরাসরি দুইটা dimension-কে প্রভাবিত করে: Scalability & bottlenecks ("identifies the true bottleneck, not the obvious one") এবং Adaptability ("absorbs the change cleanly", curveball সেগমেন্টে ঠিক এই জিনিসটাই টেস্ট হয়)।
২. Peak Traffic-এর তিনটা স্তর (বিস্তারিত)
২.১ Diurnal (দৈনিক) Peak
এটা দিনের মধ্যেই ঘণ্টাভিত্তিক ওঠানামা। মানুষের ঘুম/জাগরণ চক্রের সাথে যুক্ত।
উদাহরণ — একটা ফুড ডেলিভারি অ্যাপ:
- রাত ২টা-৬টা: প্রায় শূন্য ট্রাফিক (average-এর ~5%)
- সকাল ৮-১০টা: হালকা বৃদ্ধি (breakfast order, average-এর ~80%)
- দুপুর ১২টা-২টা: প্রথম spike (lunch, average-এর ~250%)
- সন্ধ্যা ৭টা-৯টা: সবচেয়ে বড় spike (dinner, average-এর ~300%)
এই ধরনের সিস্টেমে "average QPS" আসলে একটা misleading সংখ্যা — কারণ প্রকৃত সিস্টেমকে বেশিরভাগ সময় 30-80% capacity-তে idle থাকতে হয়, আর দিনে মাত্র ২-৩ ঘণ্টা পুরো ক্ষমতায় চলতে হয়। এইজন্যই আমরা average থেকে multiplier ধরে peak বের করি — এই multiplier-ই হলো diurnal peak factor, সাধারণত 2-3x।
গাণিতিক উদাহরণ: যদি average QPS = 10,000 হয় এবং dinner-time spike average-এর 3x হয়, তাহলে peak QPS = 30,000। সার্ভার ক্যাপাসিটি এই 30,000-এর জন্য provision করতে হবে, নাহলে প্রতিদিন সন্ধ্যায় সিস্টেম ক্র্যাশ করবে।
২.২ Weekly Peak
সপ্তাহের দিন অনুযায়ী প্যাটার্ন পরিবর্তন হয়, প্রোডাক্টের ধরন অনুযায়ী দুই বিপরীত দিকে যেতে পারে।
উদাহরণ ১ — E-commerce (B2C): শুক্র-শনি-রবি (উইকেন্ড, দেশ অনুযায়ী ভিন্ন হতে পারে) ট্রাফিক normal weekday-র চেয়ে ~30-50% বেশি, কারণ মানুষ অবসর সময়ে শপিং করে।
উদাহরণ ২ — B2B SaaS Tool (যেমন প্রজেক্ট ম্যানেজমেন্ট টুল): এর ঠিক উল্টো — সোম-শুক্র অফিস আওয়ারে ট্রাফিক পিক করে, উইকেন্ডে ৭০-৮০% কমে যায়। Monday morning-এ প্রায়ই একটা "catch-up spike" থাকে কারণ সবাই উইকেন্ডের পেন্ডিং কাজ ঢুকিয়ে দেয়।
ডিজাইন প্রভাব: এই weekly pattern জানা থাকলে তুমি auto-scaling policy-কে (Day 169) শুধু সময়ের ভিত্তিতে না, দিনের ভিত্তিতেও টিউন করতে পারবে — যেমন B2B টুলে উইকেন্ডে server capacity 40% কমিয়ে cost বাঁচানো যায় (predictable pattern হলে scheduled scaling কাজ করে, শুধু reactive auto-scaling না লাগলেও চলে)।
২.৩ Event-Driven / Seasonal Peak — সবচেয়ে বিপজ্জনক স্তর
এটাই আসল ঝুঁকি, কারণ এই peak-এর ম্যাগনিটিউড diurnal/weekly peak-এর তুলনায় অনেক বড়, এবং প্রায়ই আগে থেকে পুরোপুরি predict করা যায় না।
উদাহরণ ১ — মেসেজিং অ্যাপ, নববর্ষের রাত: ডিসেম্বর ৩১ রাত ১১:৫৫টা থেকে জানুয়ারি ১ রাত ১২:১০টা পর্যন্ত (মাত্র ১৫ মিনিটের উইন্ডো) message volume normal দিনের 10-20x হয়ে যায়। এটা predictable (তারিখটা জানা), কিন্তু ম্যাগনিটিউড এতটাই বড় যে normal 3x provisioning সম্পূর্ণ ভেঙে পড়বে।
উদাহরণ ২ — E-commerce, Black Friday/Cyber Monday: normal ট্রাফিকের 5-10x, কিন্তু এখানে শুধু QPS বাড়ে না — checkout/payment path-এ conversion rate-ও বদলায়, inventory contention (Day 133) বেড়ে যায়, এবং fraud detection সিস্টেম (Day 136)-এ false positive বাড়তে পারে কারণ normal user behavior pattern-ও বদলে যায় sale-এর সময়।
উদাহরণ ৩ — Viral Content (unpredictable): ধরো একটা celebrity হঠাৎ একটা পোস্ট শেয়ার করলো, বা কোনো breaking news notification পাঠাতে হলো (তোমার ⭐ notification system experience-এর সাথে সরাসরি সম্পর্কিত)। একটা নির্দিষ্ট post/user-এর জন্য read traffic normal-এর 50-100x হয়ে যেতে পারে কয়েক মিনিটের মধ্যে, এবং এটা আগে থেকে predict করা প্রায় অসম্ভব — এইজন্যই এটাকে "celebrity problem" বলা হয় (Day 96-এ feed system আলোচনায় ফিরে আসবো)।
গুরুত্বপূর্ণ ফ্রেমওয়ার্ক — ইন্টারভিউতে কীভাবে বলবে:
দুর্বল উত্তর (score ~3): "আমি peak factor হিসেবে 3x ধরছি।"
শক্তিশালী উত্তর (score 4-5): "Diurnal peak-এর জন্য আমি baseline 3x ধরছি overall capacity provisioning-এ। কিন্তু এই সিস্টেমে যদি viral/celebrity effect থাকে (যেমন এখানে feed বা notification path), সেই নির্দিষ্ট hot path-এর জন্য আমি আলাদাভাবে ভাবতে চাই — হয় sufficient headroom রাখবো (20-50x spike সামলানোর মতো), অথবা একটা graceful degradation strategy (Day 166, load shedding) রাখবো যাতে পুরো সিস্টেম না ভেঙে শুধু সেই hot feature-টা degrade করে।"
এই দ্বিতীয় উত্তরটা দেখায় তুমি bottleneck আগেই চিহ্নিত করেছো, শুধু prompted হয়ে না (রুব্রিক dimension: Scalability & bottlenecks)।
৩. Load Factor আর Safety Margin — কেন শুধু Peak ধরাও যথেষ্ট না
যদি capacity ঠিক peak QPS-এর সমান রাখা হয়, সিস্টেম তাত্ত্বিকভাবে চলবে, কিন্তু বাস্তবে কোনো buffer/margin থাকবে না unexpected variance-এর জন্য। তাই:
Required Provisioned Capacity = Peak QPS × Safety Margin
সাধারণত Safety Margin = 1.3-1.5x (industry-standard rule of thumb)।
সম্পূর্ণ উদাহরণ:
- Average QPS = 60,000
- Diurnal peak factor = 3x → Peak QPS = 180,000
- Safety margin = 1.3x → Provisioned Capacity = 180,000 × 1.3 = 234,000 QPS
কেন এই অতিরিক্ত margin দরকার:
- Traffic estimation-এ ভুল থাকতে পারে — DAU বা per-user action সংখ্যা assumption ভুল হতে পারে
- Hardware failure buffer — যদি একটা node/server ক্লাস্টার থেকে বাদ পড়ে (crash, maintenance), বাকি nodes-কে অতিরিক্ত load নিতে হবে
- Unplanned mini-spikes — diurnal peak-এর মধ্যেও ছোট ছোট micro-spike থাকতে পারে যেগুলো average করে ফেলা হয়েছে
এই "headroom" কনসেপ্টটা Phase 8 (Day 169, Capacity Planning)-এ আরও বিস্তারিত আসবে, কিন্তু এখনই estimation-এর সময় এটা মেনশন করলে ইন্টারভিউয়ার বুঝবে তুমি শুধু নাম্বার গুণ করছো না, operational reality-ও ভাবছো।
৪. Growth Modeling — দুটো মডেল, বিস্তারিত গাণিতিক উদাহরণ সহ
৪.১ Linear Growth Model
পরিণত (mature), স্থিতিশীল প্রোডাক্টের জন্য উপযুক্ত — যেখানে growth একটা নির্দিষ্ট, প্রায় constant হারে হয়, শতাংশ compound হয় না।
Users(t) = Users(0) + growth_rate × t
উদাহরণ — একটা established B2B ইনভয়েসিং টুল:
- আজ 100,000 কোম্পানি ব্যবহার করছে (Users(0))
- প্রতি মাসে নতুন 2,000 কোম্পানি যোগ হয় (growth_rate, প্রায় constant, কারণ B2B sales cycle নির্দিষ্ট গতিতে চলে)
Users(12 মাস পরে) = 100,000 + 2,000 × 12 = 100,000 + 24,000 = 124,000
এখানে growth শতাংশ হিসেবে দেখলে প্রথম মাসে 2% বৃদ্ধি, কিন্তু ১২তম মাসে সেই একই 2,000 নতুন ইউজার তখনকার বেসের মাত্র ~1.7% (কারণ বেস বড় হয়ে গেছে) — অর্থাৎ শতাংশ হারে growth ক্রমশ কমছে, এটাই linear model-এর বৈশিষ্ট্য।
৪.২ Exponential Growth Model
নতুন, viral-phase প্রোডাক্টের জন্য — যেখানে growth rate একটা constant শতাংশ (percentage), যা প্রতিবার আগের (already-grown) বেসের উপর প্রযোজ্য হয় (compounding)।
Users(t) = Users(0) × (1 + r)^t
যেখানে r = growth rate per period (যেমন মাসিক 10%), t = কতগুলো period।
উদাহরণ — একটা নতুন ভাইরাল সোশ্যাল অ্যাপ:
- আজ 1,000,000 DAU (Users(0))
- মাসিক growth rate 15% (r = 0.15, viral phase)
Users(12 মাস পরে) = 1,000,000 × (1.15)^12
ধাপে ধাপে কম্পাউন্ডিং (approximate):
মাস 1: 1,000,000 × 1.15 = 1,150,000
মাস 2: 1,150,000 × 1.15 = 1,322,500
মাস 3: 1,322,500 × 1.15 = 1,520,875
মাস 6: ≈ 2,313,061
মাস 9: ≈ 3,517,876
মাস 12: ≈ 5,350,250
(1.15)^12 ≈ 5.35 — মানে ১ বছরে DAU প্রায় ৫.৩৫ গুণ বেড়ে যাবে, 1M থেকে ~5.35M।
৪.৩ Rule of 72 — মুখে মুখে দ্রুত Doubling Time বের করার শর্টকাট
Exponential growth-এ একটা quantity কতদিনে ডাবল হবে সেটা বের করতে:
Doubling Time ≈ 72 / (growth rate, শতাংশে)
উদাহরণ প্রয়োগ:
- 15% মাসিক growth → Doubling time ≈ 72/15 = 4.8 মাস
- 10% মাসিক growth → Doubling time ≈ 72/10 = 7.2 মাস
- 20% মাসিক growth → Doubling time ≈ 72/20 = 3.6 মাস
- 5% মাসিক growth (moderate, established product) → Doubling time ≈ 72/5 = 14.4 মাস
কেন এই শর্টকাট ইন্টারভিউতে এত মূল্যবান: ইন্টারভিউয়ার যদি বলে "growth rate মাসিক 20%", তুমি সাথে সাথে (ক্যালকুলেটর ছাড়া) বলতে পারবে "তাহলে প্রতি ~৩.৬ মাসে ইউজার বেস ডাবল হবে, মানে প্রতি ৩.৬ মাসে storage, QPS, bandwidth — সব resource-ই ডাবল হবে যদি per-user usage constant থাকে।" এটা তাৎক্ষণিকভাবে দেখায় তুমি সংখ্যাটার প্রভাব বুঝছো, শুধু ফর্মুলা জানো না।
৫. Growth Modeling-এর ডিজাইনে প্রভাব — তিনটা নির্দিষ্ট প্রশ্ন
যখন ইন্টারভিউয়ার বলবে "৩ বছরের জন্য ডিজাইন করো", তোমাকে এই তিনটা প্রশ্নের উত্তর স্পষ্টভাবে দিতে হবে:
৫.১ কোন Resource সবার আগে Bottleneck হবে?
উদাহরণ: ধরো storage আর QPS দুটোই বাড়ছে, কিন্তু ভিন্ন হারে।
- Storage বাড়ে cumulative ভাবে (প্রতিদিনের নতুন ডেটা জমা হতে থাকে, পুরনো ডেটা delete না হলে) — এমনকি user growth flat থাকলেও storage বাড়তেই থাকে
- QPS বাড়ে user growth rate অনুযায়ী (যদি per-user usage constant থাকে) — user growth যদি exponential হয়, QPS-ও exponential-ভাবে বাড়ে
তাই একটা সিস্টেমে হয়তো ১২ মাস পরে QPS ৫ গুণ বেড়ে গেছে (exponential user growth-এর কারণে), কিন্তু storage বেড়েছে মাত্র ২ গুণ (কারণ per-user data generation rate কম, অথবা অনেক ইউজার নতুন এবং এখনও বেশি ডেটা জমাননি) — এই ক্ষেত্রে compute/QPS bottleneck storage bottleneck-এর অনেক আগে আসবে, তাই horizontal scaling (read replica, sharding) storage optimization-এর চেয়ে বেশি জরুরি অগ্রাধিকার।
৫.২ Architecture কি Re-architecture ছাড়া স্কেল করবে?
উদাহরণ — একটা নতুন স্টার্টআপ চ্যাট অ্যাপ, মাসিক 20% growth:
আজ: 1M DAU → single Postgres instance যথেষ্ট (read replica সহ)
৩.৬ মাস পরে: 2M DAU → read replica-র সংখ্যা বাড়াতে হবে
৭.২ মাস পরে: 4M DAU → connection pooling limit-এ চাপ পড়বে, PgBouncer টিউনিং লাগবে (Day 26)
১০.৮ মাস পরে: 8M DAU → single-master write bottleneck শুরু হবে, sharding নিয়ে ভাবতে হবে (Day 34, 40)
১৪.৪ মাস পরে: 16M DAU → পুরো architecture সম্ভবত re-design লাগবে (Cassandra/DynamoDB migration, বা distributed SQL)
এই "স্কেলিং মাইলফলক" (milestone) আগে থেকে ম্যাপ করে রাখা — কোন DAU সংখ্যায় কোন component প্রথম ভাঙবে — এটাই সিনিয়র-লেভেল সিগন্যাল, কারণ এটা দেখায় তুমি শুধু আজকের জন্য না, ধাপে ধাপে evolve হওয়া architecture ভাবছো (Appendix A: "appropriately simple for stated requirements")।
৫.৩ Over-Engineering বনাম Under-Engineering-এর ট্রেডঅফ
ভুল পন্থা ১ (Under-engineering): শুধু আজকের 1M DAU-এর জন্য ডিজাইন করা, কোনো scaling path না রেখে — ৪-৫ মাস পরেই পুরো সিস্টেম ভেঙে পড়বে যদি growth সত্যিই 20%/মাস হয়।
ভুল পন্থা ২ (Over-engineering): আজকেই ৫ বছর পরের hypothetical 500M DAU-এর জন্য পুরো distributed, multi-region, sharded architecture বানানো — এটা এখন unnecessary complexity, দীর্ঘ development time, এবং operational overhead তৈরি করবে যেটার দরকারই নেই যদি growth prediction ভুল হয় (viral growth প্রায়ই কমে যায় বা থেমে যায়)।
সঠিক পন্থা: "আমি প্রথম ১২-১৮ মাসের প্রেডিক্টেবল growth-এর জন্য ডিজাইন করবো, কিন্তু architecture-এ কিছু 'cheap insurance' রাখবো — যেমন, শুরু থেকেই ডেটা partition key ভালোভাবে বেছে নেওয়া (future sharding সহজ করার জন্য, যদিও এখনই shard করছি না), এবং stateless application server layer রাখা (horizontal scale করা সহজ হবে)।" এটাই ভারসাম্যপূর্ণ, ইন্টারভিউতে সবচেয়ে গ্রহণযোগ্য উত্তর।
৬. সম্পূর্ণ Worked Example — একটা প্রোডাক্ট, দুই বছরের সম্পূর্ণ Growth Projection
সিস্টেম: একটা নতুন food delivery অ্যাপ
Assumptions:
- আজ: 2M DAU
- প্রতি ইউজার গড়ে সপ্তাহে 3টা অর্ডার করে (write action)
- Growth rate: প্রথম ১ বছর মাসিক 12% (aggressive expansion phase), পরের বছর মাসিক 4% (maturation phase — এটা বাস্তবসম্মত, কারণ কোনো প্রোডাক্টই চিরকাল exponential growth রাখে না)
বছর ১ শেষে (12% মাসিক, 12 মাস):
DAU(12) = 2,000,000 × (1.12)^12
(1.12)^12 ≈ 3.896
DAU(12) ≈ 7,792,000 ≈ 7.8M
Doubling time (Rule of 72): 72/12 = ৬ মাস — মানে বছরে দুইবার ডাবল হওয়ার মতো growth।
বছর ২ শেষে (4% মাসিক growth থেকে চালিয়ে, আরও 12 মাস):
DAU(24) = 7,792,000 × (1.04)^12
(1.04)^12 ≈ 1.601
DAU(24) ≈ 12,475,000 ≈ 12.5M
QPS প্রভাব (write, order placement):
আজ: 2M × 3 orders/week / 7 days / 10⁵ sec ≈ 8.6 QPS (average)
বছর ১ শেষে: 7.8M × 3/7/10⁵ ≈ 33.4 QPS (average) — প্রায় ৩.৯ গুণ বৃদ্ধি
বছর ২ শেষে: 12.5M × 3/7/10⁵ ≈ 53.6 QPS (average) — মোট প্রায় ৬.২ গুণ বৃদ্ধি (শুরুর তুলনায়)
ডিজাইন সিদ্ধান্ত এই প্রজেকশন থেকে:
- প্রথম বছরে growth rate এতটাই দ্রুত (6 মাসে ডাবল) যে quarterly capacity review যথেষ্ট না হতে পারে — বরং monthly বা এমনকি real-time auto-scaling metric-ভিত্তিক (Day 169) দরকার
- দ্বিতীয় বছরে growth ধীর হয়ে যাওয়ায় (maturation), সেই সময় থেকে capacity planning অনেকটা predictable/linear হয়ে যাবে — তখন aggressive over-provisioning-এর দরকার কমে যাবে
- একটা গুরুত্বপূর্ণ পয়েন্ট: এই QPS সংখ্যা (53.6 QPS peak-এর আগে) এখনো তুলনামূলক ছোট — single well-tuned Postgres instance-ই এটা সামলাতে পারবে (Day 2-এর B2B invoicing উদাহরণ মনে করো)। তাই এখানে আসল challenge QPS না, বরং inventory/restaurant availability data-এর consistency আর geospatial matching (Day 128-132)-এর মতো অন্য জটিলতা, যেগুলো traffic ছোট হলেও architecturally কঠিন।
এই শেষ পয়েন্টটাই গুরুত্বপূর্ণ শিক্ষা: growth modeling শুধু "সংখ্যা কত বড় হবে" তা না, বরং "কোন resource-এ চাপ পড়বে এবং কখন" — সেই বোঝাপড়া তৈরি করার জন্য।
৭. Active Recall প্রশ্ন
- Diurnal peak, weekly peak, আর event-driven peak — এই তিনটার মধ্যে পার্থক্য কী, এবং কেন event-driven peak সবচেয়ে বিপজ্জনক? প্রতিটার জন্য একটা করে নিজের উদাহরণ দাও (উপরের থেকে আলাদা)।
- Linear growth আর exponential growth model-এর মধ্যে মৌলিক পার্থক্য কী — এবং কীভাবে বুঝবে কোন প্রোডাক্টের জন্য কোন মডেল প্রযোজ্য?
- Rule of 72 ব্যবহার করে হিসেব করো: যদি একটা সিস্টেমে মাসিক 8% growth rate থাকে, doubling time কত? আর যদি প্রোডাক্ট maturation-এর পরে growth rate কমে মাসিক 2% হয়ে যায়, তখন doubling time কত হবে?
- উপরের food delivery worked example-এ, কেন লেখক বলেছে যে "আসল challenge QPS না, বরং geospatial matching"? তোমার নিজের ভাষায় এই যুক্তিটা ব্যাখ্যা করো।
- "Safety margin" (1.3-1.5x) কেন peak QPS-এর উপরেও আলাদাভাবে যোগ করা হয় — তিনটা কারণের মধ্যে যেকোনো দুটো বিস্তারিত ব্যাখ্যা করো।
Branch 1.2 — Network Layer (Days 4–11)
শুরুর আগে — Prerequisite Check
এই ব্রাঞ্চে ঢোকার আগে নিচের জিনিসগুলো তোমার ক্লিয়ার থাকা দরকার (Day 1-2 থেকে):
- Latency numbers মনে আছে তো? বিশেষ করে "same datacenter round trip (~500μs)" আর "cross-continent round trip (~150ms)" — এই ব্রাঞ্চে আমরা কেন এই সংখ্যাগুলো এমন, সেটার mechanics শিখবো।
- OSI/TCP-IP মডেলের বেসিক ধারণা থাকা দরকার — যদি একদম না থাকে, সংক্ষেপে বলি:
- Layer 3 (Network) → IP addressing, routing
- Layer 4 (Transport) → TCP/UDP — কীভাবে দুই মেশিনের মধ্যে reliable/unreliable data flow হয়
- Layer 7 (Application) → HTTP, gRPC, DNS — actual application data
এই ব্রাঞ্চ (Day 4-11) মূলত Layer 4 থেকে Layer 7 পর্যন্ত একটা request কীভাবে ভ্রমণ করে সেটা কভার করবে। শেষে (Day 10-11) গিয়ে আমরা দেখবো এই request গুলো কীভাবে অনেকগুলো সার্ভারে distribute হয়।
কেন এই অর্ডারে শেখানো হচ্ছে? TCP (Day 4) → তার ওপর TLS (Day 6) → তার ওপর HTTP (Day 7) → DNS দিয়ে address resolve (Day 8) → CDN দিয়ে content কাছে আনা (Day 9) → Load Balancer দিয়ে distribute করা (Day 10) — এটা exactly সেই ক্রম যেভাবে একটা real request ঘটে।
🗺️ পুরো Request Journey — Big Picture (এটা মাথায় রেখে পড়ো)
User টাইপ করলো example.com
│
▼
[Day 8] DNS Resolution → IP address পাওয়া গেলো
│
▼
[Day 4] TCP Handshake → connection স্থাপন
│
▼
[Day 6] TLS Handshake → secure channel তৈরি
│
▼
[Day 9] CDN → কাছের PoP থেকে static content
│
▼
[Day 10-11] Load Balancer → সঠিক backend সার্ভারে route
│
▼
[Day 7] HTTP Request/Response → actual data exchange
প্রতিটা ধাপে যদি ১ms করেও latency যোগ হয়, পুরো chain মিলে user experience-এ বড় প্রভাব ফেলে — এইজন্যই প্রতিটা layer আলাদাভাবে বোঝা দরকার।
Day 4 — TCP Internals: Handshake, Congestion Control, Nagle's Algorithm
কেন TCP?
TCP হলো সেই protocol যেটা নিশ্চিত করে ডেটা reliably, in-order, without duplication পৌঁছায়। এটা "connection-oriented" — মানে ডেটা পাঠানোর আগে দুই পক্ষকে একটা সম্পর্ক (connection) স্থাপন করতে হয়।
3-Way Handshake
Client Server
│ ------- SYN (seq=x) --------→ │
│ ←---- SYN-ACK (seq=y,ack=x+1)-│
│ ------- ACK (ack=y+1) ------→ │
│ │
│ Connection Established │
- SYN: Client বলে "আমি connection শুরু করতে চাই, আমার sequence number x থেকে শুরু"
- SYN-ACK: Server বলে "ঠিক আছে, আমিও রাজি, আমার sequence number y, তোমার x পেয়েছি"
- ACK: Client বলে "তোমার y পেয়েছি, এখন কথা শুরু করি"
গুরুত্বপূর্ণ সংখ্যা: এই পুরো handshake-এ 1 RTT (Round Trip Time) লাগে ডেটা পাঠানো শুরুর আগেই। যদি client-server 150ms দূরে থাকে (cross-continent), শুধু connection বানাতেই 150ms চলে যায় — কোনো actual ডেটা এখনো যায়নি!
কেন Connection Reuse এত গুরুত্বপূর্ণ (এটা explain করতে পারা Day 4-এর মূল লক্ষ্য)
প্রতিবার নতুন TCP connection বানালে:
- নতুন 3-way handshake (1 RTT)
- TCP-এর "slow start" আবার শুরু হয় (নিচে দেখো)
- যদি TLS থাকে, আরেকটা handshake (Day 6)
এইজন্য HTTP Keep-Alive, connection pooling (তোমার PgBouncer এক্সপেরিয়েন্স ঠিক এই একই সমস্যার সমাধান, শুধু database লেয়ারে), এবং HTTP/2-এর multiplexing (Day 7) — সবগুলোই একটা মূল সমস্যার সমাধান: নতুন connection বানানোর cost এড়ানো।
Congestion Control — কেন TCP হঠাৎ সব ডেটা পাঠায় না
TCP জানে না নেটওয়ার্কের capacity কত। তাই এটা ধীরে ধীরে গতি বাড়ায়:
Slow Start:
- শুরুতে একটা ছোট "congestion window" (cwnd) দিয়ে শুরু (সাধারণত 10 segments)
- প্রতিটা successful ACK-এ cwnd দ্বিগুণ হয় (exponential growth)
- Packet loss হলেই বোঝে network কনজেস্টেড, এবং cwnd হঠাৎ কমিয়ে দেয় (Congestion Avoidance-এ চলে যায়)
এর প্র্যাকটিক্যাল প্রভাব: একটা নতুন connection-এ প্রথম কয়েক RTT-তে থ্রুপুট কম থাকে — এইজন্য ছোট ছোট অনেক request (যেমন অনেক ছোট image file) পাঠানো, একটা বড় persistent connection-এর চেয়ে অনেক ধীর হতে পারে, প্রতিবার slow start থেকে শুরু হওয়ার কারণে।
Nagle's Algorithm — ছোট প্যাকেট batch করা
Nagle's Algorithm ছোট ছোট প্যাকেট (যেমন এক-অক্ষরের keystroke) একসাথে জমিয়ে পাঠায়, যাতে নেটওয়ার্ক ছোট প্যাকেটের overhead-এ নষ্ট না হয়।
সমস্যা: এটা latency বাড়িয়ে দেয় কারণ ডেটা পাঠানোর আগে buffer-এ অপেক্ষা করে। এইজন্য real-time application (gaming, trading systems) এ TCP_NODELAY flag সেট করে Nagle's Algorithm বন্ধ করে দেওয়া হয়।
Interview-এ বলার মতো লাইন: "Nagle's algorithm throughput optimize করে কিন্তু latency-sensitive application-এ এটা disable করতে হয়, কারণ এটা delayed ACK-এর সাথে মিলে বিশেষভাবে খারাপ interaction তৈরি করতে পারে (একে 'Nagle-Delayed ACK deadlock' বলা হয়)।"
🎯 Active Recall — Day 4
- একটা cross-continent (150ms RTT) client TCP connection বানাতে কত সময় লাগবে শুধু handshake-এ (কোনো TLS ছাড়া)?
- কেন connection pooling (তোমার PgBouncer experience) TCP-এর slow start সমস্যার সাথে সম্পর্কিত?
- কোন ধরনের application-এ Nagle's Algorithm বন্ধ রাখা উচিত এবং কেন?
Day 5 — UDP, QUIC, এবং কখন TCP ছেড়ে দেওয়া উচিত
UDP — Reliability ছাড়া গতি
UDP-তে কোনো handshake নেই, কোনো guarantee নেই ডেটা পৌঁছাবে বা order ঠিক থাকবে কিনা। শুধু "fire and forget"।
কেন এটা কখনো কখনো ভালো: DNS query, video streaming, online gaming — এসব ক্ষেত্রে stale/lost ডেটার চেয়ে দেরি করা খারাপ। একটা গেমে যদি একটা position-update প্যাকেট হারিয়ে যায়, পরের প্যাকেটেই নতুন position আসবে — পুরনোটা re-send করার কোনো মানে নেই।
QUIC — TCP-এর সমস্যাগুলোর আধুনিক সমাধান
QUIC হলো UDP-এর উপর বানানো একটা নতুন protocol (Google-এর তৈরি, এখন HTTP/3-এর ভিত্তি) যেটা TCP-এর reliability রাখে কিন্তু তিনটা বড় সমস্যা সমাধান করে:
- Head-of-line blocking নেই: TCP-তে একটা stream-এর মধ্যে packet loss হলে পুরো stream আটকে যায়। QUIC-এ multiple independent stream একই connection-এ চলে, একটার loss অন্যটাকে block করে না। (HTTP/2-তে এই সমস্যাটাই থেকে যায় কারণ HTTP/2 এখনো TCP-এর উপরে চলে — Day 7-এ এটা বিস্তারিত দেখবো)
- দ্রুততর handshake: QUIC TLS handshake আর connection handshake একসাথে করে ফেলে (combined), তাই 1 RTT-এর বদলে প্রায় 0-RTT (repeat connection-এ) সম্ভব হয়।
- Connection migration: যদি তোমার ফোন WiFi থেকে mobile data-য় switch করে, TCP connection ভেঙে যায় (নতুন IP)। QUIC connection ID দিয়ে চলে, IP বদলালেও connection বেঁচে থাকে।
কখন কী ব্যবহার করবে (ডিসিশন ফ্রেমওয়ার্ক)
| Use case | Protocol | কেন |
|---|---|---|
| Web browsing (HTTP/3) | QUIC | দ্রুত handshake, no HOL blocking |
| Video call / gaming | UDP (custom) | Loss tolerable, latency critical |
| File transfer, DB replication | TCP | Reliability essential, loss unacceptable |
| DNS query | UDP | ছোট, দ্রুত, retry সহজ |
🎯 Active Recall — Day 5
- QUIC কীভাবে head-of-line blocking সমাধান করে যেটা TCP পারে না?
- Mobile app-এ QUIC কেন বিশেষভাবে উপকারী (connection migration প্রসঙ্গে)?
- Gaming-এ কেন packet retransmission-এর চেয়ে packet loss মেনে নেওয়া ভালো?
Day 6 — TLS: Handshake, Session Resumption, mTLS, Cert Chains
TLS কী সমস্যা সমাধান করে
TCP শুধু ডেটা পৌঁছে দেয় — কিন্তু কেউ মাঝপথে পড়তে পারবে (no confidentiality), বদলে দিতে পারবে (no integrity), অথবা server-কে impersonate করতে পারবে (no authentication)। TLS এই তিনটাই সমাধান করে।
TLS 1.3 Handshake (সরল করে)
Client Server
│ --- ClientHello (supported ciphers) -→ │
│ │
│ ←-- ServerHello + Certificate + key --- │
│ │
│ --- Finished (encrypted) ------------→ │
│ │
│ Application Data (encrypted) │
TLS 1.3-এ handshake 1 RTT-তে হয় (TLS 1.2-এ ছিল 2 RTT) — এটা একটা বড় উন্নতি কারণ পুরো secure connection বানাতে আগে TCP handshake (1 RTT) + TLS handshake (2 RTT) = 3 RTT লাগতো, এখন 2 RTT লাগে (TCP + TLS)।
সংখ্যায় বসাও: cross-continent (150ms one-way, তাই RTT ~300ms কখনো কখনো hop অনুযায়ী ভ্যারি করে, সরলতার জন্য ধরি RTT ~150ms):
- TCP handshake: 1 RTT
- TLS 1.3 handshake: 1 RTT
- Total: ~2 RTT = ~300ms — এটা শুধু connection বানাতেই, তারপর actual request!
Session Resumption — বারবার handshake না করা
প্রথমবার একটা client কোনো server-এর সাথে connect করলে full handshake লাগে। কিন্তু দ্বিতীয়বার connect করার সময়:
- Session Tickets / Session IDs: server আগের session-এর একটা "ticket" client-কে দিয়ে রাখে; পরের বার client সেই ticket পাঠালে server আগের negotiated key পুনরায় ব্যবহার করে — handshake কে 0-RTT বা 1-RTT-এ নামিয়ে আনে।
Practical impact: এইজন্যই CDN-এর কাছাকাছি PoP-এ (Day 9) session resumption cache রাখা হয় — একই ইউজার বারবার visit করলে handshake cost বারবার দিতে হয় না।
mTLS (Mutual TLS)
সাধারণ TLS-এ শুধু server নিজের identity প্রমাণ করে (certificate দিয়ে)। mTLS-এ client-ও নিজের certificate দিয়ে প্রমাণ করে সে কে। এটা মূলত service-to-service communication-এ ব্যবহার হয় (microservices-এর মধ্যে, service mesh-এ — Day 11-এ দেখবো), যেখানে দুই পক্ষকেই একে অপরের identity verify করতে হয়, শুধু browser-server-এর মতো এক-দিকে না।
Certificate Chain — বিশ্বাস কোথা থেকে আসে
Root CA (self-signed, browser/OS-এ pre-installed)
│
▼ signs
Intermediate CA
│
▼ signs
Leaf Certificate (example.com এর নিজের certificate)
Client leaf certificate পেলে chain ধরে ধরে root পর্যন্ত verify করে দেখে — root যদি তার trusted store-এ থাকে, পুরো chain বিশ্বাসযোগ্য।
TLS কোথায় Terminate করা উচিত (এটা ডিজাইন প্রশ্নে সরাসরি আসে)
- Load Balancer-এ terminate: LB decrypt করে backend-এ plain HTTP পাঠায় — backend সার্ভারের CPU বাঁচে, কিন্তু LB থেকে backend পর্যন্ত ট্রাফিক ভেতরের নেটওয়ার্কে unencrypted (যদি নেটওয়ার্ক trusted হয়, এটা acceptable)
- End-to-end (re-encrypt): LB decrypt করে আবার নতুন করে backend-এর সাথে TLS বানায় — বেশি secure কিন্তু বেশি CPU cost, দরকার হয় strict compliance (PCI-DSS, HIPAA) এর ক্ষেত্রে
🎯 Active Recall — Day 6
- TLS 1.3 কেন TLS 1.2-এর চেয়ে দ্রুত (RTT সংখ্যায় ব্যাখ্যা করো)?
- mTLS সাধারণ TLS থেকে আলাদা কীভাবে, এবং কোথায় এটা দরকার হয়?
- তোমার একটা payment-related সিস্টেমে (compliance দরকার) TLS termination strategy কী হবে এবং কেন?
Day 7 — HTTP/1.1 → HTTP/2 → HTTP/3
HTTP/1.1 এর সমস্যা
- প্রতিটা request-response-এর জন্য আলাদা connection (যদি keep-alive না থাকে) — অথবা keep-alive থাকলেও একটা connection-এ একবারে একটাই request (pipelining থিওরিতে আছে কিন্তু বাস্তবে ব্যবহার হয় না বাগের কারণে)
- এই সমস্যা কাটাতে browser-রা একই domain-এর সাথে 6টা পর্যন্ত parallel connection খোলে — কিন্তু প্রতিটা connection-এর নিজস্ব slow start, TLS handshake ইত্যাদি cost আছে
HTTP/2 — Multiplexing
HTTP/2 একটাই TCP connection-এর ভেতর multiple concurrent streams চালায় — মানে একই connection দিয়ে একসাথে অনেকগুলো request-response পাঠানো যায়, সিরিয়ালি না।
Head-of-Line Blocking সমস্যা (গুরুত্বপূর্ণ): যেহেতু HTTP/2 এখনো TCP-এর উপর চলে, আর TCP guarantee করে byte-এর order, তাই যদি একটা stream-এর একটা packet হারিয়ে যায়, TCP পুরো connection-কে (সব stream-সহ) থামিয়ে দেয় সেই packet retransmit না হওয়া পর্যন্ত — এমনকি অন্য stream-এর ডেটা প্রস্তুত থাকলেও। এটাকে বলে TCP-level HOL blocking, এবং এটাই HTTP/3-এর জন্মের মূল কারণ।
HTTP/3 — QUIC-এর উপর HTTP
HTTP/3 আসলে HTTP/2-এর মতোই multiplexing ধারণা, কিন্তু TCP-এর বদলে QUIC (Day 5) এর উপর চলে। যেহেতু QUIC-এ প্রতিটা stream independent, একটা stream-এর packet loss অন্য stream-কে block করে না — true HOL-blocking-free multiplexing।
সারাংশ টেবিল (ইন্টারভিউতে দ্রুত আঁকার মতো)
| ফিচার | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| Transport | TCP | TCP | QUIC (UDP-ভিত্তিক) |
| Multiplexing | নেই | আছে (stream-ভিত্তিক) | আছে |
| HOL Blocking | আছে (application level) | আছে (TCP level) | নেই |
| Handshake RTT | TCP+TLS আলাদা | TCP+TLS আলাদা | Combined, প্রায় 0-RTT (repeat) |
| Header Compression | নেই | HPACK | QPACK |
🎯 Active Recall — Day 7
- HTTP/2 multiplexing করলেও কেন এখনো head-of-line blocking সমস্যা থেকে যায়?
- HTTP/3 কীভাবে এই সমস্যা সমাধান করে (Day 5-এর QUIC জ্ঞান কাজে লাগাও)?
- যদি কোনো নেটওয়ার্কে packet loss rate বেশি হয় (যেমন খারাপ mobile connection), HTTP/2 আর HTTP/3-এর মধ্যে perceptible difference কেমন হবে?
Day 8 — DNS Deep Dive: Resolution, TTL, Anycast, GeoDNS
DNS Resolution — ধাপে ধাপে (একটা cold lookup)
Browser → OS resolver cache (miss)
→ ISP Resolver (Recursive Resolver)
→ Root Nameserver (".com কোথায়?")
→ TLD Nameserver ("example.com কোথায়?")
→ Authoritative Nameserver ("example.com = 93.184.x.x")
← IP address ফিরে আসে
প্রতিটা hop-এ latency যোগ হয় — এইজন্য caching এত গুরুত্বপূর্ণ প্রতিটা লেভেলে (browser, OS, ISP resolver)।
TTL (Time To Live) — Caching vs Freshness Tradeoff
DNS record-এর সাথে একটা TTL থাকে (যেমন 300 সেকেন্ড) — মানে resolver এই record 300 সেকেন্ড cache-এ রাখবে, তারপর আবার query করবে।
Tradeoff:
- কম TTL (যেমন 30s) → দ্রুত পরিবর্তন propagate হয় (failover-এর জন্য ভালো), কিন্তু বেশি DNS query = বেশি load, সামান্য বেশি latency
- বেশি TTL (যেমন 24h) → কম load, দ্রুত response, কিন্তু কোনো সমস্যা হলে (server down) client অনেকক্ষণ পুরনো (মৃত) IP-তে যেতেই থাকবে
Practical pattern: DR/failover-প্রবণ record-এ TTL কম রাখা হয় (৩০-৬০ সেকেন্ড), স্ট্যাটিক record-এ (যেমন MX record) বেশি।
DNS দিয়ে Failover — এবং এর সীমাবদ্ধতা
DNS-based failover মানে: primary region down হলে DNS record আপডেট করে traffic secondary region-এ পাঠানো।
সীমাবদ্ধতা যেটা ইন্টারভিউয়ে বলা দরকার:
- TTL respect না করা clients: অনেক resolver/client TTL ignore করে বেশিক্ষণ cache রাখে — তাই failover ধীরে ছড়ায় (কখনো কখনো ঘণ্টার মধ্যে সম্পূর্ণ propagate না-ও হতে পারে)
- এটা instant না — তাই critical failover-এ শুধু DNS-এর ওপর ভরসা না করে Anycast (নিচে) বা Load Balancer-level failover বেশি নির্ভরযোগ্য
Anycast — একই IP, একাধিক লোকেশন
Anycast-এ একই IP address একাধিক physical location থেকে announce করা হয় (BGP routing দিয়ে)। User-এর request automatically নেটওয়ার্ক-লেভেলে সবচেয়ে কাছের (routing-এর দিক থেকে) লোকেশনে চলে যায় — কোনো DNS পরিবর্তনের দরকার নেই।
উদাহরণ: Cloudflare/Google-এর DNS (1.1.1.1, 8.8.8.8) Anycast — সারা পৃথিবীতে একই IP, কিন্তু প্রতিটা user routing-এর মাধ্যমে কাছেরটাতেই পৌঁছায়।
Anycast vs DNS-based GeoDNS — পার্থক্য বোঝা জরুরি:
- Anycast: routing-level, instant failover (BGP route withdraw করলেই traffic অন্য লোকেশনে চলে যায়) — কিন্তু granular control কম (TCP connection মাঝপথে অন্য সার্ভারে চলে যেতে পারে যদি BGP route বদলায়, causing connection reset)
- GeoDNS: DNS resolver-কে user-এর location অনুযায়ী আলাদা আলাদা IP রিটার্ন করা (যেমন Asia থেকে query করলে Singapore-এর IP, Europe থেকে করলে Frankfurt-এর IP) — TTL-এর কারণে propagation স্লো, কিন্তু granular এবং predictable
🎯 Active Recall — Day 8
- TTL কম রাখলে আর বেশি রাখলে কী কী tradeoff হয় — একটা real scenario দিয়ে ব্যাখ্যা করো।
- DNS-based failover-এর প্রধান সীমাবদ্ধতা কী, এবং Anycast কীভাবে এটা এড়ায়?
- GeoDNS আর Anycast — কোনটা তুমি ব্যবহার করবে যদি তোমার প্রয়োজন হয় (a) দ্রুততম failover, (b) খুব নির্দিষ্ট region-ভিত্তিক routing control?
Day 9 — CDN Architecture: PoPs, Origin Shield, Cache Keys
CDN-এর মূল ধারণা
CDN (Content Delivery Network) মানে content-এর copy world-এর বিভিন্ন জায়গায় (PoP — Point of Presence) রেখে দেওয়া, যাতে user-এর কাছের PoP থেকেই serve করা যায় — Day 1-এর latency numbers মনে করো: cross-continent round trip ~150ms vs local PoP round trip ~5-20ms।
User (Dhaka) → CDN PoP (Singapore/Mumbai) → [cache hit? সরাসরি রিটার্ন]
│
│ [cache miss হলে]
▼
Origin Shield (একটা মধ্যবর্তী cache layer)
│
│ [এখানেও miss হলে]
▼
Origin Server (আসল সার্ভার)
Origin Shield — কেন এটা দরকার
ধরো তোমার ১০০টা PoP আছে world-জুড়ে। যদি একটা popular content-এর cache expire হয়ে যায়, ১০০টা PoP-ই একসাথে origin server-এ request পাঠাবে — এটাকে বলে "thundering herd on origin"।
সমাধান: Origin Shield হলো একটা একক intermediate caching layer, যেটা সব PoP-এর request প্রথমে receive করে। এটা নিজে একবার origin থেকে ডেটা আনে, তারপর সব PoP-কে serve করে — origin server-এ শুধু 1টা request যায়, ১০০টা না।
তোমার Redis/ES experience-এর সাথে analogy: এটা অনেকটা একটা centralized cache layer-এর মতো যেটা "cache stampede" প্রতিরোধ করে (Day 18-তে আমরা এই stampede প্যাটার্ন আরও গভীরে দেখবো)।
Cache Key Design — এটা যেখানে বাগ হয় সবচেয়ে বেশি
CDN কীভাবে বোঝে দুইটা request একই content চাচ্ছে? Cache Key দিয়ে — সাধারণত URL + কিছু নির্দিষ্ট header/query param এর combination।
সাধারণ ভুল এবং সমস্যা:
- যদি cache key-তে অপ্রয়োজনীয় query parameter (যেমন
?utm_source=facebook) অন্তর্ভুক্ত থাকে, একই কনটেন্ট বিভিন্ন URL-এর জন্য আলাদা cache entry তৈরি হবে → cache hit ratio কমে যায় (একে "cache fragmentation" বলা যায়) - যদি cache key-তে প্রয়োজনীয় parameter বাদ পড়ে (যেমন
Accept-Languageheader, যেটা content আলাদা করে), ভুল ইউজারকে ভুল ভাষার cached content দেখানো হতে পারে
Design rule: cache key-তে শুধুমাত্র সেই dimension-গুলো রাখো যেগুলো actual response content বদলায়।
Invalidation Strategies — "Cache invalidation is one of the two hard problems"
- TTL-based expiry: সহজ, কিন্তু stale content কিছুক্ষণ থেকে যেতে পারে
- Purge/Invalidation API: content আপডেট হলে সরাসরি CDN-কে বলে দাও "এই key-টা invalidate করো" — real-time কিন্তু বেশি ব্যবহার করলে (যেমন প্রতি সেকেন্ডে) CDN-এর ওপর চাপ বাড়ায়
- Versioned URLs (cache-busting):
style.css?v=2বাstyle.a1b2c3.css(content hash) — নতুন version মানেই নতুন URL, তাই invalidation-এর দরকারই নেই, পুরনো URL আলাদা cache entry হিসেবে থেকে যায় এবং naturally TTL অনুযায়ী expire হয়
Production-grade approach: static assets (JS/CSS/images) → versioned URL + দীর্ঘ TTL (immutable); dynamic/frequently-changing content → ছোট TTL + purge API।
🎯 Active Recall — Day 9
- Origin Shield ছাড়া তোমার ১০০-PoP CDN-এ একটা viral content-এর cache expire হলে origin server-এ কী হবে? Origin Shield এটা কীভাবে ঠেকায়?
- Cache key-তে ভুল parameter থাকলে দুই ধরনের সমস্যা হতে পারে — কী কী, উদাহরণ দিয়ে ব্যাখ্যা করো।
- Versioned URL approach কেন invalidation সমস্যাটাকেই "avoid" করে ফেলে, বরং সমাধান করার চেষ্টা করে না?
Day 10 — Load Balancing: L4 vs L7, Algorithms, Health Checks
L4 vs L7 Load Balancing — মূল পার্থক্য
L4 (Transport Layer) Load Balancing:
- শুধু IP address আর port দেখে route করে (TCP/UDP লেভেলে)
- Packet-এর ভেতরের content (HTTP header, URL path) দেখে না
- অত্যন্ত দ্রুত (কম CPU/processing লাগে, কারণ deep inspection নেই)
- উদাহরণ: AWS NLB, IPVS
L7 (Application Layer) Load Balancing:
- HTTP request-এর ভেতর দেখে (URL path, header, cookie) route করে — যেমন
/api/usersএকটা service-এ,/api/ordersআরেকটা service-এ পাঠাতে পারে - SSL termination, content-based routing, request rewriting করতে পারে
- একটু বেশি latency/CPU cost (কারণ পুরো HTTP request parse করতে হয়)
- উদাহরণ: NGINX, Envoy, AWS ALB
ডিসিশন রুল: যদি শুধু raw throughput আর simple routing দরকার (যেমন একটা database cluster-এর সামনে) → L4। যদি smart routing দরকার (microservices, path-based routing, A/B testing) → L7।
Load Balancing Algorithms
| Algorithm | কীভাবে কাজ করে | কখন ভালো |
|---|---|---|
| Round Robin | পালাক্রমে প্রতিটা সার্ভারে পাঠায় | সব সার্ভার সমান ক্ষমতার হলে |
| Weighted Round Robin | শক্তিশালী সার্ভারে বেশি request | Heterogeneous hardware |
| Least Connections | যে সার্ভারে এখন সবচেয়ে কম active connection সেখানে পাঠায় | Request-এর duration ভ্যারি করলে (কিছু request দ্রুত, কিছু ধীর) |
| Least Response Time | কম latency + কম connection যেখানে | Latency-sensitive system |
| IP Hash / Consistent Hashing | client IP বা key hash করে নির্দিষ্ট সার্ভারে পাঠায় | Session affinity বা cache locality দরকার হলে |
Consistent Hashing Load Balancer — এটা গভীরে বোঝা দরকার (Day 10-এর deliverable)
সাধারণ hash-based routing-এ (server = hash(key) % N) সমস্যা হলো: যদি একটা সার্ভার যোগ/বিয়োগ হয় (N বদলায়), প্রায় সব key নতুন সার্ভারে চলে যায় — massive cache miss বা session loss।
Consistent Hashing সমাধান: সার্ভার আর key দুটোকেই একটা "hash ring"-এ বসানো হয়। প্রতিটা key তার clockwise দিকে সবচেয়ে কাছের সার্ভারে যায়। একটা সার্ভার যোগ/বিয়োগ হলে, শুধু তার আশেপাশের অংশের key-গুলো পুনর্বিন্যাস হয় — বাকি সব ঠিক থাকে।
Server A
/ \
Key3--• •--Server B
\ /
Server C--Key1, Key2
তোমার Redis Cluster experience-এর সাথে সরাসরি সম্পর্ক: Redis Cluster ঠিক এই কনসেপ্ট ব্যবহার করে (hash slots, যা consistent hashing-এর একটা variant) — এটা তোমার existing জ্ঞানের সাথে সরাসরি যুক্ত করে ব্যাখ্যা করলে ইন্টারভিউয়ারের কাছে ভালো লাগবে।
Virtual Nodes: বাস্তবে প্রতিটা physical সার্ভারকে ring-এ একাধিক virtual point হিসেবে বসানো হয় (যেমন 100-200টা), যাতে load evenly distribute হয় (নাহলে হঠাৎ একটা বড় "gap" তৈরি হয়ে একটা সার্ভারে বেশি load পড়ে যেতে পারে)।
Health Checks — কীভাবে LB জানে কোন সার্ভার "বেঁচে আছে"
- Active health check: LB নিজে periodically (যেমন প্রতি 5 সেকেন্ডে) একটা
/healthendpoint-এ request পাঠায়। Consecutive failures (যেমন 3বার) হলে সার্ভারকে "unhealthy" মার্ক করে rotation থেকে বাদ দেয়। - Passive health check: actual traffic-এর response monitor করে — যদি একটা সার্ভার থেকে বেশি error/timeout আসতে থাকে, তাকে সাময়িকভাবে বাদ দেয়।
Tradeoff: খুব aggressive health check (কম threshold, কম interval) → দ্রুত bad সার্ভার সরায়, কিন্তু temporary blip-এও unnecessary সার্ভার বাদ পড়তে পারে ("flapping")। খুব lenient → সত্যিকারের bad সার্ভারে ট্রাফিক যেতেই থাকে।
🎯 Active Recall — Day 10 (Deliverable: Consistent Hashing LB ডিজাইন)
- L4 আর L7 load balancer-এর মধ্যে পার্থক্য — একটা microservices architecture-এ কোথায় কোনটা ব্যবহার করবে?
- Simple modulo hashing (
hash % N) এর সমস্যাটা ঠিক কী, এবং consistent hashing কীভাবে এটা সমাধান করে? - Virtual nodes কেন দরকার — এগুলো ছাড়া কী সমস্যা হতে পারে?
- একটা 5-সার্ভার Redis-backed caching layer-এর জন্য consistent hashing ভিত্তিক load balancer ডিজাইন করো (হাতে এঁকে) — সার্ভার যোগ হলে কী ঘটে সেটাও দেখাও।
Day 11 — Reverse Proxies, API Gateways, Service Mesh Basics
Reverse Proxy কী, এবং Forward Proxy থেকে কীভাবে আলাদা
- Forward Proxy: client-এর পক্ষে কাজ করে — client-এর identity server থেকে লুকায় (VPN-এর মতো ধারণা)
- Reverse Proxy: server-এর পক্ষে কাজ করে — client জানেই না আসল backend সার্ভার কোনটা; সব request প্রথমে proxy-তে আসে, তারপর সঠিক backend-এ যায়
Reverse proxy (NGINX, HAProxy) সাধারণত করে: load balancing, SSL termination, caching, compression, request routing।
API Gateway — Reverse Proxy-র উপরে আরও এক ধাপ
API Gateway মূলত একটা L7 reverse proxy, কিন্তু API-নির্দিষ্ট বাড়তি ফিচার যোগ করে:
- Authentication/Authorization (একটা centralized জায়গায়, প্রতিটা microservice-এ আলাদা করে implement করার দরকার নেই)
- Rate limiting (per-client, per-API-key)
- Request/response transformation (protocol translation, যেমন client থেকে REST আসলে internal gRPC-তে রূপান্তর)
- API composition (একাধিক backend service-এর response একত্র করে একটা response তৈরি করা — এটা "Backend for Frontend" প্যাটার্নেরও ভিত্তি)
মূল পার্থক্য মনে রাখার সহজ উপায়: Reverse proxy = infrastructure-level concern (routing, SSL)। API Gateway = application-level concern (auth, rate limit, API-specific logic)।
Service Mesh — Microservice-এর ভেতরের communication সমাধান
যখন তোমার ১০-২০টা microservice একে অপরের সাথে কথা বলে (north-south না, east-west ট্রাফিক), তখন প্রতিটা service-এ আলাদা করে retry logic, circuit breaker, mTLS, tracing implement করা কঠিন এবং duplicate কাজ।
Sidecar Model (Envoy-র মূল ধারণা):
┌─────────────────────────┐ ┌─────────────────────────┐
│ Service A │ │ Service B │
│ ┌─────────┐ ┌────────┐ │ │ ┌────────┐ ┌─────────┐ │
│ │ App │←→│ Envoy │←┼──────┼→│ Envoy │←→│ App │ │
│ │ Code │ │(sidecar)│ │ │ │(sidecar)│ │ Code │ │
│ └─────────┘ └────────┘ │ │ └────────┘ └─────────┘ │
└─────────────────────────┘ └─────────────────────────┘
প্রতিটা service-এর সাথে একটা "sidecar" proxy (Envoy) চলে, যেটা সেই service-এর সব ইনকামিং/আউটগোয়িং ট্রাফিক intercept করে। Application code জানেই না এই proxy আছে — সে শুধু localhost-এ কথা বলে।
Sidecar কী কী কাজ করে:
- mTLS (automatic, application code পরিবর্তন ছাড়াই)
- Retry, timeout, circuit breaking
- Load balancing (client-side)
- Observability (metrics, tracing) — automatically, প্রতিটা service আলাদা করে instrument না করেই
Control Plane vs Data Plane:
- Data Plane = সব sidecar proxy গুলো (actual ট্রাফিক handle করে) — Envoy
- Control Plane = কেন্দ্রীয় configuration manager, যেটা সব sidecar-কে বলে দেয় কী policy apply করতে হবে (routing rule, security policy) — Istio, Linkerd
কখন Service Mesh "Overkill" (Day 158-তেও এটা আবার আসবে)
Service mesh যোগ করে অতিরিক্ত network hop (app → sidecar → network → sidecar → app), অতিরিক্ত operational complexity (আরেকটা সিস্টেম চালাতে হবে), learning curve। ৫-১০টার কম microservice, বা simple architecture-এ এটা প্রায়ই অপ্রয়োজনীয় জটিলতা যোগ করে — সরাসরি library-level solution (retry logic in code, বা lightweight API gateway) যথেষ্ট হতে পারে।
🎯 Active Recall — Day 11 (Branch শেষের consolidation)
- Reverse proxy আর API gateway-র মধ্যে ঠিক পার্থক্যটা কী — একটা বাক্যে বলো।
- Sidecar model-এ application code service mesh সম্পর্কে জানে না কেন এটা এত powerful ডিজাইন প্যাটার্ন?
- একটা ৩-সার্ভিস architecture-এ কি তুমি service mesh বসাবে? কেন বা কেন না?
পুরো Branch 1.2 Consolidation প্রশ্ন: একটা user Dhaka থেকে একটা US-based e-commerce সাইটে গিয়ে একটা প্রোডাক্ট পেজ লোড করছে। DNS resolution থেকে শুরু করে HTML response পাওয়া পর্যন্ত — প্রতিটা স্তর (DNS → TCP → TLS → CDN → LB → API Gateway → backend) দিয়ে request-টা কীভাবে যাবে, প্রতিটা ধাপে আনুমানিক কত latency যোগ হবে, সেটা ছবি এঁকে ব্যাখ্যা করো।
পরবর্তী ধাপ: এই consolidation exercise-টা করে আমাকে দেখাও (লিখে/এঁকে বর্ণনা করে) — আমি রিভিউ করবো, তারপর Day 12 (REST API Design) থেকে Branch 1.3-এ যাবো।
Day 4 · TCP internals: handshake, congestion control, Nagle
পার্ট ০ — শুরু করার আগে, TCP আসলে কী সমস্যা সমাধান করে
Internet-এর নিচের লেয়ার (IP) একটা জিনিস guarantee করে না: reliability। IP প্যাকেট হারিয়ে যেতে পারে, ভুল order-এ পৌঁছাতে পারে, ডুপ্লিকেট হতে পারে। IP শুধু "best effort delivery" দেয় — পৌঁছাতেও পারে, নাও পারে।
TCP (Transmission Control Protocol) এই কাঁচা, অনির্ভরযোগ্য IP-এর উপর একটা layer বসায় যেটা নিশ্চিত করে:
- Reliable delivery — ডেটা হারালে আবার পাঠানো হবে (retransmission)
- Ordered delivery — ডেটা যে order-এ পাঠানো হয়েছিল, সেই order-এই receiver-এ পৌঁছাবে
- No duplication — একই ডেটা দুইবার application-এ যাবে না
- Flow control — receiver যতটা সামলাতে পারে, sender ততটাই পাঠাবে (receiver-কে overwhelm করবে না)
- Congestion control — নেটওয়ার্ক যতটা সামলাতে পারে, sender ততটাই পাঠাবে (নেটওয়ার্ককে overwhelm করবে না)
এই পাঁচটা জিনিস মনে রাখো — আজকের পুরো আলোচনা এই পাঁচটার মধ্যেই ঘোরাফেরা করবে। প্রথম তিনটা "correctness" নিয়ে, শেষ দুইটা "performance/fairness" নিয়ে।
একটা analogy দিয়ে শুরু করি
ধরো তুমি একজনকে ১০০ পাতার একটা বই ডাক দিয়ে পাঠাচ্ছো, কিন্তু ডাকব্যবস্থা এমন যে প্রতিটা পাতা আলাদা খামে যাবে, এবং যেকোনো খাম হারিয়ে যেতে পারে বা উল্টাপাল্টা ক্রমে পৌঁছাতে পারে।
TCP হলো সেই সিস্টেম যেটা:
- প্রতিটা পাতায় নম্বর বসায় (sequence number)
- প্রাপক প্রতিটা পাতা পাওয়ার পর "পেয়েছি" বলে জানায় (ACK)
- নম্বর দেখে পাতাগুলো সঠিক ক্রমে সাজায়
- কোনো পাতা না পৌঁছালে আবার পাঠানোর অনুরোধ করে
- প্রাপকের হাতে কতগুলো পাতা "পড়ার অপেক্ষায়" জমে আছে সেটা দেখে sender-কে গতি কমাতে/বাড়াতে বলে
পার্ট ১ — TCP Segment-এর গঠন (যা সবকিছুর ভিত্তি)
TCP header-এর কিছু ফিল্ড না বুঝলে handshake আর congestion control বোঝা কঠিন হবে। মূল ফিল্ডগুলো:
| ফিল্ড | কাজ |
|---|---|
| Source/Destination Port | কোন application থেকে কোন application-এ |
| Sequence Number | এই segment-এর প্রথম বাইটটা স্ট্রিমের কততম বাইট |
| Acknowledgment Number | পরবর্তী কোন বাইট আশা করা হচ্ছে (মানে এই নম্বরের আগে পর্যন্ত সব পাওয়া গেছে) |
| Flags (SYN, ACK, FIN, RST...) | কানেকশনের অবস্থা বোঝায় |
| Window Size | receiver এখন কত বাইট গ্রহণ করতে প্রস্তুত (flow control) |
| Checksum | ডেটা করাপ্ট হয়নি তা যাচাই |
গুরুত্বপূর্ণ ধারণা: TCP বাইট-স্ট্রিম প্রোটোকল, প্যাকেট-ভিত্তিক না। মানে TCP "মেসেজ ১, মেসেজ ২" পাঠায় না — এটা একটা অবিচ্ছিন্ন বাইটের স্রোত পাঠায়, যেটা মাঝপথে যেকোনোভাবে ভাগ (segment) হয়ে যেতে পারে। এই কারণেই sequence number "বাইট নম্বর" ধরে রাখে, "প্যাকেট নম্বর" না।
পার্ট ২ — 3-Way Handshake (গভীরে)
ধাপে ধাপে, প্রতিটা ফিল্ডসহ
Client (ISN_c = 1000) Server (ISN_s = 5000)
│ │
│ SYN, seq=1000 │
│ ────────────────────────────────────────→│ [State: SYN_SENT]
│ │
│ SYN-ACK, seq=5000, ack=1001 │
│←──────────────────────────────────────── │ [State: SYN_RCVD]
│ │
│ ACK, seq=1001, ack=5001 │
│ ────────────────────────────────────────→│ [State: ESTABLISHED]
│ │
[State: ESTABLISHED]
ISN (Initial Sequence Number) — প্রতিটা পক্ষ নিজের একটা random starting number বেছে নেয় (নিরাপত্তার কারণে — predictable ISN হলে TCP session hijacking সহজ হয়ে যায়, তাই আধুনিক OS cryptographically random ISN জেনারেট করে)।
লক্ষ্য করো: SYN আর ACK দুটোই ১টা করে "virtual byte" খরচ করে sequence number-এ, যদিও এতে কোনো actual data নেই — এইজন্যই ACK নম্বর 1001 (1000+1), 5001 (5000+1) হয়েছে, 1000 বা 5000 না।
এই handshake-এর মূল্য কত সময়?
এই তিনটা ধাপ পুরো complete হতে 1 RTT সময় লাগে (SYN client থেকে server, SYN-ACK ফিরে আসা পর্যন্ত ১ RTT; তৃতীয় ACK-এ কোনো wait নেই কারণ client সাথে সাথেই ডেটা পাঠাতে পারে)।
সংখ্যায় দেখি:
| দুই পক্ষের দূরত্ব | RTT | Handshake সময় |
|---|---|---|
| একই ডেটাসেন্টার | ~0.5 ms | ~0.5 ms |
| একই শহর, ভিন্ন ISP | ~5-10 ms | ~5-10 ms |
| একই দেশ, ভিন্ন শহর (ঢাকা-চট্টগ্রাম) | ~10-20 ms | ~10-20 ms |
| Cross-continent (ঢাকা-নিউইয়র্ক) | ~200-250 ms | ~200-250 ms |
Practical Impact: একজন ব্যবহারকারী ঢাকা থেকে একটা US-hosted সার্ভারে request পাঠালে, কোনো actual ডেটা যাওয়ার আগেই ~200ms খরচ হয়ে যায় শুধু handshake-এ। যদি TLS-ও থাকে (Day 6), আরও একটা RTT যোগ হয় — তাই CDN/edge location এত গুরুত্বপূর্ণ, কারণ এটা এই handshake-কেই ব্যবহারকারীর কাছাকাছি নিয়ে আসে।
4-Way Termination — Connection বন্ধ করা (Handshake-এর মতোই গুরুত্বপূর্ণ কিন্তু প্রায়ই ভুলে যাওয়া হয়)
Client Server
│ ---------- FIN ------------------→ │ [Client: FIN_WAIT_1]
│ ←--------- ACK ------------------- │ [Server: CLOSE_WAIT]
│ │ [Client: FIN_WAIT_2]
│ ←--------- FIN ------------------- │ [Server: LAST_ACK]
│ ---------- ACK -------------------→ │
│ [Client: TIME_WAIT, তারপর CLOSED] │ [Server: CLOSED]
কেন 4-way (3-way না)? কারণ TCP connection full-duplex — দুই দিকেই ডেটা flow করে। যখন client বলে "আমার পাঠানো শেষ" (FIN), তখনও server-এর হয়তো client-কে কিছু পাঠানো বাকি থাকতে পারে — তাই server নিজের FIN আলাদাভাবে পাঠায়, যখন তার নিজের পাঠানো শেষ হয়।
TIME_WAIT State — একটা প্র্যাকটিক্যাল সমস্যা যেটা Production-এ আঘাত করে:
Client শেষ ACK পাঠানোর পর সাথে সাথে connection বন্ধ করে না — একটা নির্দিষ্ট সময় (সাধারণত 2×MSL, ৬০-১২০ সেকেন্ড) TIME_WAIT state-এ থাকে, যাতে delayed/duplicate প্যাকেট এলে সঠিকভাবে handle করা যায় এবং একই port pair দিয়ে নতুন connection শুরু হলে পুরনো connection-এর delayed প্যাকেট নতুন connection-এ ঢুকে না পড়ে।
এটা কেন গুরুত্বপূর্ণ: হাই-ট্রাফিক সার্ভারে (যেমন একটা load balancer যেটা প্রচুর short-lived connection বানায়) TIME_WAIT অবস্থায় হাজার হাজার connection জমে যেতে পারে, যা ephemeral port exhaustion ঘটাতে পারে (একটা মেশিনে সাধারণত ~28,000-64,000 ephemeral port থাকে)। এইজন্যই connection pooling / keep-alive এত জরুরি — নতুন connection বারবার না বানিয়ে reuse করলে এই সমস্যা এড়ানো যায়।
পার্ট ৩ — কেন Connection Reuse এত গুরুত্বপূর্ণ (Cost Breakdown)
প্রতিটা নতুন TCP connection-এর "hidden cost":
- 1 RTT — 3-way handshake
- CPU/Memory — সার্ভারে প্রতিটা connection-এর জন্য socket, buffer বরাদ্দ
- Slow Start থেকে আবার শুরু (পার্ট ৪-এ বিস্তারিত) — মানে নতুন connection প্রথমে ধীরগতিতে চলে, পূর্ণ speed পেতে সময় লাগে
- TLS থাকলে আরও 1 RTT (Day 6)
উদাহরণ দিয়ে বুঝি: ধরো একটা ওয়েবপেজে ৫০টা ছোট resource (image, JS, CSS ফাইল) আছে।
- প্রতিটার জন্য নতুন TCP connection: ৫০ × (handshake + slow start ramp-up) = ভয়ংকর ধীর, বিশেষ করে high-latency নেটওয়ার্কে
- HTTP Keep-Alive + একটা persistent connection reuse: শুধু ১বার handshake, তারপর connection warm থাকে, বাকি ৪৯টা resource সরাসরি সেই established, already-ramped-up connection দিয়ে যায়
এইজন্যই তোমার PgBouncer experience-টা এখানে সরাসরি প্রাসঙ্গিক: PgBouncer ঠিক এই একই সমস্যা সমাধান করে database লেয়ারে — প্রতিটা query-র জন্য নতুন Postgres connection বানানো ব্যয়বহুল (connection setup + authentication + Postgres-এর নিজস্ব process spawn করা), তাই connection pool করে রাখা হয়। TCP connection reuse (HTTP keep-alive, gRPC persistent connection) আর DB connection pooling — একই মূল নীতি, ভিন্ন লেয়ারে প্রয়োগ।
পার্ট ৪ — Congestion Control (সবচেয়ে গুরুত্বপূর্ণ অংশ, খুব গভীরে যাবো)
মূল সমস্যা: Sender জানে না নেটওয়ার্কের capacity কত
Sender-এর কাছে দুইটা তথ্য দরকার প্রতি মুহূর্তে সে কত ডেটা পাঠাতে পারবে সেটা ঠিক করতে:
- Receiver কত নিতে পারবে — এটা rwnd (receive window), receiver TCP header-এ জানিয়ে দেয় (flow control)
- নেটওয়ার্ক কত সামলাতে পারবে — এটা কেউ সরাসরি জানায় না, sender-কে অনুমান করতে হয় — এটাই cwnd (congestion window)
Sender যেই amount ডেটা পাঠাতে পারবে তা হলো: min(cwnd, rwnd) — দুটোর মধ্যে যেটা ছোট।
ধাপ ১: Slow Start
Connection নতুন হলে (বা packet loss-এর পর restart হলে), sender জানে না নেটওয়ার্ক কতটা সামলাতে পারবে — তাই সতর্কভাবে ছোট থেকে শুরু করে।
- শুরুর cwnd সাধারণত 10 MSS (Maximum Segment Size, প্রায় 10 × 1460 bytes ≈ 14.6 KB) — RFC 6928 অনুযায়ী আধুনিক TCP-তে (আগে এটা ছিল মাত্র 1-4 MSS)
- প্রতিটা RTT-তে, প্রতিটা ACK পাওয়ার সাথে সাথে cwnd 1 MSS করে বাড়ে — এর ফলে প্রতি RTT-তে cwnd দ্বিগুণ হয়ে যায় (exponential growth)
সংখ্যায় দেখি (উদাহরণ, MSS = 1460 bytes):
| RTT নম্বর | cwnd (MSS-এ) | cwnd (bytes-এ, approx) |
|---|---|---|
| শুরুতে | 10 | ~14.6 KB |
| RTT 1 পরে | 20 | ~29 KB |
| RTT 2 পরে | 40 | ~58 KB |
| RTT 3 পরে | 80 | ~117 KB |
| RTT 4 পরে | 160 | ~234 KB |
এখানে একটা গুরুত্বপূর্ণ practical ইনসাইট: যদি RTT = 150ms (cross-continent) হয়, পুরোপুরি "warm up" হয়ে বড় cwnd-তে পৌঁছাতে কয়েকশ মিলিসেকেন্ড থেকে কয়েক সেকেন্ড সময় লাগতে পারে। এইজন্য ছোট ফাইল ট্রান্সফার (যেমন একটা ৫০ KB API response) প্রায়ই কখনোই slow start থেকে বের হয় না — পুরো transfer slow-start phase-এর মধ্যেই শেষ হয়ে যায়। এটাই একটা কারণ কেন high-latency নেটওয়ার্কে ছোট response-ও আশানুরূপ দ্রুত আসে না।
ধাপ ২: Congestion Avoidance (Slow Start Threshold পার হওয়ার পর)
একটা ssthresh (slow start threshold) ভ্যালু থাকে। cwnd যখন ssthresh অতিক্রম করে (বা loss হওয়ার পর নতুন করে সেট হয়), sender exponential growth ছেড়ে linear growth-এ চলে যায়:
- Slow Start: প্রতি RTT-তে cwnd দ্বিগুণ
- Congestion Avoidance: প্রতি RTT-তে cwnd +1 MSS মাত্র (additive increase)
এই "ধীরে ধীরে বাড়ানো, কিন্তু loss হলে দ্রুত কমানো" নীতিকে বলা হয় AIMD (Additive Increase, Multiplicative Decrease) — এটা TCP-এর fairness এবং stability-এর মূল ভিত্তি।
ধাপ ৩: Packet Loss হলে কী হয় — এখানেই Algorithm-গুলোর পার্থক্য শুরু
Loss Detection দুই ধরনের হতে পারে:
Timeout (RTO — Retransmission Timeout): কোনো ACK-ই আসেনি একটা নির্দিষ্ট সময়ের মধ্যে — এটা মারাত্মক সংকেত (severe congestion বা connection সমস্যা)
- প্রতিক্রিয়া: cwnd পুরোপুরি 1 MSS-এ রিসেট হয়ে যায়, ssthresh = cwnd/2 সেট হয়, আবার Slow Start থেকে শুরু হয়
3 Duplicate ACKs (Fast Retransmit): receiver একই ACK number বারবার পাঠাচ্ছে (মানে একটা নির্দিষ্ট segment miss করেছে কিন্তু তারপরের কিছু segment পেয়েছে) — এটা কম severe, কারণ নেটওয়ার্ক এখনও ডেটা পাস করছে
- প্রতিক্রিয়া (Fast Retransmit + Fast Recovery): হারানো segment সাথে সাথে retransmit করা হয়, cwnd অর্ধেক করা হয় (পুরো 1-এ না নেমে), ssthresh = cwnd/2
এই দুটোর পার্থক্য বোঝা ইন্টারভিউতে গুরুত্বপূর্ণ: Timeout মানে "catastrophic", drastic reset দরকার। Duplicate ACK মানে "কিছু packet হারিয়েছে কিন্তু pipe এখনও চলছে", তাই হালকা প্রতিক্রিয়া যথেষ্ট।
Congestion Control Algorithm-গুলোর তুলনা (আধুনিক আলোচনায় এটা প্রায়ই জিজ্ঞেস করা হয়)
| Algorithm | মূল ধারণা | ব্যবহার |
|---|---|---|
| TCP Reno | ক্লাসিক AIMD, loss-based | পুরনো standard, এখন কম ব্যবহৃত |
| TCP CUBIC | loss-based কিন্তু cubic function দিয়ে growth (Reno-র চেয়ে উচ্চ-bandwidth নেটওয়ার্কে বেশি aggressive এবং দ্রুত recover করে) | Linux-এর ডিফল্ট (বহু বছর ধরে) |
| BBR (Bottleneck Bandwidth and RTT) | Loss-based না, বরং bandwidth আর RTT সরাসরি পরিমাপ করে optimal sending rate বের করে | Google ব্যবহার করে (YouTube ইত্যাদি), lossy নেটওয়ার্কে (WiFi, mobile) ভালো পারফর্ম করে কারণ এটা packet loss-কে "congestion signal" হিসেবে ভুল বোঝে না |
কেন BBR গুরুত্বপূর্ণ ইন্টারভিউতে বলার মতো পয়েন্ট: Loss-based algorithm (Reno, CUBIC) ধরে নেয় "packet loss = congestion", কিন্তু WiFi/mobile নেটওয়ার্কে packet loss প্রায়ই congestion ছাড়াই ঘটে (signal interference, ইত্যাদি কারণে)। এই ভুল ধারণায় TCP অকারণে cwnd কমিয়ে ফেলে, throughput কমে যায়। BBR সরাসরি bandwidth-delay product measure করে এই সমস্যা এড়ায়।
একটা সম্পূর্ণ Timeline উদাহরণ (সব ধাপ একসাথে)
cwnd
│
│ ╱╲ (loss detected - duplicate ACK)
│ ╱‾‾╱ ╲
│ ╱‾‾╱ ╲___
│ ╱‾‾╱ ╲___(linear growth restarts,
│ ╱‾‾╱ Congestion Avoidance congestion avoidance)
│ ╱‾‾╱ (linear +1 MSS/RTT)
│ ╱‾‾╱
│ ╱‾‾╱ Slow Start (exponential ×2/RTT)
│╱‾
└──────────────────────────────────────────────→ সময় (RTT)
ssthresh এখানে
🎯 এই পার্টের Active Recall
- Slow Start-এ cwnd প্রতি RTT-তে কীভাবে বাড়ে, আর Congestion Avoidance-এ কীভাবে বাড়ে — পার্থক্য ব্যাখ্যা করো?
- Timeout দিয়ে loss detect হওয়া, আর 3 duplicate ACK দিয়ে loss detect হওয়া — প্রতিক্রিয়ায় (cwnd রিসেট) পার্থক্য কী, এবং কেন এই পার্থক্য যুক্তিসঙ্গত?
- একটা high-latency (150ms RTT), lossy (mobile) নেটওয়ার্কে CUBIC vs BBR — কোনটা ভালো পারফর্ম করবে এবং কেন?
- একটা মাত্র ৫০ KB response, cross-continent RTT (150ms) নেটওয়ার্কে পাঠাতে গেলে — এই response কি পুরোপুরি Slow Start phase-এর মধ্যেই শেষ হয়ে যাবে, নাকি Congestion Avoidance পর্যন্ত পৌঁছাবে? হিসেব করে দেখাও (ধরো MSS=1460 bytes, initial cwnd = 10 MSS)।
পার্ট ৫ — Nagle's Algorithm (গভীরে)
সমস্যাটা কী, যেটা Nagle সমাধান করে
ধরো তুমি একটা interactive SSH session বা telnet ব্যবহার করছো — প্রতিটা কীবোর্ড keystroke সাথে সাথেই একটা আলাদা TCP segment হিসেবে পাঠানো হচ্ছে। প্রতিটা segment-এ থাকে ১ বাইট actual data, কিন্তু TCP+IP header মিলিয়ে ~৪০ বাইট overhead।
এটাকে বলে "tinygram problem" — অনেক ছোট ছোট প্যাকেট, প্রতিটাতে বিশাল overhead-to-data ratio। এটা নেটওয়ার্ক bandwidth-এর অপচয় করে (বিশেষ করে ধীরগতির লিংকে, যেমন 1980-এর দশকের dial-up, যখন এই algorithm তৈরি হয়েছিল)।
Nagle's Algorithm এর নিয়ম
সহজ ভাষায়: "যদি ইতিমধ্যে unacknowledged ডেটা পাঠানো থাকে, নতুন ছোট ডেটা তখনই পাঠাও না — ACK আসা পর্যন্ত বা যথেষ্ট ডেটা জমা হওয়া পর্যন্ত অপেক্ষা করো।"
আরও নির্দিষ্টভাবে:
- যদি segment size ≥ MSS হয় → সাথে সাথে পাঠাও (buffering দরকার নেই)
- যদি sender-এর কোনো unacknowledged ডেটা "in-flight" না থাকে → সাথে সাথে পাঠাও (ছোট হলেও)
- যদি unacknowledged ডেটা in-flight থাকে এবং নতুন ডেটা ছোট হয় → buffer করো, যতক্ষণ না হয় (ক) পূর্ববর্তী ACK আসে, বা (খ) যথেষ্ট ডেটা জমা হয়ে পূর্ণ segment হয়
উদাহরণ দিয়ে বুঝি
তুমি টাইপ করছো "hello" — একটা একটা করে অক্ষর:
Nagle ছাড়া: h, e, l, l, o — ৫টা আলাদা প্যাকেট, প্রতিটাতে ~৪০ বাইট overhead সহ ১ বাইট ডেটা
Nagle সহ:
hপাঠানো হয় সাথে সাথে (কোনো ডেটা in-flight ছিল না)- এখন
h-এর ACK-এর অপেক্ষায় থাকা অবস্থায়e,l,l,oটাইপ হয়ে গেলো — এগুলো buffer-এ জমা হয় h-এর ACK এলে, buffer-এ জমা থাকাelloএকসাথে একটা প্যাকেটে পাঠানো হয়
ফলাফল: overhead অনেক কমে যায়, কিন্তু trade-off হলো — ACK না আসা পর্যন্ত ডেটা delay হয়।
Nagle + Delayed ACK — একসাথে হলে একটা বিখ্যাত সমস্যা তৈরি হয়
Delayed ACK হলো receiver-side একটা optimization: receiver প্রতিটা প্যাকেটের জন্য সাথে সাথে ACK না পাঠিয়ে, একটু অপেক্ষা করে (সাধারণত ~40-200ms, বা পরবর্তী প্যাকেট আসা পর্যন্ত) — যাতে একটা ACK-এর সাথে reply ডেটাও piggyback করে পাঠানো যায় (efficiency-র জন্য)।
সমস্যাটা এখানে:
- Sender (Nagle সহ) বলছে: "আমি অপেক্ষা করছি ACK-এর জন্য, তারপর বাকি ডেটা পাঠাবো"
- Receiver (Delayed ACK সহ) বলছে: "আমি অপেক্ষা করছি আরেকটা প্যাকেট বা কিছু সময় পার হওয়ার জন্য, তারপর ACK পাঠাবো"
দুইপক্ষই একে অপরের অপেক্ষায় বসে থাকে — এটাকে বলে "Nagle-Delayed ACK interaction problem", যেটা প্রতিটা ছোট রিকোয়েস্টে প্রায় ৪০ms পর্যন্ত অতিরিক্ত latency যোগ করতে পারে। এই ৪০ms কোনো বড় সংখ্যা মনে না হলেও, একটা request-response chain-এ (যেমন একাধিক ছোট API call ধারাবাহিকভাবে) এটা জমা হয়ে বড় সমস্যা তৈরি করে।
সমাধান: TCP_NODELAY
TCP_NODELAY একটা socket option যেটা Nagle's Algorithm সম্পূর্ণ বন্ধ করে দেয় — প্রতিটা write() সাথে সাথে একটা প্যাকেট হিসেবে পাঠানো হয়, buffer করা ছাড়াই।
কখন TCP_NODELAY সেট করবে:
- Real-time/interactive সিস্টেম: gaming, financial trading, VoIP, chat applications — এখানে latency, throughput-এর চেয়ে বেশি গুরুত্বপূর্ণ
- HTTP servers: প্রায় সব modern web server (NGINX, ইত্যাদি) ডিফল্টভাবে TCP_NODELAY সেট করে রাখে, কারণ HTTP request/response সাধারণত ছোট এবং latency-sensitive
- RPC frameworks (gRPC ইত্যাদি): microservice-এর মধ্যে দ্রুত request-response দরকার
কখন Nagle রাখা ভালো (default থাকতে দেওয়া):
- বাল্ক ডেটা ট্রান্সফার (ফাইল আপলোড/ডাউনলোড, backup) — এখানে throughput গুরুত্বপূর্ণ, প্রতিটা ছোট write-এর latency না
একটা প্র্যাকটিক্যাল উদাহরণ — তোমার নিজের কাজের সাথে সংযোগ
ধরো তুমি একটা notification service বানাচ্ছো (তোমার existing experience) যেটা push notification পাঠানোর জন্য বারবার ছোট ছোট (কয়েক শ বাইট) request পাঠায় downstream সার্ভিসে (APNs/FCM gateway-তে)। যদি এই connection-এ Nagle enable থাকে এবং delayed ACK combine হয়, প্রতিটা notification পাঠাতে অপ্রয়োজনীয় ৪০ms পর্যন্ত latency যোগ হতে পারে — যেটা 100M+/day স্কেলে aggregate হয়ে throughput-কেও প্রভাবিত করে। এইজন্যই high-throughput, low-latency internal service-এ TCP_NODELAY সেট করা একটা standard practice।
🎯 এই পার্টের Active Recall
- Nagle's Algorithm ঠিক কোন শর্তে ডেটা buffer করে রাখে, আর কোন শর্তে সাথে সাথে পাঠায়?
- Nagle আর Delayed ACK একসাথে থাকলে কী সমস্যা হয়, এবং কেন এই সমস্যাটা "deadlock-এর মতো" আচরণ করে (যদিও প্রকৃত deadlock না, timeout দিয়ে শেষে ভেঙে যায়)?
- তোমার একটা microservice যেটা প্রতি সেকেন্ডে হাজার হাজার ছোট (< 100 bytes) internal RPC call করে — TCP_NODELAY সেট করবে কিনা, এবং যুক্তি দাও।
- উল্টো প্রশ্ন: কোন ধরনের সিস্টেমে তুমি ইচ্ছাকৃতভাবে Nagle চালু রাখবে (TCP_NODELAY সেট করবে না)?
পার্ট ৬ — সব একসাথে: একটা সম্পূর্ণ Connection Lifecycle উদাহরণ
ধরো একটা client একটা API server-এ একটা বড় ফাইল (৫ MB) আপলোড করছে, cross-continent connection (RTT ~150ms), MSS = 1460 bytes।
- Handshake: 1 RTT (~150ms) — connection established
- Slow Start শুরু: cwnd = 10 MSS (~14.6 KB) থেকে শুরু, প্রতি RTT-তে দ্বিগুণ
- RTT 1: cwnd ~14.6 KB পাঠানো গেলো
- RTT 2: cwnd ~29 KB
- RTT 3: cwnd ~58 KB
- RTT 4: cwnd ~117 KB
- RTT 5: cwnd ~234 KB
- ... এভাবে বাড়তে বাড়তে একসময় ssthresh-এ পৌঁছাবে বা packet loss হবে
- Congestion Avoidance: ধরো ssthresh-এ পৌঁছে গেছে ~500 KB cwnd-তে — এখন linear growth (+1 MSS প্রতি RTT)
- যদি packet loss হয় মাঝপথে (duplicate ACK দিয়ে detect): cwnd অর্ধেক হয়ে যাবে, fast retransmit হবে, আবার ধীরে ধীরে বাড়বে
- Nagle-এর ভূমিকা এখানে কম — কারণ এটা বাল্ক ট্রান্সফার, ফাইলের ডেটা বড় chunk-এ পাঠানো হচ্ছে (MSS-এর সমান বা বড়), তাই Nagle-এর buffering কার্যকর প্রভাব ফেলে না এখানে
- শেষে 4-way termination: FIN-ACK-FIN-ACK, তারপর client TIME_WAIT-এ যায়
মোট সময়ের হিসেব পুরোপুরি নির্ভর করে effective bandwidth কীভাবে cwnd growth-এর সাথে scale করে — এটাই কেন high-latency, high-bandwidth নেটওয়ার্কে (যাকে বলে "long fat pipe") TCP-এর পুরো bandwidth ব্যবহার করতে সময় লাগে, এবং এইজন্যই বড় ফাইল ট্রান্সফারে multiple parallel connections বা BBR-এর মতো আধুনিক algorithm ব্যবহারের সুবিধা পাওয়া যায়।
পার্ট ৭ — শেষ Consolidation: Interview-Style প্রশ্ন
নিজে নিজে (নোট ছাড়া, জোরে বলে) উত্তর দেওয়ার চেষ্টা করো:
- TCP-এর পাঁচটা মূল দায়িত্ব কী কী (পার্ট ০ থেকে) — প্রতিটা এক লাইনে ব্যাখ্যা করো।
- কেন handshake ৩-way কিন্তু termination ৪-way?
- cwnd আর rwnd-এর মধ্যে পার্থক্য কী, এবং sender কোনটা ব্যবহার করে ডেটা পাঠানোর পরিমাণ ঠিক করতে?
- Slow Start আর Congestion Avoidance-এর মধ্যে growth rate-এর পার্থক্য (exponential vs linear) কেন এভাবে ডিজাইন করা হয়েছে — safety আর efficiency-এর মধ্যে balance হিসেবে ব্যাখ্যা করো।
- একটা লাইভ প্রোডাকশন ইস্যু: তোমার একটা সার্ভিস অনেক short-lived connection বানাচ্ছে এবং হঠাৎ "cannot assign requested address" এরর দিচ্ছে — এটা কোন TCP concept-এর সাথে সম্পর্কিত (পার্ট ২ দেখো), এবং সমাধান কী হতে পারে?
- Nagle's algorithm বন্ধ করলে (TCP_NODELAY) থ্রুপুট না ল্যাটেন্সি — কোনটা উন্নত হয়, আর কোনটা সম্ভাব্য খারাপ হতে পারে?
Day 5 · UDP, QUIC — when to abandon TCP
পার্ট ০ — Day 4 থেকে সংযোগ: কেন এই টপিক গুরুত্বপূর্ণ
Day 4-এ আমরা দেখেছি TCP কতটা "যত্নশীল" — handshake, congestion control, retransmission, ordered delivery। এই যত্নের একটা মূল্য আছে: latency এবং overhead।
আজকের প্রশ্ন হলো: এই যত্নশীলতা কি সবসময় দরকার? উত্তর: না। অনেক ক্ষেত্রে এই "guarantee"-গুলোই আসলে সমস্যা তৈরি করে। UDP আর QUIC বোঝার মূল উদ্দেশ্য হলো — কখন reliability ছেড়ে দিয়ে গতি বেছে নেওয়া বুদ্ধিমানের কাজ, এবং কীভাবে আধুনিক protocol (QUIC) দুটোই একসাথে দেওয়ার চেষ্টা করে।
পার্ট ১ — UDP এর ফান্ডামেন্টাল
UDP কী, একদম বেসিক থেকে
UDP (User Datagram Protocol) হলো IP-এর উপর একটা ন্যূনতম layer — শুধু port number যোগ করে (যাতে একই মেশিনে একাধিক application আলাদা করা যায়) এবং একটা checksum (optional integrity check)। এর বাইরে UDP কিছুই করে না।
UDP header মাত্র ৮ বাইট (TCP header সাধারণত ২০ বাইট, options সহ আরও বেশি):
| ফিল্ড | সাইজ |
|---|---|
| Source Port | 2 bytes |
| Destination Port | 2 bytes |
| Length | 2 bytes |
| Checksum | 2 bytes |
তুলনা করো Day 4-এর TCP header-এর সাথে — sequence number নেই, ACK number নেই, window size নেই, flags নেই। UDP "connectionless" — কোনো handshake নেই, কোনো state track করা হয় না। sender শুধু একটা packet (datagram) পাঠিয়ে দেয়, receiver পাক বা না পাক।
UDP কী কী দেয় না (এটাই মূল বিষয়)
Day 4-এ TCP-এর ৫টা দায়িত্বের কথা মনে করো — reliability, ordering, no-duplication, flow control, congestion control। UDP এর একটাও করে না:
- কোনো handshake নেই → 0 RTT setup cost
- কোনো retransmission নেই → packet হারালে হারিয়েই গেলো, কেউ আবার পাঠাবে না
- কোনো ordering গ্যারান্টি নেই → packet ভিন্ন route নিয়ে ভিন্ন order-এ পৌঁছাতে পারে
- কোনো flow/congestion control নেই → sender receiver-এর ক্ষমতা বা নেটওয়ার্কের অবস্থা বিবেচনা না করেই পাঠাতে থাকে
তাহলে UDP কেন ব্যবহার করবে? — এই প্রশ্নটাই আজকের মূল কেন্দ্রবিন্দু
মূল ইনসাইট: TCP-এর guarantee গুলো ফ্রি না — সেগুলোর জন্য মূল্য দিতে হয় latency আকারে (handshake RTT, retransmission wait, head-of-line blocking)। এমন অনেক application আছে যেখানে:
"দেরি করে সঠিক ডেটা" এর চেয়ে "সময়মতো approximate/lossy ডেটা" ভালো
এই একটা বাক্য মুখস্থ রাখলে UDP-এর পুরো justification বোঝা যায়।
উদাহরণ ১: ভিডিও কল (WebRTC-এর ভিত্তি)
ধরো একটা ভিডিও কলে একটা ফ্রেমের একটা প্যাকেট হারিয়ে গেলো।
- TCP হলে: sender retransmit করবে হারানো প্যাকেট, receiver অপেক্ষা করবে (ordering বজায় রাখতে) — ততক্ষণে ভিডিও freeze হয়ে যাবে, এবং retransmit-এর ডেটা এসে পৌঁছানোর সময়ে সেই ফ্রেম already outdated (নতুন ফ্রেম আসার সময় হয়ে গেছে)
- UDP হলে: সেই প্যাকেট হারিয়ে গেলে সামান্য glitch/pixelation দেখা যাবে সেই ফ্রেমে, কিন্তু পরের ফ্রেম ঠিক সময়েই আসবে — কল চলতেই থাকবে
মূল যুক্তি: একটা পুরনো ফ্রেম দেরি করে সঠিকভাবে দেখানোর কোনো মূল্য নেই — user real-time অভিজ্ঞতা চায়, perfect অভিজ্ঞতা না।
উদাহরণ ২: DNS (Day 8-এর সাথে সংযোগ)
DNS query সাধারণত UDP দিয়ে পাঠানো হয় কারণ:
- Query + response দুটোই খুব ছোট (এক প্যাকেটে ফিট করে)
- TCP handshake-এর 1 RTT overhead একটা ছোট lookup-এর জন্য অপ্রয়োজনীয় বেশি
- যদি packet হারিয়ে যায়, client সহজেই নিজে থেকে আবার query পাঠাতে পারে (application-level retry) — এটা TCP-এর built-in retransmission মেকানিজমের চেয়ে সহজ এবং দ্রুত এখানে, কারণ পুরো query-ই আবার পাঠানো ছোট একটা কাজ
ব্যতিক্রম: বড় DNS response (যেমন DNSSEC সহ, বা zone transfer) TCP ব্যবহার করে, কারণ UDP-তে packet size limit আছে (সাধারণত ৫১২ বাইট থেকে EDNS0 দিয়ে বাড়ানো যায়, কিন্তু তারপরও সীমাবদ্ধ)।
উদাহরণ ৩: Online Gaming
একটা multiplayer game-এ player-এর position update প্রতি কয়েক মিলিসেকেন্ডে পাঠানো হয়।
- যদি একটা position-update প্যাকেট হারিয়ে যায়, পরের আপডেটেই (কয়েক ms পরে) নতুন, আরও up-to-date position আসবে
- পুরনো position retransmit করার কোনো মানে নেই — ততক্ষণে player আরও এগিয়ে গেছে
- TCP ব্যবহার করলে, একটা হারানো প্যাকেটের জন্য retransmission wait করতে গিয়ে পরবর্তী সব আপডেট আটকে থাকবে (ordering-এর কারণে) — এটা game-এ "lag" হিসেবে অনুভূত হবে
উদাহরণ ৪: Streaming Media / Live Broadcast
একই যুক্তি — একটা ভিডিও স্ট্রিমে একটা ফ্রেমের ডেটা সামান্য corrupt/missing হলে, viewer একটা glitch দেখবে কিন্তু stream চলতেই থাকবে; TCP হলে পুরো stream buffer করে retransmission-এর জন্য অপেক্ষা করতে হতো।
সারাংশ — কখন UDP বেছে নেবে (Decision Framework)
| শর্ত | UDP উপযুক্ত কেন |
|---|---|
| ডেটা দ্রুত "stale" (পুরনো/অপ্রয়োজনীয়) হয়ে যায় | পুরনো ডেটা retransmit করার মূল্য নেই |
| Application নিজেই loss handle করতে পারে | game state, ভিডিও কোডেক নিজেই error concealment করে |
| খুব ছোট, single-packet exchange | handshake overhead অপ্রয়োজনীয় |
| Latency, correctness-এর চেয়ে বেশি গুরুত্বপূর্ণ | real-time interactivity মুখ্য |
| Multicast/broadcast দরকার | TCP point-to-point, UDP broadcast/multicast সাপোর্ট করে |
পার্ট ২ — QUIC: TCP-এর সমস্যা + UDP-এর গতি, দুটোই একসাথে
কেন QUIC তৈরি হলো — সমস্যাটা আবার ঝালাই করি
Google ইঞ্জিনিয়াররা লক্ষ্য করলো: web-এর জন্য UDP-এর raw speed দরকার নেই (কারণ web content-এর reliability দরকার — একটা HTML page-এর অর্ধেক বাইট হারিয়ে গেলে সেটা useless), কিন্তু TCP-এর নির্দিষ্ট কিছু সমস্যা আছে যেগুলো protocol-এর গভীরে embedded, ফিক্স করা কঠিন:
- TCP head-of-line blocking (Day 7-এ HTTP/2 প্রসঙ্গে দেখেছি) — একটা stream-এর একটা প্যাকেট miss হলে, একই connection-এর অন্য সব stream আটকে যায়, কারণ TCP নিজে stream-এর concept বোঝে না, শুধু একটা linear byte-stream ordering মেনে চলে
- ধীর handshake — TCP handshake (1 RTT) + TLS handshake (1-2 RTT, Day 6) = অনেক সময় নষ্ট, বিশেষ করে ছোট request-এ
- OS kernel-এ embedded — TCP-তে নতুন feature/improvement আনতে হলে প্রতিটা OS-এর kernel আপডেট লাগে (কারণ TCP stack সাধারণত kernel-এ implement করা), যেটা রোলআউট হতে বছরের পর বছর লাগে
- Connection migration সমর্থন করে না — TCP connection 4-tuple (source IP, source port, dest IP, dest port) দিয়ে identify হয়। Client-এর IP বদলে গেলে (যেমন WiFi থেকে mobile data-এ switch), connection ভেঙে যায়, নতুন করে সব শুরু করতে হয়
QUIC-এর মূল সমাধান: UDP-এর উপর নিজস্ব Reliability Layer বানানো
QUIC আসলে UDP প্যাকেটের ভেতরে নিজের reliability, ordering, congestion control ইমপ্লিমেন্ট করে — application layer-এ (user-space, kernel-এ না)। এর মানে:
- QUIC পায় UDP-এর flexibility (kernel পরিবর্তন ছাড়াই আপডেট করা যায়, কারণ এটা library/application code)
- কিন্তু নিজে বানিয়ে নেয় TCP-এর মতোই reliability, ordering, congestion control — শুধু আরও স্মার্টভাবে
সমাধান ১: Independent Streams (HOL Blocking সমাধান)
QUIC connection-এর ভেতর একাধিক independent stream থাকতে পারে। প্রতিটা stream-এর নিজস্ব sequencing থাকে — একটা stream-এর packet loss শুধু সেই stream-কেই ব্লক করে, অন্য stream-গুলো নির্বিঘ্নে চলতে থাকে।
TCP + HTTP/2 (একই connection-এ multiplexed streams):
Stream 1: [pkt1][pkt2][LOST][pkt4] ←── TCP লেভেলে ordering ভাঙে
Stream 2: [pkt1][pkt2][pkt3] ←── এটাও আটকে যায় কারণ TCP
একটাই linear byte stream
QUIC (independent streams, UDP-ভিত্তিক):
Stream 1: [pkt1][pkt2][LOST][pkt4] ←── শুধু এই stream প্রভাবিত
Stream 2: [pkt1][pkt2][pkt3] ←── স্বাভাবিকভাবে চলতে থাকে
এটাই সবচেয়ে গুরুত্বপূর্ণ পার্থক্য বোঝার পয়েন্ট: HTTP/2 already স্ট্রিম মাল্টিপ্লেক্সিং করে application layer-এ, কিন্তু নিচে TCP এখনও একটা মাত্র ordered byte stream হিসেবে কাজ করে — তাই TCP-লেভেল loss সব HTTP/2 stream-কে প্রভাবিত করে। QUIC এই মাল্টিপ্লেক্সিং-কে transport layer-এ নিয়ে আসে, তাই loss-এর প্রভাব সঠিকভাবে isolated থাকে।
সমাধান ২: দ্রুততর Handshake (0-RTT / 1-RTT)
QUIC TLS 1.3-কে নিজের ভেতরে integrate করে — অর্থাৎ connection handshake এবং cryptographic handshake একসাথে, একই সময়ে সম্পন্ন হয়:
| Protocol Stack | Handshake সময় (নতুন connection) | Handshake সময় (repeat connection) |
|---|---|---|
| TCP + TLS 1.3 | 2 RTT (1 TCP + 1 TLS) | 2 RTT (session resumption দিয়ে কিছুটা কমতে পারে, কিন্তু TCP handshake আলাদাভাবে লাগবেই) |
| QUIC | 1 RTT (TCP + TLS combined) | 0-RTT সম্ভব (client আগের session-এর cached key ব্যবহার করে প্রথম প্যাকেটেই encrypted data পাঠাতে পারে) |
0-RTT-এর একটা সতর্কতা: 0-RTT data "replay attack"-এর ঝুঁকিতে থাকে (কারণ এটা fresh handshake ছাড়াই পাঠানো হচ্ছে, একজন attacker সেই প্যাকেট capture করে আবার পাঠাতে পারে) — তাই শুধুমাত্র idempotent request (যেমন GET, যেটা বারবার করলেও কোনো ক্ষতি নেই) 0-RTT-তে পাঠানো নিরাপদ; non-idempotent (যেমন payment request) সাধারণত 0-RTT এড়িয়ে চলে।
সমাধান ৩: Connection Migration
QUIC connection চেনা হয় Connection ID দিয়ে, IP+port দিয়ে না। মানে:
TCP: Connection = (src_IP, src_port, dst_IP, dst_port)
IP বদলালে = নতুন connection দরকার
QUIC: Connection = Connection ID (একটা independent identifier)
IP বদলালেও = একই Connection ID, connection বেঁচে থাকে
Practical Impact: তুমি একটা ভিডিও কল করছো, বাসার WiFi থেকে বের হয়ে মোবাইল ডেটায় switch করলে — QUIC-ভিত্তিক connection (যেমন Google Meet) নির্বিঘ্নে চলতে থাকবে, কারণ connection ID অপরিবর্তিত থাকে, শুধু underlying network path বদলায়।
সমাধান ৪: Congestion Control User-Space-এ (Deployment Velocity)
যেহেতু QUIC user-space-এ (application/library কোডে) ইমপ্লিমেন্ট হয়, নতুন congestion control algorithm (যেমন BBR, Day 4-এ আলোচিত) deploy করতে পুরো internet-এর OS kernel আপডেট হওয়ার অপেক্ষা করতে হয় না — শুধু application/library আপডেট করলেই হয়। এটাই একটা বড় কারণ কেন Google দ্রুত iterate করতে পেরেছে QUIC নিয়ে, TCP নিয়ে যেটা কার্যত অসম্ভব (TCP-র বেশিরভাগ পরিবর্তনই কার্যকর হতে বছরের পর বছর লাগে, কারণ middlebox, kernel, ISP সব জায়গায় compatibility বজায় রাখতে হয়)।
HTTP/3 = HTTP over QUIC
Day 7-এ আমরা HTTP/3 নিয়ে সংক্ষেপে কথা বলেছি — এখন পুরো ছবিটা পরিষ্কার: HTTP/3 আসলে নতুন কোনো HTTP semantics না, এটা শুধু HTTP/2-এর multiplexing ধারণাকে TCP-এর বদলে QUIC-এর উপর বসিয়েছে, যাতে TCP-level HOL blocking সমস্যা দূর হয়।
পার্ট ৩ — QUIC কি তাহলে "reliable UDP"? এই ভুল ধারণা পরিষ্কার করা দরকার
একটা সাধারণ ভুল ধারণা: "QUIC মানে reliable UDP, তাই এটা TCP-এর মতোই।" এটা আংশিক সত্যি, কিন্তু গুরুত্বপূর্ণ পার্থক্য আছে:
| বিষয় | TCP | QUIC |
|---|---|---|
| Reliability | আছে (single ordered stream) | আছে (per-stream ordered, stream-level independence) |
| HOL Blocking | আছে (পুরো connection-জুড়ে) | নেই (stream-level isolation) |
| Encryption | Optional (TLS আলাদা layer) | বাধ্যতামূলক, TLS 1.3 built-in |
| Handshake | TCP + TLS আলাদা (2 RTT) | Combined (1 RTT, বা 0-RTT repeat) |
| Kernel dependency | OS kernel-এ implement | User-space library-তে implement |
| Connection identity | IP+port 4-tuple | Connection ID (IP-independent) |
মূল কথা: QUIC "TCP-এর ভালো অংশ (reliability, ordering) + UDP-এর flexibility (user-space, no kernel lock-in) + নতুন উদ্ভাবন (stream independence, connection migration, integrated security)" — এটা দুটোর মাঝামাঝি কিছু না, বরং একটা নতুন প্রজন্মের transport protocol যেটা TCP-এর সীমাবদ্ধতা মাথায় রেখে ডিজাইন করা।
পার্ট ৪ — Decision Framework: কখন কী ব্যবহার করবে (Interview-Ready)
সিদ্ধান্তের ফ্লো (মনে রাখার সহজ উপায়)
প্রশ্ন ১: ডেটা হারালে "stale/useless" হয়ে যায়, নাকি এখনও দরকারি?
│
├── Stale হয়ে যায় (game position, video frame,
│ live audio) → UDP (raw) বিবেচনা করো
│
└── এখনও দরকারি (file content, API response,
database record, financial transaction)
│
▼
প্রশ্ন ২: HOL blocking এবং handshake speed
গুরুত্বপূর্ণ কিনা (web-scale traffic, mobile
network switching)?
│
├── হ্যাঁ → QUIC/HTTP-3 বিবেচনা করো
│
└── না, বা legacy compatibility দরকার
→ TCP যথেষ্ট
বাস্তব উদাহরণ সহ টেবিল
| Use Case | Protocol | মূল যুক্তি |
|---|---|---|
| Web browsing (আধুনিক browser + server) | QUIC (HTTP/3) | দ্রুত handshake, no HOL blocking, mobile-friendly |
| Legacy API, internal service (compatibility priority) | TCP | ব্যাপক support, simpler debugging/tooling, ossification কম ঝুঁকি |
| Video conferencing (Zoom, Google Meet) | UDP (RTP-ভিত্তিক) বা QUIC | Real-time, loss-tolerant, latency critical |
| Online multiplayer gaming | UDP (custom protocol) | সর্বনিম্ন latency, application-level loss handling |
| File transfer / backup / replication | TCP | Reliability essential, প্রতিটা বাইট গুরুত্বপূর্ণ |
| DNS query | UDP (fallback: TCP for large responses) | ছোট, দ্রুত, সহজ retry |
| Database replication (Postgres streaming replication) | TCP | প্রতিটা WAL byte-এর order এবং সম্পূর্ণতা critical — এক বাইট হারালে data corruption |
| gRPC internal microservice calls | TCP (HTTP/2-ভিত্তিক) অথবা QUIC (HTTP/3-ভিত্তিক gRPC, নতুন) | Reliability দরকার + multiplexing benefit |
| IoT sensor data (high frequency, tolerant of loss) | UDP | প্রতিটা reading না পেলেও চলবে, পরের reading আসবে |
একটা গুরুত্বপূর্ণ nuance: "Reliable" মানে সবসময় TCP/QUIC না
কিছু সিস্টেম UDP-এর উপর নিজস্ব custom reliability layer বানায় (TCP পুরোপুরি ব্যবহার না করে) — কারণ তাদের নির্দিষ্ট প্রয়োজন TCP-এর generic reliability model-এর চেয়ে ভিন্ন:
- QUIC নিজেই এর একটা উদাহরণ (UDP-এর উপর custom reliability)
- WebRTC-এর data channel SCTP ব্যবহার করে (partial reliability সাপোর্ট করে — তুমি বলে দিতে পারো "এই স্ট্রিমে ৩ বারের বেশি retransmit করো না")
- গেম ইঞ্জিন (যেমন Source engine) নিজস্ব "reliable UDP" বানায় যেখানে শুধু নির্দিষ্ট গুরুত্বপূর্ণ ইভেন্ট (যেমন "player fired weapon") reliable delivery পায়, কিন্তু position update-এর মতো high-frequency, loss-tolerant ডেটা raw UDP-তেই যায়
এই থেকে ইন্টারভিউ-এর জন্য শেখার পয়েন্ট: "TCP vs UDP" একটা বাইনারি সিদ্ধান্ত না — একই সিস্টেমে বিভিন্ন ডেটা টাইপের জন্য বিভিন্ন reliability guarantee দরকার হতে পারে, এবং সিনিয়র-লেভেল ডিজাইনে এই granularity-টা দেখানো একটা ভালো সংকেত।
পার্ট ৫ — একটা সম্পূর্ণ কেস স্টাডি: Live Video Streaming Platform ডিজাইন (protocol choice সহ)
ধরো তুমি একটা live streaming platform ডিজাইন করছো (Twitch-এর মতো) — বিভিন্ন অংশে বিভিন্ন protocol লাগবে:
| Component | Protocol | যুক্তি |
|---|---|---|
| Streamer → Ingest Server (video upload) | RTMP (TCP-ভিত্তিক) অথবা WebRTC/QUIC-ভিত্তিক নতুন প্রোটোকল (WHIP) | Ingest-এ কিছুটা reliability দরকার (source quality বজায় রাখতে), কিন্তু নতুন সিস্টেমে কম-latency-র জন্য QUIC-ভিত্তিক সমাধানে ঝুঁকছে ইন্ডাস্ট্রি |
| Ingest → Transcoding pipeline (internal) | TCP | Internal, reliable pipeline, ordering critical |
| CDN → Viewer (video segment delivery, HLS/DASH) | TCP (HTTP/1.1 বা HTTP/2) অথবা QUIC (HTTP/3) | Video segment (কয়েক সেকেন্ডের chunk) সম্পূর্ণ এবং সঠিক লাগবে, তাই reliable transport দরকার — কিন্তু QUIC ব্যবহার করলে page load ও segment fetch দ্রুততর হবে বিশেষত mobile viewer-দের জন্য |
| Live chat (viewer messages) | WebSocket over TCP | Message ordering এবং delivery guarantee দরকার, কিন্তু connection persistent রাখা priority |
| Ultra-low-latency interactive stream (যেমন real-time reaction) | WebRTC (UDP-ভিত্তিক, SRTP) | সর্বনিম্ন latency priority, সামান্য frame loss acceptable |
এই কেস স্টাডিটাই দেখায় কেন "TCP vs UDP" একক প্রশ্ন না — একই প্রোডাক্টে বিভিন্ন কম্পোনেন্টে বিভিন্ন protocol বেছে নেওয়া হয়, প্রতিটার নির্দিষ্ট requirement অনুযায়ী।
পার্ট ৬ — Consolidation: Interview-Style প্রশ্ন
নিজে নিজে (নোট ছাড়া, জোরে বলে) উত্তর দেওয়ার চেষ্টা করো:
- UDP header-এ কী কী নেই যা TCP header-এ আছে, এবং এই absence-গুলো UDP-কে কী সুবিধা দেয়?
- "দেরি করে সঠিক ডেটার চেয়ে সময়মতো lossy ডেটা ভালো" — এই নীতি কোন কোন ধরনের সিস্টেমে প্রযোজ্য, তিনটা উদাহরণ দাও।
- QUIC কীভাবে HTTP/2-এর TCP-level head-of-line blocking সমস্যা সমাধান করে — mechanism ব্যাখ্যা করো (independent streams concept ব্যবহার করে)।
- QUIC connection migration কীভাবে কাজ করে, এবং এটা mobile user experience-এ কী পার্থক্য আনে?
- 0-RTT data পাঠানো কেন idempotent request-এর জন্যই নিরাপদ, non-idempotent-এর জন্য না — উদাহরণ দিয়ে ব্যাখ্যা করো।
- কেন QUIC-কে "user-space-এ ইমপ্লিমেন্টেড" বলা হয়, এবং এটা কেন deployment velocity-র জন্য গুরুত্বপূর্ণ (TCP-র সাথে তুলনা করে)?
- একটা live video streaming platform ডিজাইনে (পার্ট ৫ দেখো) — কোন কোন কম্পোনেন্টে TCP/QUIC আর কোথায় UDP/WebRTC ব্যবহার করবে, এবং কেন প্রতিটাতে আলাদা প্রোটোকল দরকার?
Day 6 · TLS: handshake, resumption, mTLS, cert chains
পার্ট ০ — Day 4-5 থেকে সংযোগ, এবং TLS আসলে কী সমস্যা সমাধান করে
Day 4-এ TCP আমাদের দিলো: reliable, ordered delivery। Day 5-এ QUIC আমাদের দিলো: দ্রুত, flexible transport। কিন্তু একটা জিনিস কোনোটাই দেয়নি: নিরাপত্তা।
TCP একটা connection নিশ্চিত করে ঠিকই, কিন্তু:
- যেকেউ মাঝপথে (router, ISP, public WiFi-এর অন্য কেউ) তোমার ডেটা পড়ে ফেলতে পারে (plain text-এ যায়)
- যেকেউ ডেটা পরিবর্তন করে দিতে পারে পথিমধ্যে, তুমি বুঝতেও পারবে না
- তুমি যে সার্ভারের সাথে কথা বলছো বলে ভাবছো, সেটা আসল সার্ভার কিনা তার কোনো প্রমাণ নেই (Man-in-the-Middle attack সম্ভব)
TLS (Transport Layer Security) এই তিনটা সমস্যা সমাধান করে তিনটা মূল গ্যারান্টি দিয়ে:
- Confidentiality (গোপনীয়তা) — এনক্রিপশনের মাধ্যমে, মাঝপথে কেউ পড়তে পারবে না
- Integrity (অখণ্ডতা) — MAC (Message Authentication Code) দিয়ে, ডেটা বদলানো হলে ধরা পড়বে
- Authentication (পরিচয় যাচাই) — Certificate দিয়ে, তুমি প্রমাণ পাও সার্ভার আসলেই যে দাবি করছে সেই
এই তিনটা মনে রাখো — আজকের প্রতিটা মেকানিজম (handshake, cert chain, mTLS) এই তিনটার কোনো না কোনোটা অর্জনের জন্য ডিজাইন করা।
একটা analogy দিয়ে শুরু করি
তুমি একটা চিঠি পাঠাতে চাও যাতে:
- পথে কেউ পড়তে না পারে (তালাবদ্ধ বাক্সে ভরে পাঠাও — encryption)
- পথে কেউ চিঠি বদলে দিলে বোঝা যায় (একটা বিশেষ সিল লাগাও যা ভাঙলে বোঝা যাবে — integrity check)
- তুমি নিশ্চিত হও যে বাক্সটা সঠিক ব্যক্তির কাছে পৌঁছাচ্ছে, ভুয়া ঠিকানায় না (সরকারি স্বীকৃত পরিচয়পত্র চেক করা — certificate verification)
পার্ট ১ — Cryptography-এর বেসিক যেটা না জানলে TLS বোঝা কঠিন
Symmetric vs Asymmetric Encryption
Symmetric Encryption: একই key দিয়ে encrypt আর decrypt দুটোই হয়।
- সুবিধা: অনেক দ্রুত (AES-এর মতো algorithm হার্ডওয়্যার-accelerated)
- সমস্যা: দুই পক্ষকে আগে থেকেই সেই একই key জানতে হবে — কিন্তু এই key নিরাপদে কীভাবে শেয়ার করবে ইন্টারনেটের মতো অনিরাপদ চ্যানেলে?
Asymmetric Encryption (Public-Key Cryptography): দুইটা আলাদা key — একটা public key (সবাইকে দেওয়া যায়) দিয়ে encrypt করা হয়, আরেকটা private key (গোপন রাখা হয়) দিয়ে decrypt করা হয়।
- সুবিধা: key শেয়ার করার সমস্যা সমাধান হয় — public key প্রকাশ্যে পাঠানো যায়, কেউ সেটা দিয়ে decrypt করতে পারবে না
- সমস্যা: অনেক ধীর (symmetric-এর চেয়ে ১০০-১০০০ গুণ পর্যন্ত ধীর হতে পারে)
TLS-এর চমৎকার সমাধান: দুটোরই সুবিধা নেওয়া —
- Asymmetric cryptography ব্যবহার করে নিরাপদে একটা shared symmetric key নিয়ে আসা (handshake-এর মূল কাজ এটাই)
- এরপর actual ডেটা এনক্রিপ্ট করতে সেই দ্রুতগতির symmetric key ব্যবহার করা
এই একটা লাইনই পুরো TLS handshake-এর মূল উদ্দেশ্য ব্যাখ্যা করে: "নিরাপদে একটা shared secret negotiate করা, তারপর সেটা দিয়ে দ্রুত communication করা।"
Digital Signature — Authentication-এর ভিত্তি
Private key দিয়ে কোনো ডেটার একটা "signature" তৈরি করা যায়, যেটা যে কেউ সংশ্লিষ্ট public key দিয়ে verify করতে পারে যে এই signature সেই private key-ধারী ব্যক্তিই বানিয়েছে। এটাই certificate-এর ভিত্তি (পার্ট ৪-এ বিস্তারিত)।
পার্ট ২ — TLS Handshake গভীরে (TLS 1.3, বর্তমান স্ট্যান্ডার্ড)
TLS 1.3-এর হ্যান্ডশেক (Full/Fresh handshake)
Client Server
│ │
│ ClientHello │
│ (supported cipher suites, key_share, │
│ supported_versions) │
│ ──────────────────────────────────────────────────→ │
│ │
│ ServerHello + key_share │
│ {EncryptedExtensions} │
│ {Certificate} │
│ {CertificateVerify} │
│ {Finished} │
│ ←────────────────────────────────────────────────── │
│ │
│ {Finished} │
│ Application Data (encrypted) ────────────────────→ │
│ │
(কার্লি ব্র্যাকেট {} মানে এই অংশটুকু ইতিমধ্যে এনক্রিপ্টেড — TLS 1.3-এ ServerHello-এর পরের সবকিছু এনক্রিপ্টেড, যেটা TLS 1.2-এর চেয়ে একটা বড় নিরাপত্তা উন্নতি, কারণ certificate-ও কেউ মাঝপথে দেখতে পারবে না)
ধাপে ধাপে কী ঘটছে
ClientHello: client বলে "আমি এই cipher suite-গুলো সাপোর্ট করি, এবং এখানে আমার key exchange-এর জন্য একটা random value (
key_share, Diffie-Hellman-ভিত্তিক)"ServerHello + key_share: server নিজের পছন্দের cipher suite বেছে নেয়, নিজের
key_shareপাঠায় — এই মুহূর্তেই দুই পক্ষের কাছে যথেষ্ট তথ্য আছে shared secret বের করার জন্য (Diffie-Hellman key exchange-এর ম্যাজিক — দুই পক্ষ কখনো actual secret শেয়ার না করেই একই secret independently বের করতে পারে গাণিতিকভাবে)Certificate: server তার certificate পাঠায় (পার্ট ৪-এ বিস্তারিত) — প্রমাণ করতে যে সে যা দাবি করছে (যেমন example.com) সেটাই সে
CertificateVerify: server তার private key দিয়ে হ্যান্ডশেকের এই পর্যন্ত সবকিছুর একটা signature বানায় — এটা প্রমাণ করে server সত্যিই সেই certificate-এর সংশ্লিষ্ট private key-এর মালিক (শুধু certificate দেখানো যথেষ্ট না, কারণ certificate একটা public ডকুমেন্ট যেকেউ কপি করতে পারে — private key দিয়ে signature বানানোটাই আসল প্রমাণ)
Finished: উভয় পক্ষ একটা MAC পাঠায় পুরো handshake-এর, যাতে নিশ্চিত হয় কেউ মাঝপথে handshake-এর কোনো অংশ পরিবর্তন করেনি (downgrade attack প্রতিরোধ)
কেন এটা "1 RTT" (TLS 1.2 ছিল 2 RTT)
TLS 1.2-এ: ClientHello → ServerHello+Certificate (কিন্তু key exchange এখনো সম্পূর্ণ হয়নি, আরেকটা round দরকার) → Client key exchange সম্পন্ন করে পাঠায় → Server Finished পাঠায় = 2 RTT
TLS 1.3-এ: key exchange প্রথম বার্তাতেই (key_share দিয়ে) সম্পন্ন হয়ে যায় — Diffie-Hellman parameter client প্রথমেই "guess" করে পাঠিয়ে দেয় (সাধারণ ব্যবহৃত curve, যেমন X25519 ধরে নিয়ে), server সেটা মেনে নিলে এক রাউন্ডেই কাজ শেষ। তাই 1 RTT।
সংখ্যায় দেখি — সম্পূর্ণ Secure Connection-এর মোট cost
Day 4-এর TCP handshake-এর সাথে যোগ করি:
| Layer | RTT (নতুন connection) |
|---|---|
| TCP handshake | 1 RTT |
| TLS 1.2 handshake | 2 RTT |
| TLS 1.3 handshake | 1 RTT |
| TCP + TLS 1.2 মোট | 3 RTT |
| TCP + TLS 1.3 মোট | 2 RTT |
| QUIC (TCP+TLS combined, Day 5) | 1 RTT |
Cross-continent (RTT ~150ms) হলে: TLS 1.2 দিয়ে প্রথম বাইট পেতে ~450ms, TLS 1.3 দিয়ে ~300ms, QUIC দিয়ে ~150ms। এই ৩০০ms পার্থক্যটাই বোঝায় কেন industry TLS 1.3 আর QUIC-এর দিকে দ্রুত shift করেছে।
পার্ট ৩ — Session Resumption: বারবার Handshake এড়ানো
সমস্যা
উপরের পুরো handshake প্রতিটা নতুন connection-এ আবার করতে হলে সেটা costly (extra RTT + CPU-intensive asymmetric cryptography operation)। কিন্তু একই client বারবার একই server-এ connect করে (যেমন একটা browser যেটা একই ওয়েবসাইট বারবার visit করে, বা একটা mobile app যেটা প্রতি কয়েক মিনিটে API call করে)।
সমাধান: Session Resumption (TLS 1.3-এ "PSK — Pre-Shared Key" মেকানিজম দিয়ে)
প্রথমবার একটা full handshake হওয়ার পর, server client-কে একটা "session ticket" পাঠায় (encrypted, শুধু server-ই এটা বুঝতে পারে) — এই ticket-এ session-এর key material সংরক্ষিত থাকে।
দ্বিতীয়বার connect করার সময়:
Client Server
│ ClientHello + PSK (session ticket) + │
│ early_data (0-RTT application data, optional) │
│ ──────────────────────────────────────────────────→ │
│ │
│ ServerHello + {Finished} │
│ ←────────────────────────────────────────────────── │
│ │
│ Application Data ─────────────────────────────────→│
Server ticket verify করে আগের negotiated key পুনর্ব্যবহার করে — নতুন asymmetric handshake লাগে না, শুধু ticket-ভিত্তিক verification। এতে handshake 0-RTT বা 1-RTT-তে নেমে আসে।
Session ID vs Session Ticket — দুইটা পুরনো ও নতুন পদ্ধতি
- Session ID (TLS 1.2-era): server নিজের মেমোরিতে session state সংরক্ষণ করে রাখে, client শুধু session ID পাঠায় পরের বার — সমস্যা: server-side memory ব্যবহার হয়, বহু সার্ভার (load-balanced) থাকলে session state শেয়ার করার সমস্যা হয়
- Session Ticket (আধুনিক, stateless): session state client-এর কাছে encrypted ticket আকারে রাখা হয় (server নিজে কিছু মনে রাখে না) — server শুধু নিজের একটা secret key দিয়ে ticket decrypt/verify করতে পারে। Stateless, তাই multiple load-balanced server-এর মধ্যে state শেয়ার করার সমস্যা নেই (যদি সব server একই ticket-encryption key শেয়ার করে)
Production insight: Load balancer-এর পেছনে একাধিক TLS-terminating সার্ভার থাকলে, session ticket key সব সার্ভারে sync রাখতে হবে, নাহলে একটা client-এর resumption request ভুল সার্ভারে গেলে resumption fail করবে (fallback করে full handshake-এ চলে যাবে — কার্যকরী কিন্তু ধীর)।
0-RTT Data — সুবিধা এবং ঝুঁকি (Day 5-এর সাথে সংযোগ)
Session resumption-এ client চাইলে প্রথম বার্তাতেই (early_data) actual application ডেটা পাঠিয়ে দিতে পারে, ServerHello-এর জন্য অপেক্ষা না করেই — এটাই 0-RTT।
ঝুঁকি: 0-RTT ডেটা replay attack-এর বিপক্ষে সুরক্ষিত না — একজন attacker যদি এই প্রথম প্যাকেট capture করে ফেলে, সে সেটা আবার পাঠাতে পারবে এবং server সেটা বৈধ মনে করবে (কারণ এটা fresh handshake দিয়ে verify হয়নি)।
Rule of thumb: শুধুমাত্র idempotent operation (যেমন GET request, যেটা বারবার করলেও state পরিবর্তন হয় না) 0-RTT-তে নিরাপদ। Non-idempotent (যেমন POST /transfer-money) কখনোই 0-RTT-তে পাঠানো উচিত না।
পার্ট ৪ — Certificate এবং Certificate Chain — বিশ্বাস কোথা থেকে আসে
মূল প্রশ্ন: Client কীভাবে বিশ্বাস করে যে একটা certificate সত্যি?
Certificate নিজেই একটা ফাইল — যেকেউ যেকোনো নাম দিয়ে একটা certificate বানাতে পারে ("আমি example.com" — এটা declare করা তো সহজ)। তাহলে client কীভাবে জানে এটা fake না?
উত্তর: Digital Signature Chain-এর মাধ্যমে বিশ্বাসযোগ্যতা তৈরি করা হয় — এবং এই chain-এর একদম উপরে থাকে এমন কিছু যাকে সবাই আগে থেকেই বিশ্বাস করে (browser/OS-এ pre-installed)।
Certificate Chain-এর গঠন
┌─────────────────────────────────────────┐
│ Root CA Certificate │ ← self-signed
│ (যেমন DigiCert Global Root) │ browser/OS-এ pre-installed,
│ │ "বিশ্বাসযোগ্য" ধরে নেওয়া হয়
└───────────────┬───────────────────────────┘
│ signs (তার private key দিয়ে)
▼
┌─────────────────────────────────────────┐
│ Intermediate CA Certificate │
│ (Root-এর তুলনায় বেশি ব্যবহৃত হয়, │
│ Root-কে অফলাইনে/নিরাপদে রাখার জন্য) │
└───────────────┬───────────────────────────┘
│ signs
▼
┌─────────────────────────────────────────┐
│ Leaf/Server Certificate │
│ (example.com-এর নিজের certificate, │
│ এটাই actual TLS handshake-এ পাঠানো হয়) │
└─────────────────────────────────────────┘
Client কীভাবে verify করে (ধাপে ধাপে)
- Server তার leaf certificate পাঠায়, সাথে সাধারণত intermediate certificate-ও পাঠায় (যাতে client-কে আলাদা করে fetch করতে না হয়)
- Client leaf certificate-এর signature verify করে intermediate CA-এর public key দিয়ে (এই public key intermediate certificate-এই থাকে)
- Client intermediate certificate-এর signature verify করে root CA-এর public key দিয়ে
- Client দেখে root CA কি তার trusted root store-এ আছে কিনা (browser/OS-এ আগে থেকেই কয়েকশ trusted root বিল্ট-ইন থাকে)
- যদি পুরো chain valid হয় এবং root trusted হয় → certificate বিশ্বাসযোগ্য
মূল ইনসাইট: বিশ্বাসের পুরো ভিত্তি হলো "root CA-কে আগে থেকেই বিশ্বাস করা হয়" — এটাকে বলে "trust anchor"। যদি কোনোভাবে একটা fake root CA browser-এ ইনস্টল হয়ে যায় (যেমন malware দিয়ে), তাহলে সেই root দিয়ে সাইন করা যেকোনো fake certificate-ও বিশ্বাসযোগ্য মনে হবে — এটাই একটা বড় নিরাপত্তা ঝুঁকির উৎস।
কেন Intermediate CA দরকার (Root CA সরাসরি sign করলেই তো হতো?)
Root CA private key অত্যন্ত সংবেদনশীল — যদি এটা leak হয়, সারা পৃথিবীর সব certificate যেগুলো এই root দিয়ে (সরাসরি বা পরোক্ষভাবে) sign করা, সব অবিশ্বাস্য হয়ে যায়। তাই Root CA সাধারণত:
- খুব কম ব্যবহার হয় (শুধু intermediate CA sign করতে)
- অফলাইনে, অত্যন্ত সুরক্ষিতভাবে সংরক্ষিত থাকে (HSM — Hardware Security Module-এ, air-gapped)
Intermediate CA দৈনন্দিন কাজ করে (actual server certificate sign করা)। যদি একটা intermediate CA compromise হয়, সেটা revoke করা যায় Root CA দিয়ে — বাকি system প্রভাবিত হয় না, ক্ষতি সীমিত থাকে। এটাই "blast radius" কমানোর একটা ক্লাসিক ডিজাইন প্যাটার্ন (তোমার reliability engineering মানসিকতার সাথে সরাসরি মিলে যায় — bulkhead pattern-এর মতোই একটা ধারণা, Phase 8-তে আমরা এটা আবার দেখবো)।
Certificate-এ কী কী তথ্য থাকে
| ফিল্ড | মানে |
|---|---|
| Subject | কার জন্য certificate (যেমন CN=example.com) |
| Subject Alternative Names (SAN) | কোন কোন domain-এর জন্য valid (যেমন example.com, www.example.com, *.example.com) |
| Issuer | কোন CA এটা sign করেছে |
| Validity Period | কবে থেকে কবে পর্যন্ত valid |
| Public Key | সার্ভারের public key (যেটা দিয়ে TLS handshake-এ signature verify হয়) |
| Signature | issuer CA-এর private key দিয়ে বানানো signature |
Certificate Revocation — যদি একটা certificate compromise হয়ে যায়
Certificate expire হওয়ার আগেই যদি কোনো কারণে (private key leak) সেটা অবৈধ ঘোষণা করতে হয়:
- CRL (Certificate Revocation List): CA একটা লিস্ট প্রকাশ করে সব revoke হওয়া certificate-এর — client এটা download করে চেক করে (কিন্তু বড় লিস্ট, ধীর)
- OCSP (Online Certificate Status Protocol): client CA-কে সরাসরি জিজ্ঞেস করে "এই নির্দিষ্ট certificate কি valid?" (দ্রুত কিন্তু প্রতিটা connection-এ extra network call, privacy concern-ও আছে কারণ CA জানে তুমি কোন সাইট visit করছো)
- OCSP Stapling: server নিজেই নিয়মিত CA থেকে একটা "fresh" OCSP response নিয়ে রাখে এবং TLS handshake-এর সময় client-কে সেটা "staple" করে পাঠিয়ে দেয় — client-কে আলাদা করে CA-কে জিজ্ঞেস করতে হয় না। এটা দ্রুততর এবং privacy-friendly, তাই আধুনিক প্রোডাকশন সিস্টেমে এটাই সুপারিশকৃত পদ্ধতি।
পার্ট ৫ — mTLS (Mutual TLS): দুই দিকেই পরিচয় যাচাই
সাধারণ TLS-এর সীমাবদ্ধতা
স্বাভাবিক TLS-এ শুধু server নিজের identity প্রমাণ করে certificate দিয়ে। Client-এর কোনো cryptographic identity verify হয় না TLS layer-এ (client authentication হয় application layer-এ, যেমন username/password, API key, বা OAuth token দিয়ে — Day 173-এ বিস্তারিত)।
এটা browser-server-এর মতো ক্ষেত্রে ঠিক আছে (মানুষ password দিয়ে নিজেকে প্রমাণ করে)। কিন্তু service-to-service communication-এ (microservices-এর মধ্যে) — কে কার সাথে কথা বলছে সেটা cryptographically নিশ্চিত হওয়া দরকার, শুধু network-level trust (যেমন "এই IP internal network-এর, তাই বিশ্বাসযোগ্য") যথেষ্ট না, বিশেষ করে zero-trust architecture-এ (Day 173)।
mTLS-এ কী আলাদা
Client Server
│ ClientHello │
│ ──────────────────────────────────────────────────→ │
│ │
│ ServerHello, {Certificate (server)}, │
│ {CertificateRequest} ← "তোমার certificate দাও" │
│ ←────────────────────────────────────────────────── │
│ │
│ {Certificate (client)}, │
│ {CertificateVerify (client signs)}, │
│ {Finished} │
│ ──────────────────────────────────────────────────→ │
│ │
│ {Finished} │
│ ←────────────────────────────────────────────────── │
Server একটা CertificateRequest পাঠায়, client নিজের certificate পাঠায় এবং সেটা নিজের private key দিয়ে sign করে প্রমাণ করে সে সেই certificate-এর মালিক — ঠিক server যেভাবে করে সাধারণ TLS-এ।
mTLS কোথায় ব্যবহার হয় (Day 11-এর Service Mesh-এর সাথে সরাসরি সংযোগ)
- Service Mesh (Envoy sidecar): প্রতিটা microservice-এর নিজস্ব certificate (identity) থাকে, sidecar proxy স্বয়ংক্রিয়ভাবে mTLS দিয়ে সব internal traffic secure করে — application code-কে TLS নিয়ে ভাবতেই হয় না
- B2B API access: একটা কোম্পানি আরেকটা কোম্পানির API ব্যবহার করলে, শুধু API key যথেষ্ট না মনে হলে mTLS দিয়ে দুই পক্ষের identity নিশ্চিত করা হয় (payment industry-তে খুব প্রচলিত)
- IoT device authentication: প্রতিটা device-এর নিজস্ব certificate থাকে, server device-কে identify করে certificate দিয়ে (username/password-এর চেয়ে বেশি secure এবং scalable বিপুল সংখ্যক device-এর জন্য)
- Zero Trust Architecture: "network-এর ভেতরে আছো মানেই বিশ্বাসযোগ্য" এই ধারণা বাতিল করে প্রতিটা service-to-service call-এ cryptographic verification বাধ্যতামূলক করা
mTLS-এর অপারেশনাল challenge (ইন্টারভিউতে বলার মতো গুরুত্বপূর্ণ পয়েন্ট)
mTLS চালু করলে একটা বড় challenge হলো certificate lifecycle management — শত শত/হাজার হাজার service instance-এর জন্য certificate issue, rotate, revoke করা ম্যানুয়ালি অসম্ভব। এইজন্য:
- Short-lived certificate (কয়েক ঘণ্টা বা দিনের validity, বছর না) — automated rotation দিয়ে ক্রমাগত renew হয়, compromise হলেও ক্ষতির সময় সীমিত
- SPIFFE/SPIRE এর মতো টুল — automated identity issuance এবং rotation framework, service mesh-এ ব্যাপক ব্যবহৃত
পার্ট ৬ — TLS Termination Strategy: Architecture-এ কোথায় Decrypt করবে
এটা একটা ক্লাসিক system design প্রশ্ন — Day 10 (Load Balancer)-এর সাথে সরাসরি যুক্ত।
Option ১: TLS Termination at Load Balancer
Client --[TLS]--> Load Balancer --[Plain HTTP]--> Backend Servers
- সুবিধা: Backend সার্ভারগুলোর CPU-তে encryption/decryption-এর চাপ পড়ে না (LB-তেই centralize হয়); certificate management শুধু LB-তে করলেই হয়
- অসুবিধা: LB থেকে backend পর্যন্ত ট্রাফিক unencrypted — যদি internal network compromise হয় (বা compliance-এর কারণে দরকার হয়), এটা ঝুঁকিপূর্ণ
Option ২: TLS Passthrough (LB শুধু route করে, decrypt করে না)
Client --[TLS, unmodified]--> Load Balancer (L4, শুধু routing) --[TLS]--> Backend Servers (decrypt এখানে হয়)
- সুবিধা: End-to-end encryption বজায় থাকে; LB কে certificate নিয়ে ভাবতেই হয় না
- অসুবিধা: LB content দেখতে পারে না (তাই L7 routing, যেমন path-based routing, সম্ভব না — শুধু L4 routing); প্রতিটা backend-কে নিজস্ব certificate manage করতে হয়
Option ৩: TLS Re-encryption (End-to-End with LB visibility)
Client --[TLS #1]--> Load Balancer (decrypt, inspect) --[TLS #2, নতুন handshake]--> Backend Servers
- সুবিধা: LB-তে L7 routing সম্ভব (path-based, header-based) এবং backend পর্যন্ত ট্রাফিক encrypted থাকে
- অসুবিধা: সবচেয়ে বেশি CPU cost (দুইবার TLS handshake/encryption), সবচেয়ে জটিল certificate management (LB-তে এবং প্রতিটা backend-এ)
- কখন দরকার: PCI-DSS, HIPAA-এর মতো কড়া compliance যেখানে internal network-এও encryption বাধ্যতামূলক (payment/ledger system, Day 134-137-এর সাথে সরাসরি প্রাসঙ্গিক)
Decision Framework
| Scenario | Recommended Strategy |
|---|---|
| Internal network trusted, cost sensitive | TLS termination at LB |
| L7 routing দরকার + compliance দরকার (payment) | Re-encryption |
| LB-কে content দেখানো একদমই উচিত না (high-security) | Passthrough |
পার্ট ৭ — সব একসাথে: একটা সম্পূর্ণ Request Journey (Numbers সহ)
ধরো একজন ইউজার ঢাকা থেকে একটা US-based e-commerce সাইটে (payment flow সহ) প্রথমবার visit করছে (RTT ~ 200ms cross-continent):
1. DNS Resolution (Day 8) ~20-100ms (cache miss হলে)
2. TCP Handshake (Day 4) 1 RTT ≈ 200ms
3. TLS 1.3 Handshake (fresh, no resumption) 1 RTT ≈ 200ms
├── ClientHello পাঠানো
├── Server Certificate + Chain verify
│ (root CA আগে থেকেই browser-এ trusted)
└── Shared symmetric key negotiate হলো
4. Application Data (HTTPS request/response) 1 RTT ≈ 200ms
─────────────
Total ≈ 600-700ms (প্রথম বাইট পেতে)
দ্বিতীয়বার visit করলে (session resumption সহ):
1. DNS (cached) ~0ms
2. TCP Handshake 1 RTT ≈ 200ms
3. TLS 1.3 Resumption (PSK, 0-RTT possible) 0-1 RTT ≈ 0-200ms
4. Application Data 1 RTT ≈ 200ms
─────────────
Total ≈ 200-400ms (প্রায় অর্ধেক!)
যদি QUIC/HTTP-3 ব্যবহার করা হয় (Day 5):
1. DNS (cached) ~0ms
2. QUIC handshake (TCP+TLS combined) 1 RTT (fresh) বা 0-RTT (repeat)
3. Application Data included in handshake বা 1 RTT
─────────────
Total ≈ 200ms (fresh) বা কম (repeat)
Payment step-এ (mTLS দিয়ে backend payment gateway-এর সাথে communication):
- Internal microservice call (checkout service → payment service) mTLS দিয়ে secure করা হবে, যাতে শুধু authorized service-ই payment gateway-কে access করতে পারে
- এই certificate short-lived (কয়েক ঘণ্টার validity), automated rotation (SPIFFE/SPIRE-এর মতো টুল দিয়ে)
- TLS termination strategy হবে re-encryption (compliance-এর কারণে, পার্ট ৬)
পার্ট ৮ — Consolidation: Interview-Style প্রশ্ন
নিজে নিজে (নোট ছাড়া, জোরে বলে) উত্তর দেওয়ার চেষ্টা করো:
- TLS-এর তিনটা মূল গ্যারান্টি কী কী (পার্ট ০), এবং প্রতিটার জন্য কোন মেকানিজম দায়ী (encryption/MAC/certificate)?
- Symmetric আর asymmetric encryption কেন একসাথে ব্যবহার করা হয় TLS-এ, আলাদা আলাদা না?
- TLS 1.3 কেন TLS 1.2-এর চেয়ে দ্রুত (RTT সংখ্যায় ব্যাখ্যা করো, Day 4-এর TCP handshake-এর সাথে মিলিয়ে মোট cost বের করো)।
- Certificate chain-এ Root CA আর Intermediate CA আলাদা রাখার মূল কারণ কী (blast radius প্রসঙ্গে)?
- Session resumption-এ 0-RTT data কেন idempotent request-এর জন্যই নিরাপদ?
- mTLS সাধারণ TLS থেকে ঠিক কীভাবে আলাদা, এবং Service Mesh (Day 11)-এ এটা কেন প্রয়োজনীয়?
- তোমার একটা payment-related সিস্টেমে TLS termination strategy কী হবে, এবং কেন LB-তে simple termination যথেষ্ট না?
- mTLS-এ certificate lifecycle management কেন একটা বড় অপারেশনাল challenge, এবং short-lived certificate + automated rotation কীভাবে এটা সমাধান করে?
Day 7 · HTTP/1.1 → HTTP/2 → HTTP/3, head-of-line blocking
পার্ট ০ — Day 4-6 থেকে সংযোগ: এখন পর্যন্ত আমরা কী শিখেছি
এই পর্যন্ত আমরা transport এবং security layer শিখেছি:
- Day 4: TCP কীভাবে reliable byte-stream দেয়, কিন্তু connection ধীরে "warm up" হয় (slow start)
- Day 5: UDP/QUIC কীভাবে transport-লেভেলে independent stream এবং দ্রুত handshake দেয়
- Day 6: TLS কীভাবে secure channel বানায়, এবং এটার নিজস্ব RTT cost আছে
আজকে আমরা Application Layer-এ উঠবো — HTTP প্রোটোকল, যেটা সরাসরি এই সব নিচের layer-এর উপর বসে ব্যবহার করে actual request/response পাঠাতে। HTTP-এর বিবর্তনের পুরো গল্পটাই আসলে একটাই সমস্যা সমাধানের চেষ্টা: "একটা connection দিয়ে যতটা সম্ভব দ্রুত, যতটা সম্ভব বেশি request-response চালানো, নিচের layer-এর সীমাবদ্ধতাগুলোর মধ্যে থেকে।"
পার্ট ১ — HTTP/1.0 এবং HTTP/1.1: শুরুর সমস্যা
HTTP/1.0 — প্রতিটা Request-এর জন্য নতুন Connection
HTTP/1.0-এ ডিফল্ট আচরণ ছিল: প্রতিটা request-response-এর পর connection বন্ধ হয়ে যেত। পরের request-এর জন্য আবার নতুন TCP connection বানাতে হতো।
সমস্যাটা Day 4-এর জ্ঞান দিয়ে বুঝি: প্রতিটা নতুন connection মানে —
- নতুন 3-way handshake (1 RTT)
- (HTTPS হলে) নতুন TLS handshake (Day 6, আরও 1-2 RTT)
- নতুন slow start থেকে শুরু (Day 4 পার্ট ৪) — connection কখনো "warm" হওয়ার সুযোগই পায় না
একটা সাধারণ ওয়েবপেজে যদি ২০টা resource (HTML, CSS, JS, images) থাকে, HTTP/1.0-এ এর মানে ২০ বার সম্পূর্ণ handshake cycle — ভয়াবহ ধীর, বিশেষ করে high-latency নেটওয়ার্কে।
HTTP/1.1 — Persistent Connection (Keep-Alive)
HTTP/1.1 ডিফল্টভাবে connection: keep-alive চালু করলো — মানে একটা TCP connection একাধিক request-response-এর জন্য পুনর্ব্যবহার করা যায়, প্রতিবার নতুন করে বানাতে হয় না।
HTTP/1.0 (প্রতি request নতুন connection):
[Handshake][Req1][Res1][Close]
[Handshake][Req2][Res2][Close]
[Handshake][Req3][Res3][Close]
HTTP/1.1 (persistent connection):
[Handshake][Req1][Res1][Req2][Res2][Req3][Res3][Close]
এটা Day 4-এর "connection reuse" আলোচনার সাথে সরাসরি মিলে যায় — একবার handshake করে connection warm রেখে, বারবার নতুন cost এড়ানো।
কিন্তু HTTP/1.1-এও একটা মৌলিক সীমাবদ্ধতা রয়ে গেলো: Head-of-Line Blocking (Application Level)
HTTP/1.1-এ একটা connection-এ একবারে মাত্র একটাই request "in-flight" থাকতে পারে (strictly speaking) — মানে Request 2 পাঠানোর আগে Request 1-এর সম্পূর্ণ Response আসা পর্যন্ত অপেক্ষা করতে হয় (একই connection-এ)।
একই connection-এ:
Req1 ──────→
←────── Res1 (সম্পূর্ণ আসা পর্যন্ত অপেক্ষা)
Req2 ──────→
←────── Res2
যদি Response 1 কোনো কারণে ধীর হয় (যেমন একটা ভারী database query), Response 2, 3, 4 সবাই লাইনে দাঁড়িয়ে থাকে, যদিও তাদের ডেটা হয়তো আগেই প্রস্তুত। এটাকে বলে Head-of-Line (HOL) Blocking — লাইনের সামনের একজন ধীর হলে পেছনের সবাই আটকে যায়, ঠিক যেন একটা supermarket-এর সিঙ্গেল queue-তে একজন কাস্টমারের অনেক সময় লাগলে পুরো লাইন থেমে থাকে।
Pipelining — একটা ব্যর্থ সমাধান: HTTP/1.1 স্পেসিফিকেশনে "pipelining" নামে একটা ফিচার ছিল — client একাধিক request পরপর পাঠিয়ে দিতে পারতো response-এর জন্য অপেক্ষা না করেই। কিন্তু response অবশ্যই সেই একই order-এই ফিরতে হতো যেই order-এ request পাঠানো হয়েছিল — তাই যদি প্রথম response ধীর হয়, বাকি সব response, যদিও হয়তো ইতিমধ্যে প্রস্তুত, client-এর কাছে delivered হতে পারে না। এছাড়া অনেক proxy/server pipelining সঠিকভাবে handle করতো না (বাগ ছিল), তাই বাস্তবে browser-রা এটা কখনো ডিফল্টভাবে চালু করেনি।
Browser-দের "সমাধান": Multiple Parallel Connections
যেহেতু একটা connection-এ একবারে একটা request, browser-রা practical সমাধান হিসেবে একই domain-এর সাথে একাধিক (সাধারণত ৬টা পর্যন্ত) parallel TCP connection খুলতে শুরু করলো।
সমস্যা:
- প্রতিটা connection-এর নিজস্ব handshake cost, নিজস্ব slow start (Day 4) — তাই resource-গুলো ভাগ করে দিলেও প্রতিটা connection-ই ধীরগতিতে শুরু করে
- Server-এ connection-এর সংখ্যা বেড়ে যায় (প্রতি client ৬টা করে) — বেশি মেমোরি/CPU খরচ
- ৬টার বেশি resource parallel-এ লোড করা যায় না per domain — এইজন্য ওয়েবসাইট-রা "domain sharding" করতো (একই সাইটের resource-গুলো বিভিন্ন subdomain-এ ছড়িয়ে রাখা, যেমন img1.example.com, img2.example.com), যাতে browser আরও বেশি connection খুলতে পারে — কিন্তু এতে আরও বেশি DNS lookup + handshake, একটা সমস্যা সমাধান করতে গিয়ে নতুন ওভারহেড তৈরি হলো
🎯 পার্ট ১-এর Active Recall
- HTTP/1.0-এ প্রতিটা request-এর জন্য নতুন connection বানানোর hidden cost কী কী (Day 4-এর জ্ঞান ব্যবহার করে)?
- HTTP/1.1-এর Head-of-Line blocking ঠিক কোন স্তরে ঘটে (application না transport)?
- Pipelining কেন বাস্তবে ব্যবহার হয়নি, যদিও স্পেসিফিকেশনে ছিল?
- Domain sharding সমাধান কী নতুন সমস্যা তৈরি করে?
পার্ট ২ — HTTP/2: Multiplexing দিয়ে Application-Level HOL Blocking সমাধান
মূল ধারণা: একটা Connection-এ Multiple Concurrent Streams
HTTP/2-এর কেন্দ্রীয় উদ্ভাবন হলো multiplexing — একটা মাত্র TCP connection-এর ভেতর দিয়ে একাধিক request-response একসাথে, ইন্টারলিভড হয়ে চলতে পারে, কোনোটা কোনোটার জন্য অপেক্ষা না করেই।
HTTP/1.1 (একই connection, sequential):
[──Req1──][──Res1──][──Req2──][──Res2──]
HTTP/2 (একই connection, multiplexed streams):
Stream 1: [Req1]........[Res1 data............]
Stream 2: [Req2][Res2 data......]
Stream 3: [Req3][Res3 data.]
(সব একই connection-এ, ইন্টারলিভড ফ্রেম আকারে)
কীভাবে এটা কাজ করে — Frames এবং Streams
HTTP/2 ডেটাকে ছোট ছোট binary frame-এ ভাগ করে (HTTP/1.1-এর মতো plain text protocol না — এটা একটা বড় পরিবর্তন, parsing দ্রুততর এবং কম error-prone করে তোলে)। প্রতিটা frame-এর একটা Stream ID থাকে, যেটা বলে দেয় এটা কোন request/response-এর অংশ।
Connection-এর ভেতর দিয়ে যাওয়া raw frame sequence:
[Stream 1: HEADERS] [Stream 3: HEADERS] [Stream 1: DATA]
[Stream 3: DATA] [Stream 1: DATA (শেষ)] [Stream 3: DATA (শেষ)]
Receiver এই frame-গুলোকে Stream ID অনুযায়ী পুনরায় একত্র করে সঠিক request/response-এ। এই মেকানিজমের কারণে server একই সাথে একাধিক request প্রসেস করে response frame পাঠাতে পারে, ইন্টারলিভড ভাবে — কোনো response-কে অন্য response-এর সম্পূর্ণ হওয়ার জন্য অপেক্ষা করতে হয় না।
Stream Prioritization
HTTP/2-এ client প্রতিটা stream-এর একটা priority নির্ধারণ করতে পারে (যেমন: CSS/JS ফাইল বেশি priority, নিচের দিকের image কম priority) — server এই priority অনুযায়ী bandwidth allocate করার চেষ্টা করে। এটা page rendering দ্রুত করতে সাহায্য করে, কারণ critical resource আগে আসে।
Header Compression (HPACK)
HTTP request-এ প্রতিবার প্রায় একই header পাঠানো হয় (User-Agent, Cookie, Accept-Language ইত্যাদি) — এগুলো repetitive এবং বেশ বড় (Cookie হেডার কখনো কখনো কয়েক KB পর্যন্ত হতে পারে)।
HPACK এই headers কে compress করে দুইভাবে:
- Static table: সাধারণ common header (যেমন
:method: GET,content-type) pre-defined index দিয়ে রেফার করা হয়, পুরো টেক্সট না পাঠিয়ে - Dynamic table: connection-এর জীবনে একবার পাঠানো header পরের বার শুধু একটা ছোট index reference দিয়ে পাঠানো যায় (পুরো header আবার পাঠানোর দরকার নেই)
Practical impact: বিশেষ করে API-heavy application-এ (একই headers বারবার পাঠানো), HPACK headers-এর সাইজ উল্লেখযোগ্যভাবে কমিয়ে দেয়, bandwidth বাঁচায়।
Server Push (এখন প্রায় deprecated, কিন্তু বোঝা জরুরি কেন)
HTTP/2-এ একটা ফিচার ছিল "Server Push" — server client-এর request না করা resource-ও proactively পাঠিয়ে দিতে পারতো (যেমন client HTML request করলে, server অনুমান করে সাথে CSS/JS ফাইলও push করে দিতো, client আলাদা করে request করার আগেই)।
কেন এটা deprecated হয়ে গেলো (Chrome, ইত্যাদি এখন সাপোর্ট বন্ধ করেছে): বাস্তবে দেখা গেলো —
- Server-এর অনুমান প্রায়ই ভুল হতো (client-এর browser cache-এ হয়তো ইতিমধ্যে resource ছিল, কিন্তু server সেটা জানতো না এবং তাও push করতো — bandwidth নষ্ট)
- Implementation জটিলতা এবং debugging কঠিন
- HTTP/103 Early Hints নামে একটা সহজ বিকল্প এসেছে, যেটা server-কে বলতে দেয় "এই resource-গুলো লাগবে" কিন্তু client নিজে decide করে fetch করবে কিনা (browser cache respect করে)
ইন্টারভিউ ইনসাইট: এটা একটা ভালো উদাহরণ যে "থিওরিটিক্যালি ভালো আইডিয়া" বাস্তব ব্যবহারে সবসময় কাজ নাও করতে পারে — production feedback থেকে শেখা এবং ফিচার সরিয়ে ফেলার সিদ্ধান্তও একটা ভালো ইঞ্জিনিয়ারিং সিদ্ধান্ত।
HTTP/2-এর সমস্যা যেটা এখনো থেকে যায়: TCP-Level HOL Blocking
HTTP/2 application-level HOL blocking সমাধান করলো — কিন্তু এটা এখনো TCP-এর উপর চলে। Day 4-এ আমরা শিখেছি TCP একটা single ordered byte-stream গ্যারান্টি করে।
এখানেই সমস্যা: HTTP/2-এর multiple stream আসলে application-level ধারণা — কিন্তু নিচে TCP এই সব stream-এর ডেটাকে একটাই linear byte sequence হিসেবে দেখে। যদি এই byte sequence-এর মাঝখানে একটা প্যাকেট হারিয়ে যায় (যেটা হয়তো Stream 3-এর একটা অংশ ছিল), TCP-এর নিয়ম অনুযায়ী পুরো stream-এর পরের সব বাইট (Stream 1, Stream 2 সহ, যেগুলো হয়তো সেই হারানো প্যাকেটের পরে এসেছিল) receiver application-এ ডেলিভার হতে পারে না, যতক্ষণ না হারানো প্যাকেট retransmit হয়ে আসে।
TCP byte stream (multiple HTTP/2 stream interleaved):
[S1 data][S2 data][S3 data - LOST][S1 data][S2 data]
│
▼
TCP বলে: "এই bytes-এর পরে যা আছে তা receiver-কে
দেওয়া যাবে না, যতক্ষণ না LOST অংশ পুনরায় আসে"
│
▼
ফলাফল: S1 এবং S2-এর পরের ডেটা, যদিও নেটওয়ার্কে
ইতিমধ্যে পৌঁছেছে, application এখনো দেখতে পাচ্ছে না
এটাই "TCP-level Head-of-Line Blocking" — application layer (HTTP/2) সমস্যা সমাধান করেছে, কিন্তু transport layer (TCP)-এ একই সমস্যা রয়ে গেছে, এবং এটাই HTTP/3-এর জন্মের মূল কারণ।
🎯 পার্ট ২-এর Active Recall
- HTTP/2 multiplexing কীভাবে কাজ করে (Frame এবং Stream ID concept ব্যবহার করে ব্যাখ্যা করো)?
- HPACK header compression কীভাবে bandwidth বাঁচায় — static table আর dynamic table-এর পার্থক্য কী?
- Server Push কেন deprecated হয়ে গেলো, এবং Early Hints কীভাবে ভিন্ন approach নেয়?
- HTTP/2 application-level HOL blocking সমাধান করলেও কেন TCP-level HOL blocking থেকে যায় — mechanism-সহ ব্যাখ্যা করো।
পার্ট ৩ — HTTP/3: QUIC-এর উপর HTTP (Day 5-এর জ্ঞান এখানে কাজে লাগবে)
মূল পরিবর্তন: Transport বদলানো, Semantics না
গুরুত্বপূর্ণ ভুল ধারণা দূর করি: HTTP/3 কোনো নতুন request/response model বা নতুন header format নিয়ে আসেনি। এটা মূলত HTTP/2-এর multiplexing ধারণাকেই, কিন্তু TCP-এর বদলে QUIC (Day 5)-এর উপর বসিয়েছে।
HTTP/1.1 → TCP (single connection, sequential)
HTTP/2 → TCP (multiplexed streams, TCP-level HOL blocking থেকে যায়)
HTTP/3 → QUIC (UDP-ভিত্তিক) (multiplexed streams, transport-level ও independent)
কীভাবে HTTP/3 TCP-Level HOL Blocking সমাধান করে
Day 5-এ আমরা শিখেছি QUIC-এর প্রতিটা stream সত্যিকার independent — একটা stream-এর packet loss শুধু সেই stream-কেই প্রভাবিত করে, কারণ QUIC নিজেই স্ট্রিম-সচেতন transport layer, TCP-এর মতো একটামাত্র linear byte-stream না।
QUIC-এর ভেতর multiple HTTP/3 streams:
Stream 1: [pkt1][pkt2][LOST][pkt4] ←── শুধু Stream 1 প্রভাবিত, wait করছে
Stream 2: [pkt1][pkt2][pkt3] ←── সম্পূর্ণ, নির্বিঘ্নে ডেলিভার হয়ে গেছে
Stream 3: [pkt1][pkt2] ←── চলতে থাকে, প্রভাবিত না
এটাই মূল পার্থক্য HTTP/2 vs HTTP/3-এর মধ্যে: উভয়ই "multiplexing" শব্দ ব্যবহার করে, কিন্তু HTTP/2-এর multiplexing শুধু application layer-এ conceptual (নিচে TCP একটাই stream হিসেবে দেখে), আর HTTP/3-এর multiplexing transport layer পর্যন্ত সত্যিকারভাবে independent (QUIC নিজেই প্রতিটা stream আলাদাভাবে ট্র্যাক করে)।
HTTP/3-এর অন্যান্য সুবিধা (Day 5-6 থেকে সরাসরি প্রযোজ্য)
- দ্রুততর handshake: QUIC + TLS 1.3 combined handshake, 1 RTT (fresh) বা 0-RTT (repeat) — Day 5-6-এর হিসেব এখানে সরাসরি প্রযোজ্য
- Connection Migration: mobile network switching-এ connection টিকে থাকে (Day 5) — HTTP/3-এ এটার মানে হলো, WiFi থেকে mobile data-এ switch করলেও তোমার browsing session/download বিঘ্নিত হয় না
- Mandatory encryption: QUIC-এ TLS 1.3 built-in এবং বাধ্যতামূলক — HTTP/3-এ কোনো "unencrypted" ভার্সন নেই (HTTP/1.1, HTTP/2-এ যেমন ছিল)
Header Compression: QPACK (HPACK-এর replacement)
HTTP/2-এর HPACK compression stream-এর মধ্যে ordering-এর উপর নির্ভরশীল ছিল (dynamic table entry নির্দিষ্ট ক্রমে আসতে হতো)। কিন্তু QUIC-এ যেহেতু stream-গুলো independent এবং out-of-order আসতে পারে, HPACK সরাসরি ব্যবহার করলে নিজেই একটা নতুন HOL blocking সমস্যা তৈরি হতো (একটা stream-এর header table update-এর জন্য অন্য stream অপেক্ষা করতে বাধ্য হতো)।
তাই HTTP/3-এর জন্য QPACK ডিজাইন করা হলো — যেটা compression efficiency বজায় রেখেও stream-independence নষ্ট না করে কাজ করে (একটা আলাদা, dedicated "control stream" ব্যবহার করে table update synchronize করতে, কিন্তু কোনো stream সরাসরি অন্য stream-এর table update-এর জন্য block হয় না)।
এটা একটা চমৎকার ইঞ্জিনিয়ারিং ইনসাইট: একটা লেয়ারের সমস্যা (TCP HOL blocking) সমাধান করতে গিয়ে, ওপরের লেয়ারের একটা optimization (HPACK)-ও নতুন করে ডিজাইন করতে হলো, কারণ সেটার নিজস্ব assumption (ordered delivery) নতুন transport-এর সাথে খাপ খাচ্ছিল না।
🎯 পার্ট ৩-এর Active Recall
- HTTP/3 কি নতুন কোনো HTTP semantics নিয়ে এসেছে, নাকি existing মডেল নতুন transport-এ বসিয়েছে?
- HTTP/2-এর "multiplexing" আর HTTP/3-এর "multiplexing"-এর মধ্যে ঠিক কোন স্তরে পার্থক্য (application vs transport)?
- QPACK কেন HPACK-এর মতো সরাসরি ব্যবহার করা গেলো না QUIC-এর সাথে?
পার্ট ৪ — সম্পূর্ণ তুলনা এবং সারাংশ
সব প্রোটোকল একসাথে (এই টেবিলটা মুখস্থের মতো রাখো)
| ফিচার | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| Transport | TCP | TCP | QUIC (UDP-ভিত্তিক) |
| Data Format | Plain text | Binary frames | Binary frames (QUIC-এ) |
| Multiplexing | নেই (এক connection, এক request at a time) | আছে (stream-ভিত্তিক, application layer) | আছে (stream-ভিত্তিক, transport layer পর্যন্ত true independent) |
| HOL Blocking | আছে (application level) | আছে (TCP level, একটা loss সব stream আটকায়) | নেই (per-stream independent) |
| Header Compression | নেই | HPACK | QPACK |
| Handshake (fresh, HTTPS সহ) | TCP + TLS আলাদা (~2-3 RTT) | TCP + TLS আলাদা (~2-3 RTT) | Combined (~1 RTT) |
| Connection Migration | নেই | নেই | আছে (QUIC Connection ID) |
| Encryption | Optional | Optional (কার্যত সবসময় TLS সহ ব্যবহৃত হয়) | বাধ্যতামূলক |
| Server Push | নেই | ছিল, এখন deprecated | নেই (Early Hints ব্যবহার হয়) |
HOL Blocking-এর তিন স্তর — সবচেয়ে গুরুত্বপূর্ণ কনসেপ্ট, আবার সংক্ষেপে
স্তর ১: Application-Level HOL Blocking (HTTP/1.1-এ)
→ একটা connection-এ একটা request সম্পূর্ণ শেষ না হলে পরেরটা শুরু হয় না
→ সমাধান: HTTP/2 (multiplexing)
স্তর ২: Transport-Level HOL Blocking (HTTP/2-এ, TCP-এর কারণে)
→ একটা TCP segment হারালে, connection-এর সব stream আটকে যায়
→ সমাধান: HTTP/3 (QUIC, independent streams)
স্তর ৩: বাকি কোনো HOL blocking নেই HTTP/3-এ transport লেভেলে
(প্রতিটা stream সত্যিই independent)
একটা সাধারণ ভুল যেটা এড়ানো উচিত ইন্টারভিউতে
"HTTP/2 multiplexing করে, তাই HOL blocking সমস্যা নেই" — এই statement টা অসম্পূর্ণ এবং বিভ্রান্তিকর। সঠিক বলা উচিত: "HTTP/2 application-level HOL blocking সমাধান করেছে, কিন্তু এটা TCP-এর উপর চলার কারণে transport-level HOL blocking এখনো থেকে যায় — এই সমস্যার সম্পূর্ণ সমাধান HTTP/3 (QUIC-ভিত্তিক) দিয়েই এসেছে।"
পার্ট ৫ — একটা প্র্যাকটিক্যাল কেস স্টাডি: কখন কোন Protocol Version-এ কী প্রভাব পড়ে
উদাহরণ ১: একটা ভালো নেটওয়ার্কে (কম packet loss, যেমন wired broadband)
- HTTP/1.1: multiple parallel connection দিয়ে কাজ চালানো যায়, কিন্তু handshake overhead সবচেয়ে বেশি
- HTTP/2: significant উন্নতি, একটা connection দিয়েই সব resource multiplexed, HOL blocking rarely trigger হয় কারণ packet loss কম
- HTTP/3: সামান্য উন্নতি HTTP/2-এর চেয়ে (কারণ ভালো নেটওয়ার্কে loss rare, তাই TCP-level HOL blocking এমনিতেই কম ঘটে) — মূল সুবিধা এখানে দ্রুত handshake
উদাহরণ ২: একটা lossy mobile নেটওয়ার্কে (উচ্চ packet loss rate)
- HTTP/1.1: ধীর, কারণ বেশি connection, বেশি handshake, এবং প্রতিটা connection আলাদাভাবে loss handle করে
- HTTP/2: এখানে সমস্যা সবচেয়ে প্রকট হয় — একটাই connection, তাই একটা loss পুরো multiplexed traffic আটকে দেয় — অনেক ক্ষেত্রে দেখা গেছে lossy নেটওয়ার্কে HTTP/2 আসলে HTTP/1.1-এর multiple-connection approach-এর চেয়েও খারাপ পারফর্ম করে (কারণ HTTP/1.1-এর একাধিক connection-এ, একটা connection-এ loss হলে অন্য connection-গুলো প্রভাবিত হয় না, defacto একটা "independent stream"-এর মতো আচরণ করে!)
- HTTP/3: সবচেয়ে ভালো পারফর্ম করে — QUIC-এর per-stream independence loss-এর প্রভাব সীমিত রাখে, এবং BBR-জাতীয় congestion control (Day 4) lossy নেটওয়ার্কেও ভালো throughput বজায় রাখে
এটাই একটা চমৎকার ইন্টারভিউ ইনসাইট: "নতুন protocol সবসময় পুরনোটার চেয়ে ভালো" এটা সরল সত্য না — network condition অনুযায়ী প্রতিটা protocol-এর উপযুক্ততা বদলায়। HTTP/2 ভালো নেটওয়ার্কে চমৎকার, কিন্তু lossy নেটওয়ার্কে HTTP/1.1-এর multi-connection approach-এর চেয়েও খারাপ হতে পারে ঠিক এই HOL blocking কারণেই।
উদাহরণ ৩: একটা API Gateway ডিজাইন করছো (তোমার production experience-এর সাথে সংযোগ)
ধরো তোমার notification/API service বহু ধরনের client (কিছু stable wired connection-এ, কিছু mobile) থেকে ট্রাফিক পায়।
- সিদ্ধান্ত: server-এ HTTP/1.1, HTTP/2, এবং HTTP/3 — তিনটাই সাপোর্ট রাখা ভালো (ALPN negotiation দিয়ে client-server নিজেরাই ঠিক করে নেয় কোনটা ব্যবহার করবে)
- Mobile-heavy traffic হলে HTTP/3 অগ্রাধিকার (adoption-এর দিকে ঠেলা) দেওয়া যুক্তিসঙ্গত, কারণ mobile নেটওয়ার্কে packet loss এবং network switching (WiFi ↔ cellular) বেশি ঘটে — যেখানে QUIC-এর সুবিধাগুলো (independent streams + connection migration) সবচেয়ে বেশি কাজে আসবে
পার্ট ৬ — Consolidation: Interview-Style প্রশ্ন
নিজে নিজে (নোট ছাড়া, জোরে বলে) উত্তর দেওয়ার চেষ্টা করো:
- HTTP/1.0 থেকে HTTP/1.1-এ প্রধান উন্নতি কী ছিল, এবং তাও কোন সমস্যা রয়ে গেলো?
- HTTP/2-এর multiplexing কীভাবে HTTP/1.1-এর application-level HOL blocking সমাধান করে (Frame, Stream ID ব্যবহার করে ব্যাখ্যা করো)?
- HPACK আর QPACK আলাদা algorithm হিসেবে ডিজাইন করার দরকার হলো কেন — QUIC-এর independent stream property-র সাথে সম্পর্ক দেখিয়ে ব্যাখ্যা করো।
- HTTP/2-তে TCP-level HOL blocking ঠিক কীভাবে ঘটে — একটা concrete byte-stream উদাহরণ দিয়ে দেখাও (পার্ট ২-এর ডায়াগ্রামের মতো, নিজের ভাষায়)।
- একটা lossy mobile নেটওয়ার্কে কেন HTTP/2 কখনো কখনো HTTP/1.1-এর multi-connection approach-এর চেয়েও খারাপ পারফর্ম করতে পারে?
- Server Push কেন deprecated হলো, এবং এটা থেকে ইঞ্জিনিয়ারিং সিদ্ধান্ত নেওয়ার ক্ষেত্রে কী শেখা যায়?
- তোমার একটা API service-এ, ৭০% ট্রাফিক mobile client থেকে আসে, ৩০% stable wired connection থেকে — protocol support strategy কী হবে এবং কেন?
Day 8 · DNS: resolution, TTL, anycast, GeoDNS
পার্ট ০ — Day 4-7 থেকে সংযোগ: এটাই আসলে সবকিছুর প্রথম ধাপ
এতদিন আমরা যা শিখেছি (TCP handshake, TLS, HTTP) — এগুলোর সবকিছুরই একটা প্রাথমিক শর্ত আছে: একটা IP address থাকতে হবে যেখানে connect করতে হবে। কিন্তু user তো টাইপ করে example.com — একটা মানুষের পড়ার মতো নাম, IP address (যেমন 93.184.216.34) না।
DNS (Domain Name System) এই "নাম থেকে ঠিকানা" রূপান্তর করে দেয়। এটা এমন একটা সিস্টেম যেটা এত মৌলিক এবং এত ভালোভাবে কাজ করে যে আমরা প্রায়ই ভুলে যাই এটা আসলে ইন্টারনেটের সবচেয়ে বড়, সবচেয়ে distributed database — বিলিয়ন বিলিয়ন query handle করে প্রতিদিন, প্রায় সবসময় নিখুঁতভাবে।
একটা analogy দিয়ে শুরু করি
DNS-কে ভাবো একটা globally distributed ফোন বুক হিসেবে, কিন্তু এমন একটা ফোন বুক যেটা:
- কেন্দ্রীয়ভাবে একটা জায়গায় নেই — hierarchical ভাবে হাজার হাজার সার্ভারে ছড়ানো
- প্রতিটা এন্ট্রি নিয়মিত আপডেট হতে পারে (কেউ ফোন নম্বর বদলালে)
- caching করা হয় প্রতিটা স্তরে, যাতে বারবার পুরো বুক খুঁজতে না হয়
পার্ট ১ — DNS Hierarchy: কীভাবে সংগঠিত
DNS namespace একটা inverted tree — একদম উপরে থাকে "root", তারপর ধাপে ধাপে নিচে নামে।
"." (Root)
/ | \
.com .org .net ... (TLD - Top Level Domain)
|
example.com (Authoritative domain)
|
www.example.com, api.example.com (Subdomains)
একটা domain name-কে ডান থেকে বাম পড়া হয় resolution-এর সময়:
www.example.com. (লক্ষ্য করো শেষে একটা "." আছে — এটা root-কে বোঝায়, সাধারণত লুকানো থাকে)
- Root (
.) — সবার উপরে - TLD (
.com) — Top Level Domain - Second-level domain (
example.com) — এটা organization নিজে register করে - Subdomain (
www.example.com) — organization নিজের ইচ্ছামতো তৈরি করতে পারে
Nameserver-এর প্রকারভেদ
| Nameserver টাইপ | দায়িত্ব |
|---|---|
| Root Nameserver | জানে কোন TLD (.com, .org, .net) নেমসার্ভার কোথায় (পৃথিবীতে মাত্র ১৩টা "logical" root server আছে, প্রতিটা Anycast দিয়ে বহু ফিজিক্যাল লোকেশনে বিস্তৃত — পার্ট ৪-এ বিস্তারিত) |
| TLD Nameserver | জানে একটা নির্দিষ্ট TLD-এর মধ্যে কোন domain-এর authoritative nameserver কোথায় (যেমন .com-এর TLD nameserver জানে example.com-এর authoritative nameserver কোনটা) |
| Authoritative Nameserver | আসল উত্তর দেয় — example.com-এর জন্য প্রকৃত IP address কী, এটা এখানেই সংরক্ষিত (organization নিজে বা তাদের DNS provider এটা host করে) |
| Recursive Resolver | Client-এর পক্ষ থেকে পুরো lookup process সম্পন্ন করে (সাধারণত ISP বা 3rd-party যেমন Google 8.8.8.8, Cloudflare 1.1.1.1) |
পার্ট ২ — Resolution Process: ধাপে ধাপে (Cold Lookup)
ধরো একজন user প্রথমবার www.example.com ভিজিট করছে (কোথাও কোনো cache নেই):
1. Browser → OS resolver cache চেক করে [miss]
2. OS → Recursive Resolver-কে (ISP/8.8.8.8) জিজ্ঞেস করে
3. Recursive Resolver → Root Nameserver-কে জিজ্ঞেস করে
"www.example.com কোথায়?"
Root উত্তর দেয়: "আমি জানি না, কিন্তু .com নেমসার্ভার
জিজ্ঞেস করো, এই তার ঠিকানা"
4. Recursive Resolver → TLD (.com) Nameserver-কে জিজ্ঞেস করে
TLD উত্তর দেয়: "example.com-এর authoritative
nameserver হলো ns1.example.com, এই তার IP"
5. Recursive Resolver → Authoritative Nameserver-কে জিজ্ঞেস করে
Authoritative উত্তর দেয়: "www.example.com = 93.184.216.34"
6. Recursive Resolver → Client-কে ফিরে পাঠায়: 93.184.216.34
এটাকে বলে "recursive resolution" — client নিজে root/TLD/authoritative সবার সাথে আলাদা করে কথা বলে না, শুধু recursive resolver-কেই একটা জিজ্ঞাসা করে, এবং recursive resolver নিজে বাকি সব ধাপ ("recursion") সম্পন্ন করে সরাসরি চূড়ান্ত উত্তর দেয়।
Latency Impact — Day 1-এর জ্ঞান এখানে প্রযোজ্য
প্রতিটা hop-এ একটা network round trip লাগে। যদি cache কোথাও না থাকে (worst case), আনুমানিক ৪-৫টা round trip লাগতে পারে (root, TLD, authoritative + resolver-এর নিজের প্রসেসিং)। প্রতিটা hop যদি ২০-৫০ms হয় (বিভিন্ন লোকেশনে থাকা সার্ভারের কারণে), সম্পূর্ণ cold DNS lookup ১০০-২০০ms পর্যন্ত সময় নিতে পারে — এবং এটা TCP handshake, TLS handshake শুরু হওয়ার আগেই ঘটে (Day 4, 6)।
এইজন্যই DNS caching এত গুরুত্বপূর্ণ — এই পুরো chain বারবার চালানো user experience-এর জন্য মারাত্মক ধীর হবে।
পার্ট ৩ — Caching এবং TTL: Freshness বনাম Efficiency
Caching কোথায় কোথায় হয়
Browser cache (কয়েক মিনিট/ঘণ্টা)
│
▼
OS-level resolver cache
│
▼
Recursive Resolver cache (ISP বা 8.8.8.8/1.1.1.1)
│
▼
(cache miss হলে তবেই root/TLD/authoritative-এর দিকে যায়)
প্রতিটা স্তরের cache hit মানে — উপরের সব hop skip হয়ে যায়। যেমন যদি recursive resolver-এর নিজের cache-এ example.com-এর এন্ট্রি থাকে, root/TLD/authoritative কাউকেই জিজ্ঞেস করার দরকার নেই।
TTL (Time To Live) — এই caching কতক্ষণ valid থাকবে
প্রতিটা DNS record-এর সাথে একটা TTL value থাকে (সেকেন্ডে), যেটা authoritative nameserver ঠিক করে দেয়। উদাহরণ: A record: www.example.com → 93.184.216.34, TTL=300 মানে এই এন্ট্রি ৩০০ সেকেন্ড (৫ মিনিট) পর্যন্ত cache-এ রাখা যাবে, তারপর আবার query করতে হবে fresh ডেটার জন্য।
TTL-এর মৌলিক Tradeoff
| TTL | সুবিধা | অসুবিধা |
|---|---|---|
| কম (যেমন ৩০-৬০ সেকেন্ড) | কোনো পরিবর্তন (IP বদল, failover) দ্রুত সবার কাছে পৌঁছায় | বেশি বার query করতে হয় → বেশি latency (প্রতিবার cache miss), authoritative nameserver-এ বেশি load |
| বেশি (যেমন ২৪ ঘণ্টা) | কম query, দ্রুত response (বেশিরভাগ সময় cache hit), কম load authoritative server-এ | কোনো সমস্যা হলে (server down, migration) পরিবর্তন ছড়াতে অনেক সময় লাগে |
বাস্তব উদাহরণ দিয়ে বুঝি
উদাহরণ ১ — একটা স্ট্যাটিক corporate ওয়েবসাইট: এই সাইটের IP কখনো বদলায় না (বছরের পর বছর) — এখানে TTL উচ্চ রাখা (যেমন ২৪ ঘণ্টা) যুক্তিসঙ্গত, কারণ পরিবর্তনের সম্ভাবনা কম, আর উচ্চ TTL মানে কম query, দ্রুত resolution বেশিরভাগ user-এর জন্য।
উদাহরণ ২ — একটা active-active multi-region সিস্টেম যেটা প্রায়ই traffic শিফট করে (blue-green deployment বা failover-এর জন্য): এখানে TTL কম রাখা (৩০-৬০ সেকেন্ড) জরুরি, কারণ deployment/failover-এর সময় দ্রুত traffic নতুন region-এ পাঠানো দরকার — উচ্চ TTL হলে অনেক client অনেকক্ষণ পুরনো (হয়তো এখন unhealthy) সার্ভারে যেতেই থাকবে।
Production pattern: অনেক কোম্পানি একটা planned migration-এর আগে থেকেই TTL কমিয়ে রাখে (যেমন migration-এর ২৪ ঘণ্টা আগে TTL ২৪ ঘণ্টা থেকে ৫ মিনিটে নামিয়ে আনা) — এটাকে বলে "TTL preheating" বা "pre-migration TTL reduction" — যাতে actual migration-এর সময় দ্রুত সব client নতুন IP-তে সুইচ করতে পারে।
Negative Caching — একটা কম আলোচিত কিন্তু গুরুত্বপূর্ণ ব্যাপার
শুধু "সফল" lookup cache হয় না — "এই domain নেই" (NXDOMAIN) উত্তরও cache হয় (SOA record-এ একটা আলাদা TTL দিয়ে, যাকে বলে "negative TTL")। এর মানে যদি তুমি একটা নতুন domain register করো এবং সাথে সাথে চেষ্টা করো visit করতে (কারো resolver যদি আগেই "এই domain নেই" cache করে ফেলে থাকে), তুমি কিছুক্ষণ ভুলভাবে "সাইট পাওয়া যাচ্ছে না" দেখতে পারো, negative TTL expire না হওয়া পর্যন্ত।
পার্ট ৪ — DNS-এর মাধ্যমে Failover এবং এর সীমাবদ্ধতা
DNS-Based Failover কীভাবে কাজ করে
একটা সাধারণ pattern: Primary region down হলে, DNS-এ authoritative record আপডেট করে দেওয়া হয় secondary region-এর IP দিয়ে — নতুন যেসব client resolve করবে তারা secondary-তে যাবে।
Before failover: example.com → 1.2.3.4 (Primary, US-East)
After failover: example.com → 5.6.7.8 (Secondary, US-West)
সীমাবদ্ধতা ১: TTL Respect না করা Clients
সবকিছু TTL সঠিকভাবে respect করে না:
- কিছু পুরনো/misconfigured resolver TTL-কে গুরুত্ব না দিয়ে নিজের ইচ্ছামতো (কখনো কখনো অনেক বেশিক্ষণ) cache রাখে
- কিছু application নিজেই একবার resolve করে IP hard-cache করে রাখে (connection pooling implementation-এ common সমস্যা — যদি connection pool নতুন resolution না করেই পুরনো connection বারবার ব্যবহার করে)
- Corporate network-এ বা কিছু ISP-তে DNS caching layer থাকে যেগুলো নিজেদের নিয়মে চলে, ব্যবহারকারীর TTL respect নাও করতে পারে
ফলাফল: DNS failover কখনোই "instant" না — এটা একটা gradual propagation (কিছু ব্যবহারকারী সেকেন্ডে, কিছু মিনিটে, কিছু ঘণ্টার মধ্যে দেখতে পাবে)।
সীমাবদ্ধতা ২: DNS Failover Detection নিজে ধীর
DNS নিজে ঠিক করে না কখন failover ট্রিগার হবে — এর জন্য আলাদা health check system দরকার যেটা primary region-এর স্বাস্থ্য মনিটর করে এবং সমস্যা দেখলে DNS record আপডেট করে। এই পুরো detection + update চেইনটাও কিছু সময় নেয় (সেকেন্ড থেকে মিনিট পর্যায়ে, health check interval এবং threshold অনুযায়ী)।
তাই ইন্টারভিউতে বলার মতো গুরুত্বপূর্ণ পয়েন্ট: "DNS failover একটা useful কিন্তু imperfect টুল — এটা critical, sub-second failover-এর জন্য যথেষ্ট না। এর চেয়ে দ্রুত এবং নির্ভরযোগ্য বিকল্প হলো Anycast (নিচে) অথবা Load Balancer-level failover (Day 10), যেখানে DNS resolution-এর পরে, একই IP-তে থেকেই routing decision নেওয়া হয়।"
পার্ট ৫ — Anycast: DNS পরিবর্তন ছাড়াই Instant Routing
মূল ধারণা
Anycast মানে: একই IP address একাধিক ফিজিক্যাল লোকেশন থেকে একসাথে announce করা হয় নেটওয়ার্ক-লেভেলে (BGP routing protocol দিয়ে)। User যখন সেই IP-তে request পাঠায়, ইন্টারনেটের routing infrastructure স্বয়ংক্রিয়ভাবে সবচেয়ে কাছের (routing-এর হিসেবে, ভৌগোলিক দূরত্বে না) লোকেশনে পাঠায়।
Anycast IP: 1.1.1.1
/ | \
Location A Location B Location C
(Singapore) (Frankfurt) (New York)
User in Dhaka → routing decides closest → Singapore (Location A)
User in Berlin → routing decides closest → Frankfurt (Location B)
একই IP, কিন্তু routing infrastructure স্বয়ংক্রিয়ভাবে
প্রতিটা ব্যবহারকারীকে ভিন্ন লোকেশনে পাঠায়
কেন এটা DNS-based Failover-এর চেয়ে দ্রুত
Anycast-এ কোনো DNS পরিবর্তনের দরকার নেই যখন একটা লোকেশন down হয়ে যায়। যদি Singapore location down হয়ে যায়, সেই লোকেশন BGP route announcement বন্ধ করে দেয় (route withdraw) — ইন্টারনেটের routing infrastructure স্বয়ংক্রিয়ভাবে সেই route ভুলে যায় এবং পরবর্তী নিকটতম লোকেশনে (Frankfurt বা New York) traffic পুনর্নির্দেশিত হয় — কোনো DNS TTL-এর অপেক্ষা ছাড়াই, প্রায় তাৎক্ষণিকভাবে (BGP convergence time-এর মধ্যে, যেটা সেকেন্ডের মধ্যে হয়, DNS TTL-এর মিনিট/ঘণ্টার তুলনায়)।
বাস্তব উদাহরণ
Cloudflare-এর 1.1.1.1 এবং Google-এর 8.8.8.8 DNS resolver — সারা পৃথিবীতে একই IP address, কিন্তু শত শত ফিজিক্যাল লোকেশন থেকে announce করা হয়। ঢাকা থেকে query করলে সবচেয়ে কাছের PoP-তে যায় (হয়তো Singapore বা Mumbai), ইউরোপ থেকে query করলে অন্য PoP-তে — এই পুরো routing user-এর কোনো action ছাড়াই, DNS-এর কোনো ভূমিকা ছাড়াই ঘটে (কারণ IP address-ই একটাই, শুধু network routing আলাদা)।
Anycast-এর সীমাবদ্ধতা (এটাও বলা জরুরি ইন্টারভিউতে)
TCP Connection Disruption Risk: যদি একটা BGP route পরিবর্তন হয় একটা active TCP connection চলাকালীন সময়ে (Day 4), সেই connection হঠাৎ একটা ভিন্ন ফিজিক্যাল সার্ভারে "route" হয়ে যেতে পারে যেখানে সেই connection-এর কোনো state (sequence number ইত্যাদি) নেই — এর ফলে connection reset (RST) হয়ে যায়, user-কে আবার নতুন করে connect করতে হয়।
তুলনা GeoDNS-এর সাথে: এই কারণেই কিছু সিস্টেম Anycast-এর বদলে (বা সাথে) GeoDNS ব্যবহার করে, যেখানে routing "sticky" থাকে একটা নির্দিষ্ট session-এর জন্য (client একবার একটা নির্দিষ্ট IP resolve করলে, সেই connection-এর পুরো জীবদ্দশায় একই সার্ভারের সাথে কথা বলে, DNS-এর TTL অনুযায়ী)।
পার্ট ৬ — GeoDNS: DNS-Level Geographic Routing
GeoDNS কীভাবে কাজ করে
GeoDNS একটা DNS resolution পদ্ধতি যেখানে resolver ব্যবহারকারীর (আসলে ব্যবহারকারীর recursive resolver-এর) ভৌগোলিক অবস্থান দেখে ভিন্ন ভিন্ন IP address রিটার্ন করে।
DNS query from Asia → example.com → returns 1.2.3.4 (Singapore datacenter)
DNS query from Europe → example.com → returns 5.6.7.8 (Frankfurt datacenter)
DNS query from US → example.com → returns 9.10.11.12 (Virginia datacenter)
প্রতিটা ব্যবহারকারী আলাদা, নির্দিষ্ট IP পায় (Anycast-এর মতো একই IP না) — routing সিদ্ধান্ত DNS layer-এই নেওয়া হয়, নেটওয়ার্ক routing layer-এ না।
GeoDNS vs Anycast — এই পার্থক্যটা পরিষ্কার বোঝা জরুরি (ইন্টারভিউতে প্রায়ই গুলিয়ে ফেলা হয়)
| বিষয় | Anycast | GeoDNS |
|---|---|---|
| কোন layer-এ routing decision | Network layer (BGP routing) | DNS layer (resolver ভিন্ন IP রিটার্ন করে) |
| IP address | সব লোকেশনে একই IP | প্রতিটা লোকেশনের জন্য আলাদা IP |
| Failover গতি | প্রায় তাৎক্ষণিক (BGP convergence, সেকেন্ডে) | ধীর (DNS TTL-নির্ভর, মিনিট/ঘণ্টা) |
| Granularity/Control | কম (routing infrastructure নিজে সিদ্ধান্ত নেয় কোনটা "কাছে") | বেশি (তুমি নিজে নির্দিষ্ট করতে পারো কোন country/region কোন IP পাবে) |
| Connection Stability | risk আছে (mid-connection route change) | স্থিতিশীল (একবার resolve হলে, TTL অনুযায়ী একই IP-তে থাকে) |
| ব্যবহারের উদাহরণ | DNS resolver নিজেই (1.1.1.1), DDoS mitigation, CDN edge network | বড় ওয়েবসাইট/API যেগুলো region-ভিত্তিক নির্দিষ্ট data residency/latency optimization চায় |
কখন কোনটা বেছে নেবে (Decision Framework)
Anycast বেছে নাও যখন:
- সর্বোচ্চ গুরুত্ব দ্রুততম failover (সেকেন্ডে)
- Service নিজেই connection-agnostic বা short-lived connection-heavy (যেমন DNS resolver নিজে, বা UDP-ভিত্তিক সার্ভিস যেখানে connection state কম গুরুত্বপূর্ণ)
- Global network infrastructure থাকা (নিজস্ব BGP announcement করার সক্ষমতা — এটা সহজলভ্য না, প্রতিষ্ঠিত CDN/cloud provider-দের জন্য practical)
GeoDNS বেছে নাও যখন:
- নির্দিষ্ট region-ভিত্তিক routing control দরকার (যেমন data residency আইন — EU ইউজারদের data অবশ্যই EU সার্ভারে থাকতে হবে)
- Long-lived, stateful connection আছে যেগুলোকে mid-session বিঘ্নিত করা যাবে না
- BGP/Anycast infrastructure নিজে maintain করার সক্ষমতা/প্রয়োজন নেই (GeoDNS প্রায় যেকোনো standard DNS provider দিয়ে সেটআপ করা যায়)
Production Reality: বড় প্রতিষ্ঠান (Cloudflare, AWS, Google) প্রায়ই দুটোই একসাথে ব্যবহার করে — edge network layer-এ Anycast (দ্রুত raw routing এবং DDoS resilience-এর জন্য), এবং তার ভেতরে application-level GeoDNS বা L7 routing (নির্দিষ্ট backend region নির্বাচনের জন্য, compliance এবং data residency মেনে চলতে)।
পার্ট ৭ — একটা সম্পূর্ণ কেস স্টাডি: একটা Global SaaS Product-এর DNS Strategy
ধরো তুমি একটা global SaaS product ডিজাইন করছো — US, EU, এবং Asia-Pacific-এ ডেটাসেন্টার আছে, এবং GDPR-এর কারণে EU user-দের data অবশ্যই EU-তে থাকতে হবে।
DNS Strategy:
1. app.example.com → GeoDNS ব্যবহার করে region-ভিত্তিক routing
├── EU users → EU datacenter IP (data residency compliance)
├── US users → US datacenter IP
└── APAC users → APAC datacenter IP (সবচেয়ে কম latency)
2. api.example.com (internal, high-availability দরকার) → Anycast
→ যেকোনো datacenter down হলে ন্যানোসেকেন্ডে reroute,
কিন্তু data residency চিন্তা নেই কারণ এটা stateless API gateway layer
3. TTL Strategy:
├── স্বাভাবিক অবস্থায়: TTL = 300s (৫ মিনিট) — balance between
│ freshness এবং query load
└── Planned maintenance window-এর ২৪ ঘণ্টা আগে: TTL কমিয়ে
৩০ সেকেন্ডে আনা হয় — যাতে maintenance শুরু হওয়ার সময়
traffic দ্রুত অন্য region-এ শিফট করা যায়
4. Health Check + Failover:
├── প্রতিটা region-এর health প্রতি ১০ সেকেন্ডে চেক করা হয়
├── ৩ বার consecutive failure হলে DNS record আপডেট হয়
│ (secondary region-এ শিফট)
└── কিন্তু এই DNS-based failover শুধু "graceful degradation"
হিসেবে কাজ করে — critical, sub-second failover-এর জন্য
এর সাথে সাথে Load Balancer-level health check (Day 10)-ও
থাকে, যেটা DNS propagation-এর জন্য অপেক্ষা না করেই
within-region backend server বদলে দিতে পারে
এই কেস স্টাডিটাই দেখায় কীভাবে একটা প্রোডাকশন সিস্টেমে DNS-এর বিভিন্ন কৌশল (GeoDNS, Anycast, TTL tuning) একসাথে, বিভিন্ন স্তরে, বিভিন্ন requirement মেটাতে ব্যবহার করা হয় — এটা কখনোই "একটা কৌশল বেছে নাও" প্রশ্ন না।
পার্ট ৮ — Consolidation: Interview-Style প্রশ্ন
নিজে নিজে (নোট ছাড়া, জোরে বলে) উত্তর দেওয়ার চেষ্টা করো:
- একটা cold DNS lookup-এ ঠিক কতগুলো hop লাগতে পারে, এবং এই hop-গুলো কী ক্রমে ঘটে (root → TLD → authoritative)?
- TTL কম রাখলে আর বেশি রাখলে ঠিক কী কী tradeoff হয় — দুটো ভিন্ন real-world scenario দিয়ে ব্যাখ্যা করো (স্ট্যাটিক সাইট vs active failover system)।
- Negative caching (NXDOMAIN cache) কীভাবে একটা নতুন domain register করার পরপরই সমস্যা তৈরি করতে পারে?
- DNS-based failover-এর দুইটা মূল সীমাবদ্ধতা কী কী (TTL respect এবং detection speed প্রসঙ্গে)?
- Anycast কীভাবে কাজ করে (BGP routing প্রসঙ্গে), এবং কেন এটা DNS failover-এর চেয়ে দ্রুত?
- Anycast-এর একটা বড় ঝুঁকি কী (mid-connection route change প্রসঙ্গে), এবং এটা কোন ধরনের সিস্টেমে সবচেয়ে বেশি প্রভাব ফেলবে?
- GeoDNS আর Anycast-এর মধ্যে ঠিক কোন স্তরে (network vs DNS) routing decision নেওয়া হয় — এই পার্থক্যটা এক বাক্যে বলো।
- একটা GDPR-compliant global SaaS product-এ (পার্ট ৭-এর কেস স্টাডি) কোথায় GeoDNS আর কোথায় Anycast ব্যবহার করবে, এবং কেন একসাথে দুটোই দরকার হতে পারে?
Day 9 · CDN architecture: PoPs, origin shield, invalidation
পার্ট ০ — Day 1-8 থেকে সংযোগ: কেন CDN এত গুরুত্বপূর্ণ
Day 1-এ আমরা শিখেছিলাম: cross-continent round trip ~150ms, local network round trip ~1-10ms। Day 4-8-এ আমরা দেখেছি প্রতিটা connection-এ (DNS, TCP, TLS, HTTP) কত RTT লাগে। এই সব RTT-র প্রতিটাই user-এর দূরত্বের উপর নির্ভরশীল।
CDN-এর মূল প্রতিশ্রুতি সহজ: যদি content-টা user-এর কাছেই রাখা যায়, তাহলে এই সব RTT-র "distance factor" নাটকীয়ভাবে কমে যায়। ঢাকা থেকে US-এর origin server-এ প্রতিটা request পাঠানোর বদলে, যদি ঢাকার কাছেই (Singapore বা Mumbai-তে) content-এর একটা copy থাকে, পুরো experience অনেক দ্রুত হয়ে যায়।
একটা analogy
CDN-কে ভাবো একটা বইয়ের চেইন লাইব্রেরি হিসেবে — মূল প্রকাশক (origin) হয়তো আমেরিকায়, কিন্তু জনপ্রিয় বইগুলোর copy স্থানীয় শাখা লাইব্রেরিতে (PoP) রাখা থাকে। তুমি স্থানীয় শাখায় গিয়ে বই পড়তে পারো, আমেরিকায় চিঠি পাঠিয়ে বই আনানোর দরকার নেই — যদি বইটা স্থানীয় শাখায় already থাকে।
পার্ট ১ — PoP (Point of Presence): CDN-এর মূল বিল্ডিং ব্লক
PoP কী
PoP হলো CDN provider-এর একটা physical বা logical data center location, যেখানে caching server বসানো থাকে user-দের কাছাকাছি। একটা বড় CDN provider-এর (Cloudflare, Akamai, Fastly) পৃথিবীজুড়ে শত শত PoP থাকতে পারে — প্রতিটা শহর/অঞ্চলে একাধিক।
Origin Server
(US, একমাত্র "সত্যিকারের" ডেটার উৎস)
│
┌───────────────┼───────────────┐
│ │ │
PoP (Singapore) PoP (Frankfurt) PoP (São Paulo)
│ │ │
Users in Asia Users in Europe Users in
South America
PoP কীভাবে User-কে খুঁজে পায় (Day 8-এর সংযোগ)
User একটা request পাঠালে, CDN নিশ্চিত করে সেই request সবচেয়ে কাছের PoP-তে যায় — এটা সাধারণত করা হয়:
- Anycast দিয়ে (Day 8) — একই IP সব PoP থেকে announce করা, network routing স্বয়ংক্রিয়ভাবে কাছেরটাতে পাঠায়
- অথবা GeoDNS দিয়ে (Day 8) — resolver ব্যবহারকারীর location দেখে ভিন্ন PoP-এর IP রিটার্ন করে
এটাই Day 8-এর জ্ঞান সরাসরি প্রয়োগের জায়গা: CDN routing decision (কোন PoP ব্যবহারকারীকে সার্ভ করবে) মূলত DNS/Anycast layer-এই নেওয়া হয়, তারপর একবার PoP নির্ধারিত হয়ে গেলে, actual content delivery HTTP layer-এ (Day 7) ঘটে।
PoP-এর ভেতরে কী থাকে
একটা modern PoP সাধারণত থাকে:
- Cache storage (SSD/RAM ভিত্তিক, দ্রুত read-এর জন্য — Day 1-এর latency numbers মনে করো, RAM/SSD read disk-এর চেয়ে অনেক দ্রুত)
- Load balancer (Day 10) — একই PoP-এর ভেতরে একাধিক cache server-এর মধ্যে ট্রাফিক distribute করতে
- TLS termination (Day 6) — user-এর সাথে HTTPS connection এখানেই terminate হয়, যাতে user-এর কাছাকাছি secure connection দ্রুত স্থাপন করা যায় (TLS handshake RTT কমে যায় কারণ PoP কাছেই)
পার্ট ২ — Cache Hit vs Cache Miss: মৌলিক Flow
Cache Hit (সবচেয়ে ভালো কেস)
User → PoP (cache hit!) → সরাসরি response ফেরত
(Origin server-এর সাথে কোনো communication লাগেনি)
এই ক্ষেত্রে latency শুধু user-থেকে-PoP দূরত্বের উপর নির্ভর করে — origin server যত দূরেই থাকুক না কেন, কোনো প্রভাব নেই।
Cache Miss (Origin-এ যেতে হয়)
User → PoP (cache miss) → Origin Server → PoP (cache-এ save করে) → User
প্রথমবার একটা content request হলে (বা TTL expire হয়ে গেলে), PoP-কে origin থেকে fresh copy আনতে হয় — এটাই cache miss, এবং এতে origin-এর দূরত্বের পুরো latency (Day 1-এর cross-continent RTT) যোগ হয়ে যায়।
Cache Hit Ratio — সবচেয়ে গুরুত্বপূর্ণ metric
Cache Hit Ratio = Cache Hit সংখ্যা / মোট Request সংখ্যা
এই একটা সংখ্যাই বলে দেয় CDN কতটা কার্যকরী হচ্ছে। যদি hit ratio ৯৫% হয়, মানে ৯৫% request-এর জন্য origin-এর দিকে যেতেই হচ্ছে না — বিশাল latency এবং origin load সাশ্রয়। বাকি ৫% (miss) origin-এ যাচ্ছে।
Hit ratio কমে যাওয়ার সাধারণ কারণ (পরবর্তী পার্টগুলোতে বিস্তারিত):
- Cache key design খারাপ (পার্ট ৫ দেখো) — একই content ভিন্ন key-তে ভাগ হয়ে যাচ্ছে
- TTL খুব কম রাখা হয়েছে
- Content নিজেই highly personalized/dynamic (প্রতিটা user-এর জন্য আলাদা response)
পার্ট ৩ — Origin Shield: Thundering Herd সমস্যার সমাধান
সমস্যাটা প্রথমে বুঝি — "Thundering Herd on Origin"
ধরো তোমার CDN-এ ১০০টা PoP আছে world-জুড়ে। এখন একটা viral content-এর cache TTL expire হয়ে যায় ঠিক একই মুহূর্তে (স্বাভাবিক, কারণ সবগুলো PoP একই সময়ে সেই content প্রথমবার cache করেছিল)।
Origin Server
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ (১০০টা PoP একসাথে
│ │ │ │ │ │ │ │ │ │ request পাঠাচ্ছে!)
PoP1 PoP2 PoP3 ... PoP100
এটাই "thundering herd" — একটা মাত্র cache expiry event, কিন্তু ১০০টা আলাদা location একসাথে origin-কে আঘাত করছে একই content-এর জন্য। Origin server-এর জন্য এটা একটা achছাত্মিক spike তৈরি করে — যদিও প্রকৃতপক্ষে "একই" ডেটা ১০০ বার আনার কোনো প্রয়োজনই ছিল না।
সমাধান: Origin Shield — একটা মধ্যবর্তী কেন্দ্রীয় Cache Layer
Origin Server
▲
│ (মাত্র 1টা request!)
Origin Shield
(একটা কেন্দ্রীয়, নির্দিষ্ট region-এর PoP)
▲ ▲ ▲ ▲ ▲
│ │ │ │ │
PoP1 PoP2 PoP3 ... PoP100
Origin Shield হলো একটা একক, নির্দিষ্ট (সাধারণত origin-এর কাছাকাছি একটা location-এ) intermediate caching layer যেটার মধ্য দিয়ে সব PoP-এর cache-miss request যেতে বাধ্য থাকে — সরাসরি origin-এ না গিয়ে।
কীভাবে thundering herd সমাধান হয়:
- সব ১০০টা PoP-এর cache miss হলে, প্রতিটাই Origin Shield-কে জিজ্ঞেস করে
- Origin Shield নিজেও যদি সেই content cache-এ না রাখে, প্রথম request-টাই origin-কে জিজ্ঞেস করে — বাকি ৯৯টা request Origin Shield-এ "queued"/"coalesced" থাকে (একে বলে request coalescing)
- Origin থেকে response এলে, Origin Shield সেটা নিজের কাছে cache করে এবং সব ৯৯+১ = ১০০টা অপেক্ষমান PoP-কে একসাথে response দেয়
- ফলাফল: origin server মাত্র ১টা request পেয়েছে, ১০০টা না
Request Coalescing — গভীরে বোঝা জরুরি একটা concept
Request Coalescing মানে: একই সময়ে একই resource-এর জন্য একাধিক incoming request থাকলে, শুধু প্রথমটা upstream-এ (origin বা database-এ) পাঠানো হয়, বাকি সব request "wait" করে সেই একটা response-এর জন্য, এবং সবাইকে একসাথে সেই response থেকে সার্ভ করা হয়।
তোমার Redis/caching experience-এর সাথে সরাসরি সংযোগ: এটা ঠিক সেই একই প্যাটার্ন যেটা Day 18 (Cache Stampede প্রতিরোধ)-এ আমরা আরও বিস্তারিত দেখবো application-level caching-এ (যেমন Redis miss হলে database-এ একসাথে হাজারো query না পাঠিয়ে একটাই query পাঠানো, বাকিদের সেই একটা result থেকে সার্ভ করা)। Origin Shield আসলে এই একই নীতির CDN-স্কেল প্রয়োগ।
Origin Shield কোথায় বসানো উচিত
Origin Shield সাধারণত এমন একটা location-এ বসানো হয় যেটা origin server-এর নেটওয়ার্ক-দূরত্বে সবচেয়ে কাছে (একই region বা একই datacenter-এ, যদি সম্ভব হয়) — যাতে Origin Shield-থেকে-Origin RTT ন্যূনতম হয়, যেহেতু cache-miss হলে এই পথেই যেতে হবে।
Origin Shield ছাড়া বনাম সহ — সংখ্যায় দেখি
ধরো একটা viral post CDN-এ cache TTL expire হয়ে গেলো, ১০০টা PoP-এর মধ্যে ৫০টা একই সময়ে (কয়েক মিলিসেকেন্ডের মধ্যে) request করে।
- Origin Shield ছাড়া: origin server ৫০টা simultaneous request পায় একই content-এর জন্য — যদি origin-এর একটা single request handle করতে ৫০ms লাগে, এবং ৫০টা concurrent request আসে, origin-এর CPU/connection pool মারাত্মকভাবে চাপে পড়বে, সম্ভবত timeout/error দেখা দেবে অন্যান্য (unrelated) request-এও, কারণ resource shared।
- Origin Shield সহ: origin মাত্র ১টা request পায়, ৪৯টা PoP অপেক্ষা করে Origin Shield-এর কাছে, response এলে সবাই একসাথে পায়।
পার্ট ৪ — Cache Invalidation: "One of the Two Hard Problems in Computer Science"
একটা বিখ্যাত উক্তি (Phil Karlton): "There are only two hard things in Computer Science: cache invalidation and naming things." CDN-এর context-এ, cache invalidation মানে: "কীভাবে নিশ্চিত করবে যে PoP-এ থাকা cached কনটেন্ট, origin-এর latest ভার্সনের সাথে সামঞ্জস্যপূর্ণ থাকে?"
পদ্ধতি ১: TTL-Based Expiry (সবচেয়ে সহজ, ডিফল্ট)
Content-এর সাথে একটা TTL সেট করে দাও (Cache-Control: max-age=3600 — ১ ঘণ্টা)। TTL expire হওয়ার পর PoP আবার origin থেকে fresh copy আনবে।
সুবিধা: সহজ, কোনো active invalidation logic লাগে না। অসুবিধা: TTL expire না হওয়া পর্যন্ত content আপডেট হলেও পুরনো (stale) ভার্সন সার্ভ হতে থাকবে — worst case ততক্ষণ stale থাকবে যতক্ষণ TTL সেট করা আছে।
পদ্ধতি ২: Purge/Invalidation API (Active Invalidation)
Content পরিবর্তন হলে, সরাসরি CDN-এর API কল করে বলে দাও: "এই নির্দিষ্ট URL/key invalidate করো, এখনই" — CDN তখন সব PoP-তে (বা নির্দিষ্ট PoP-এ) সেই cache entry মুছে দেয় বা invalid মার্ক করে দেয়।
সুবিধা: Real-time — content পরিবর্তনের সাথে সাথেই cache আপডেট হয়ে যায় (পরের request-এই fresh content আসবে)। অসুবিধা:
- Latency: একটা purge request পাঠিয়ে সব PoP-তে propagate হতে কিছু সময় লাগে (কয়েক সেকেন্ড থেকে মিনিট, CDN provider অনুযায়ী)
- Scale issue: যদি প্রতি সেকেন্ডে বহুবার purge করতে হয় (frequently-changing content-এ), এটা নিজেই একটা bottleneck হয়ে যেতে পারে (CDN-এর purge API-তে rate limit থাকে সাধারণত)
কখন ব্যবহার করবে: emergency fix (ভুল content publish হয়ে গেছে, দ্রুত সরাতে হবে), অথবা মাঝে মাঝে (দিনে কয়েকবার) আপডেট হওয়া content (যেমন একটা news article edit হলো)।
পদ্ধতি ৩: Versioned URLs / Cache-Busting (সবচেয়ে elegant সমাধান, "সমস্যাটাই এড়িয়ে যাওয়া")
এই পদ্ধতিতে invalidation-এর দরকারই পড়ে না — বরং প্রতিটা নতুন version-এর জন্য একটা নতুন, unique URL ব্যবহার করা হয়:
পুরনো পদ্ধতি (সমস্যাযুক্ত):
style.css (TTL=1 year, কিন্তু content পরিবর্তন হলে
invalidate করতেই হবে)
Versioned URL পদ্ধতি:
style.a1b2c3d4.css (filename-এ content hash)
অথবা
style.css?v=2 (query param দিয়ে version)
নতুন deploy হলে:
style.e5f6g7h8.css (নতুন hash, সম্পূর্ণ নতুন URL)
কীভাবে এটা কাজ করে:
- HTML ফাইল রেফারেন্স করে
style.a1b2c3d4.css— যখন CSS পরিবর্তন হয়, নতুন build-এ hash বদলে যায় (style.e5f6g7h8.css), এবং HTML-ও নতুন hash রেফারেন্স করে - পুরনো URL (
style.a1b2c3d4.css) আর কখনো রেফারেন্স হয় না, কিন্তু এটা technically CDN cache-এ এখনো থাকতে পারে (কোনো ক্ষতি নেই, কারণ কেউ সেটা আর চাইবে না) — TTL অনুযায়ী স্বাভাবিকভাবে expire হবে বা eviction policy-তে সরে যাবে - নতুন URL (
style.e5f6g7h8.css) একটা সম্পূর্ণ নতুন cache entry — CDN এটাকে "নতুন" content হিসেবে treat করে, প্রথমবার cache-miss হয়ে origin থেকে আনবে, তারপর অত্যন্ত দীর্ঘ TTL (এমনকি "immutable" — কখনো পরিবর্তন হবে না, কারণ hash-ই তো content-নির্ভর) সেট করা যায়
এই approach-এর সবচেয়ে বড় সুবিধা: invalidation সমস্যাটাই আর নেই — তুমি কখনো "existing cache entry invalidate" করছো না, শুধু নতুন entry তৈরি করছো এবং reference পয়েন্ট বদলে দিচ্ছো। এটাই সবচেয়ে robust, race-condition-free সমাধান।
তিনটা পদ্ধতির তুলনা এবং কখন কোনটা
| Content Type | সুপারিশকৃত পদ্ধতি | যুক্তি |
|---|---|---|
| Static assets (JS, CSS, images with build hash) | Versioned URL + অত্যন্ত দীর্ঘ TTL (immutable) | Invalidation-এর দরকারই নেই, সবচেয়ে দ্রুত এবং নির্ভরযোগ্য |
| API response (frequently changing, যেমন product price) | ছোট TTL (সেকেন্ড থেকে কয়েক মিনিট) | Freshness গুরুত্বপূর্ণ, purge করার মতো frequent update-এর জন্য অবাস্তব |
| News article / CMS content | মাঝারি TTL + Purge API (edit হলে) | বেশিরভাগ সময় TTL যথেষ্ট, কিন্তু হঠাৎ edit হলে purge দিয়ে দ্রুত propagate করা |
| Emergency fix (ভুল কনটেন্ট প্রকাশিত হয়েছে) | Purge API (সরাসরি, priority) | তাৎক্ষণিক সমাধান দরকার, TTL অপেক্ষা করার সময় নেই |
পার্ট ৫ — Cache Key Design: যেখানে সবচেয়ে বেশি Production বাগ হয়
Cache Key কী
CDN কীভাবে বোঝে দুইটা ভিন্ন request একই content চাচ্ছে কিনা? এর উত্তর Cache Key-তে — সাধারণত URL + কিছু নির্দিষ্ট request attribute (header, query parameter, cookie) মিলিয়ে একটা key তৈরি করা হয়, এবং সেই key দিয়েই cache lookup হয়।
Cache Key = f(URL, নির্দিষ্ট headers, নির্দিষ্ট query params, ...)
সমস্যা ১: অপ্রয়োজনীয় Parameter Cache Key-তে থাকলে — "Cache Fragmentation"
ধরো তোমার ওয়েবসাইটের একটা প্রোডাক্ট পেজ আছে: /product/123
যদি Marketing team ভিন্ন ভিন্ন channel থেকে traffic ট্র্যাক করার জন্য UTM parameter যোগ করে:
/product/123?utm_source=facebook
/product/123?utm_source=google
/product/123?utm_source=email
এই তিনটা URL-এর actual content (product page) সম্পূর্ণ একই — কিন্তু যদি cache key-তে পুরো query string অন্তর্ভুক্ত থাকে (ডিফল্ট আচরণ অনেক CDN-এ), তাহলে CDN এই তিনটাকে তিনটা আলাদা cache entry হিসেবে দেখবে!
ফলাফল:
- একই content তিনবার cache-এ storage নেয় (storage অপচয়)
- Cache hit ratio কমে যায় — যদি ১০০টা ভিন্ন UTM source থাকে, একই content-এর জন্য ১০০টা আলাদা cache miss হতে পারে, যদিও প্রকৃতপক্ষে একটাই content সার্ভ করা উচিত ছিল
সমাধান: cache key configuration-এ বলে দাও utm_* জাতীয় parameter ignore করতে (cache key generation-এ অন্তর্ভুক্ত না করতে), কিন্তু origin-এ request পাঠানোর সময় সেগুলো রেখে দিতে পারো (analytics-এর জন্য, যদি দরকার হয়)।
সমস্যা ২: প্রয়োজনীয় Parameter/Header Cache Key থেকে বাদ পড়লে — ভুল User-কে ভুল Content
উল্টো সমস্যা: ধরো তোমার সাইট Accept-Language header দেখে ভিন্ন ভাষায় response দেয় (Bangla vs English)। যদি cache key-তে এই header অন্তর্ভুক্ত না থাকে:
User A (Accept-Language: bn) → /home → cache miss → origin থেকে
Bangla response আসলো,
cache key শুধু URL ভিত্তিক
হওয়ায় "generic" cache-এ সেভ হলো
User B (Accept-Language: en) → /home → cache HIT!
(কারণ URL একই, key-তে
language নেই)
কিন্তু ভুল করে Bangla
response পেয়ে গেলো!
এটা একটা গুরুতর bug — user B ইংরেজি চেয়েছিল, কিন্তু cache key ভুলভাবে ডিজাইন করার কারণে সে বাংলা content পেয়ে গেলো, যেটা user A-এর জন্য cache হয়েছিল।
সমাধান: যদি response সত্যিই একটা নির্দিষ্ট header/parameter অনুযায়ী আলাদা হয়, সেটা cache key-তে অন্তর্ভুক্ত করতেই হবে (একে "Vary" header বলা হয় HTTP-তে — Vary: Accept-Language server বলে দেয় CDN-কে যে এই header অনুযায়ী response আলাদা হতে পারে, তাই সেটা cache key-এর অংশ হওয়া উচিত)।
মূল ডিজাইন নীতি (মুখস্থ রাখার মতো)
Cache key-তে শুধুমাত্র সেই dimension (URL অংশ, header, param) রাখো যেগুলো actual response content-কে বদলায় — তার বেশি না, তার কমও না।
- বেশি রাখলে → cache fragmentation, কম hit ratio (সমস্যা ১)
- কম রাখলে → ভুল ইউজারকে ভুল content দেখানোর ঝুঁকি (সমস্যা ২, একটা serious correctness bug, শুধু performance সমস্যা না)
একটা বাস্তব উদাহরণ — Personalized কিন্তু Cacheable Content Design
ধরো তোমার হোমপেজ প্রতিটা logged-in user-এর জন্য "welcome, [নাম]" দেখায় — এটা naive ভাবে cache করলে ভয়ংকর সমস্যা (একজনের নাম আরেকজন দেখবে!)।
ভালো ডিজাইন: পুরো পেজ CDN-এ cache না করে, পেজের স্ট্যাটিক অংশ (layout, navigation, footer) CDN-এ cache করা এবং personalized অংশ (নাম, ব্যক্তিগত ড্যাশবোর্ড ডেটা) client-side JavaScript দিয়ে আলাদা API call-এ (যেটা CDN cache করে না, বা user-নির্দিষ্ট token cache key-তে রাখে) লোড করা। এটাই "cache the shell, personalize via API" প্যাটার্ন — অনেক modern web app এই approach ব্যবহার করে।
পার্ট ৬ — সম্পূর্ণ কেস স্টাডি: একটা E-commerce Product Page CDN Strategy
ধরো তুমি একটা বড় e-commerce সাইটের CDN কৌশল ডিজাইন করছো:
Component Cache Strategy
Product images (static) → Versioned URL (hash-ভিত্তিক),
TTL = 1 বছর (immutable)
Cache key: শুধু URL path
Product page HTML (mostly → TTL = 5 মিনিট, cache key: URL
static, দাম মাঝে মাঝে বদলায়) + Accept-Language (Vary header)
Purge API ব্যবহার হবে যদি দাম হঠাৎ
emergency ভাবে বদলাতে হয় (ভুল দাম
প্রকাশিত হলে)
Product price (via API, → খুব ছোট TTL (৩০ সেকেন্ড) অথবা
frequently changing) cache না করাই ভালো, সরাসরি origin
(stale price দেখানো বিপজ্জনক — customer
ভুল দামে কিনতে পারে বা confuse হতে পারে)
User-specific cart/wishlist → CDN cache করা হবে না (personalized,
highly dynamic), সরাসরি origin/backend-এ
যাবে, অথবা Redis-এর মতো application-level
cache ব্যবহার হবে (CDN-level না)
Marketing campaign traffic → UTM parameters cache key থেকে বাদ
(UTM parameters) (ignore) করা হবে যাতে cache
fragmentation না হয়
Origin server protection → Origin Shield বসানো হবে যাতে flash
sale-এর সময় (হঠাৎ TTL expire + massive
traffic spike) origin-এ thundering herd
না হয়
এখানে একটা গুরুত্বপূর্ণ বিজনেস-লজিক সংযোগ: product price-এর মতো সংবেদনশীল ডেটার জন্য stale cache মানে সরাসরি ব্যবসায়িক ঝুঁকি (ভুল দামে বিক্রি) — তাই এখানে CDN caching-এর aggressive ব্যবহার এড়িয়ে চলা, বা অত্যন্ত ছোট TTL রাখা যুক্তিসঙ্গত, যদিও এটা performance-এর সামান্য মূল্য দিতে হয়। এটাই একটা সিনিয়র-লেভেল trade-off discussion — pure performance optimization না, বরং business risk বিবেচনা করে caching strategy ঠিক করা।
পার্ট ৭ — Consolidation: Interview-Style প্রশ্ন
নিজে নিজে (নোট ছাড়া, জোরে বলে) উত্তর দেওয়ার চেষ্টা করো:
- PoP কী, এবং Day 8-এর Anycast/GeoDNS জ্ঞান কীভাবে ব্যবহার হয় user-কে সঠিক PoP-তে পাঠাতে?
- "Thundering herd on origin" সমস্যাটা ঠিক কীভাবে ঘটে, এবং Origin Shield কীভাবে (request coalescing mechanism ব্যবহার করে) এটা সমাধান করে?
- তিনটা cache invalidation পদ্ধতি (TTL, Purge API, Versioned URL) — প্রতিটার সুবিধা-অসুবিধা কী, এবং versioned URL কেন "সমস্যাটাই এড়িয়ে যায়" বলা হয়?
- Cache key-তে অপ্রয়োজনীয় parameter (যেমন UTM) থাকলে কী সমস্যা হয় ("cache fragmentation")?
- Cache key থেকে প্রয়োজনীয় header (যেমন Accept-Language) বাদ পড়লে কী মারাত্মক bug হতে পারে — একটা concrete উদাহরণ দিয়ে ব্যাখ্যা করো।
- "Cache the shell, personalize via API" প্যাটার্ন কী, এবং কেন এটা logged-in user-এর personalized হোমপেজের জন্য প্রয়োজনীয়?
- একটা e-commerce সাইটের product price data কেন aggressively cache করা উচিত না, যদিও এটা performance-এর জন্য ভালো হতো — business risk প্রসঙ্গে ব্যাখ্যা করো।
- একটা flash sale ইভেন্টে (হঠাৎ massive traffic spike + cache TTL expire একসাথে) Origin Shield না থাকলে কী ঘটতে পারে?
Day 10 · Load balancing L4 vs L7, algorithms, health checks
পার্ট ০ — Day 4-9 থেকে সংযোগ: এখন পর্যন্ত request একটা PoP/Server-এ পৌঁছেছে, তারপর?
এখন পর্যন্ত আমরা দেখেছি একটা request কীভাবে ভ্রমণ করে: DNS (Day 8) দিয়ে IP পাওয়া, TCP (Day 4) দিয়ে connection, TLS (Day 6) দিয়ে secure channel, HTTP (Day 7) দিয়ে actual data, এবং CDN (Day 9) দিয়ে কাছের PoP-তে পৌঁছানো।
কিন্তু বাস্তবে কোনো single server সব traffic হ্যান্ডেল করে না — একটা backend "service" আসলে অনেকগুলো identical server instance-এর সমষ্টি (হাই ট্রাফিক সামলাতে, এবং single-point-of-failure এড়াতে)। Load Balancer হলো সেই কম্পোনেন্ট যেটা ঠিক করে দেয় একটা নির্দিষ্ট request কোন specific backend server-এ যাবে।
একটা analogy
Load Balancer-কে ভাবো একটা ব্যাংকের লবিতে থাকা ম্যানেজার হিসেবে — গ্রাহকরা আসছে, কিন্তু ব্যাংকে ১০টা কাউন্টার (backend server) আছে। ম্যানেজার প্রতিটা গ্রাহককে দেখে ঠিক করে দেয় কোন কাউন্টারে যেতে হবে — কেউ যেন সব একটা কাউন্টারে জমে না যায়, আর কোনো কাউন্টার যদি বন্ধ (down) থাকে সেখানে যেন কাউকে না পাঠানো হয়।
পার্ট ১ — L4 vs L7 Load Balancing: একদম বেসিক থেকে
OSI Layer রিমাইন্ডার (Day 4-এর পার্ট ০ থেকে)
- Layer 4 (Transport) — TCP/UDP, শুধু IP address + port নিয়ে কাজ করে
- Layer 7 (Application) — HTTP, actual request content (URL path, header, cookie, body) নিয়ে কাজ করে
L4 Load Balancing — শুধু "প্যাকেট ফরওয়ার্ড করা", কনটেন্ট না দেখে
L4 LB শুধু TCP/UDP প্যাকেটের header দেখে (source/dest IP, port) — প্যাকেটের ভেতরের actual data (HTTP request-এর মধ্যে কী আছে) সে দেখেই না, বা দেখতে পারে না (encrypted হলে তো একদমই না, Day 6)।
Client ──[TCP packet, dest_port=443]──→ L4 Load Balancer
│
▼ (শুধু IP/port দেখে
backend নির্বাচন করে)
Backend Server (encrypted
content অপরিবর্তিত থাকে,
LB এটা পড়েনি)
কাজের ধরন: L4 LB মূলত packet-লেভেলে NAT বা routing করে — কখনো কখনো এটা connection-এর জন্য শুধু একটা রুট নির্ধারণ করে দেয় এবং তারপর প্যাকেট সরাসরি সেই backend-এ যেতে থাকে (LB নিজে প্রতিটা প্যাকেট প্রসেস না করেই), যাকে বলে "DSR — Direct Server Return" বা transparent forwarding। এই কারণে L4 LB অত্যন্ত দ্রুত এবং কম CPU-intensive।
L7 Load Balancing — Content দেখে বুদ্ধিমান রাউটিং
L7 LB সম্পূর্ণ HTTP request parse করে — URL path, header, cookie, এমনকি body পর্যন্ত দেখতে পারে (কারণ এটা TLS terminate করে, Day 6-এর "TLS termination at LB" আলোচনা মনে করো)।
Client ──[HTTPS request]──→ L7 Load Balancer (TLS terminate করে,
HTTP content পড়ে)
│
┌───────────────┼───────────────┐
▼ ▼ ▼
/api/users /api/orders /api/payments
→ Service A → Service B → Service C
L7 LB যা করতে পারে যা L4 পারে না:
- Path-based routing:
/api/users→ User Service,/api/orders→ Order Service (microservices architecture-এ অপরিহার্য) - Header/Cookie-based routing: A/B testing (একটা নির্দিষ্ট cookie থাকলে নতুন version-এ পাঠানো), canary deployment
- Request/Response transformation: header যোগ/বিয়োগ করা, URL rewrite করা
- SSL Termination: TLS এখানেই terminate হয় (Day 6)
তুলনা টেবিল
| বিষয় | L4 Load Balancer | L7 Load Balancer |
|---|---|---|
| দেখে কী | IP + Port | পুরো HTTP request (path, header, cookie, body) |
| গতি/CPU cost | অত্যন্ত দ্রুত, কম CPU | তুলনামূলক ধীর, বেশি CPU (deep packet parsing) |
| Routing granularity | কম (শুধু IP/port ভিত্তিক) | বেশি (content-ভিত্তিক, smart) |
| SSL Termination | সাধারণত করে না (passthrough) | করতে পারে |
| ব্যবহারের উদাহরণ | Database cluster-এর সামনে, raw TCP/UDP traffic, high-throughput scenario | Web application, microservices, API gateway |
| উদাহরণ টুল | AWS NLB, IPVS, HAProxy (L4 mode) | NGINX, Envoy, AWS ALB, HAProxy (L7 mode) |
ডিসিশন রুল (ইন্টারভিউতে সরাসরি বলার মতো)
যদি শুধু raw throughput এবং simple, content-agnostic routing দরকার হয় (database connection distribute করা, বা একই ধরনের সব backend যেখানে content দেখার দরকার নেই) → L4। যদি smart, content-aware routing দরকার (microservices-এ path অনুযায়ী ভিন্ন service-এ পাঠানো, বা A/B testing) → L7।
Production Reality: বড় সিস্টেমে প্রায়ই দুটোই একসাথে, layered ভাবে ব্যবহার করা হয় — একটা L4 LB (দ্রুত, raw ট্রাফিক distribute করার জন্য, প্রায়ই DDoS-resilient edge layer হিসেবে) তারপরে একটা L7 LB layer (smart routing-এর জন্য)।
পার্ট ২ — Load Balancing Algorithms: কীভাবে ঠিক করা হয় কোন Server-এ পাঠাবে
এখন প্রশ্ন হলো: multiple healthy backend server থাকলে (L4 বা L7 যেকোনোটাই), কোন নির্দিষ্ট server-টা বেছে নেওয়া হবে একটা নির্দিষ্ট request-এর জন্য?
Round Robin — সবচেয়ে সহজ
প্রতিটা request পালাক্রমে পরের সার্ভারে পাঠানো হয়:
Request 1 → Server A
Request 2 → Server B
Request 3 → Server C
Request 4 → Server A (আবার প্রথম থেকে)
সমস্যা: যদি সব সার্ভার সমান ক্ষমতার না হয় (একটা সার্ভারের হার্ডওয়্যার শক্তিশালী, আরেকটার কম), Round Robin উভয়কে সমান লোড দেয় — দুর্বল সার্ভার overload হয়ে যেতে পারে।
Weighted Round Robin — ক্ষমতা অনুযায়ী ভাগ
প্রতিটা সার্ভারকে একটা "weight" দেওয়া হয় (ক্ষমতার অনুপাতে) — শক্তিশালী সার্ভার বেশি request পায়:
Server A (weight=3), Server B (weight=1)
→ প্রতি ৪টা request-এর মধ্যে ৩টা যাবে A-তে, ১টা B-তে
ব্যবহার: heterogeneous hardware (কিছু সার্ভার নতুন/শক্তিশালী, কিছু পুরনো) — cloud migration-এর সময় mixed instance type থাকলে এটা প্রাসঙ্গিক।
Least Connections — বর্তমান লোড দেখে
যে সার্ভারে এই মুহূর্তে সবচেয়ে কম active connection আছে, সেখানে পরের request পাঠানো হয়।
কেন এটা Round Robin-এর চেয়ে ভালো কিছু ক্ষেত্রে: ধরো কিছু request দ্রুত শেষ হয় (কয়েক ms), কিছু request ধীর (কয়েক সেকেন্ড, যেমন একটা ভারী রিপোর্ট জেনারেশন)। Round Robin যদি একটা সার্ভারে ধারাবাহিকভাবে অনেকগুলো "ধীর" request পাঠিয়ে দেয় (কাকতালীয়ভাবে), সেই সার্ভার overload হয়ে যাবে, যদিও অন্য সার্ভার তুলনামূলক ফাঁকা। Least Connections এই সমস্যা এড়ায় কারণ এটা real-time load দেখে সিদ্ধান্ত নেয়।
Least Response Time — Latency-Sensitive সিস্টেমে
Least Connections-এর সাথে response time-ও বিবেচনা করে — যে সার্ভার সবচেয়ে কম connection এবং সবচেয়ে কম latency দেখাচ্ছে, সেখানে পাঠানো হয়। এটা latency-critical সিস্টেমে (real-time API) বেশি কার্যকর, কারণ এটা শুধু "কম busy" না, "দ্রুত সাড়া দিচ্ছে" এমন সার্ভার খুঁজে বের করে।
IP Hash / Consistent Hashing — Session Affinity বা Cache Locality-র জন্য
Client-এর কোনো একটা attribute (সাধারণত IP address, বা কোনো নির্দিষ্ট key) hash করে সবসময় একই সার্ভারে পাঠানো হয় (যতক্ষণ সার্ভার-সংখ্যা অপরিবর্তিত থাকে)।
কেন দরকার: কিছু সিস্টেমে session affinity (sticky session) দরকার হয় — যেমন যদি একটা user-এর session data একটা নির্দিষ্ট সার্ভারের in-memory cache-এ রাখা থাকে (server-side session storage, distributed cache ছাড়া), তাহলে সেই user-এর প্রতিটা পরবর্তী request সেই একই সার্ভারে যাওয়া দরকার, নাহলে session data খুঁজে পাওয়া যাবে না।
সারাংশ টেবিল
| Algorithm | মূল ধারণা | কখন ভালো |
|---|---|---|
| Round Robin | সমান ভাগে পালাক্রমে | সব সার্ভার সমান ক্ষমতার, request গুলো সমরূপ (uniform) |
| Weighted Round Robin | ক্ষমতা অনুপাতে ভাগ | Heterogeneous hardware |
| Least Connections | কম-busy সার্ভারে পাঠানো | Request duration ভ্যারি করলে |
| Least Response Time | কম-busy + দ্রুত-responding সার্ভারে | Latency-sensitive সিস্টেম |
| IP Hash / Consistent Hashing | নির্দিষ্ট key সবসময় নির্দিষ্ট সার্ভারে | Session affinity, cache locality দরকার |
পার্ট ৩ — Consistent Hashing: গভীরে বোঝা (আজকের সবচেয়ে গুরুত্বপূর্ণ অংশ)
সমস্যাটা প্রথমে বুঝি — Naive Hashing কেন কাজ করে না
ধরো তোমার ৫টা caching server আছে, এবং তুমি একটা সহজ পদ্ধতিতে key distribute করছো:
server_index = hash(key) % N (N = সার্ভার সংখ্যা)
৫টা সার্ভার থাকা অবস্থায় (N=5), hash("user_123") % 5 = 2 মানে Server 2-তে যাবে।
সমস্যা: যদি একটা সার্ভার যোগ হয় (N=5 থেকে N=6 হলো, একটা নতুন সার্ভার যোগ করলে বা ক্র্যাশ করলে), প্রায় প্রতিটা key-র জন্য hash(key) % N-এর ফলাফল বদলে যায় (কারণ modulo-র denominator বদলে গেছে) — মানে প্রায় সব key নতুন, ভিন্ন সার্ভারে "map" হয়ে যায়।
Practical প্রভাব (ধ্বংসাত্মক):
- যদি এটা একটা caching layer হয় (Redis-এর মতো), প্রায় সব cache entry হঠাৎ "ভুল" সার্ভারে খোঁজা হবে — massive cache miss (cache stampede-এর মতো একটা পরিস্থিতি তৈরি হবে, যেটা Day 18-তে বিস্তারিত দেখবো), origin/database-এ আকস্মিক ভারী লোড
- যদি এটা session affinity-র জন্য ব্যবহার হয়, প্রায় সব ইউজার হঠাৎ "নতুন" সার্ভারে যাবে, তাদের session data খুঁজে না পেয়ে re-login বা re-authenticate করতে হতে পারে
Consistent Hashing সমাধান — Hash Ring ধারণা
Consistent Hashing-এ, সার্ভার এবং key দুটোকেই একই hash space-এ (একটা কাল্পনিক বৃত্ত বা "ring") ম্যাপ করা হয়:
Server A (hash position: 30)
/ \
Key3 (hash: 20) Server B (hash: 90)
│ │
│ HASH RING (0-360°) │
│ │
Server D (hash: 250) Key1 (hash: 100)
\ /
Server C (hash: 180)——Key2 (hash: 170)
নিয়ম: প্রতিটা key তার hash position থেকে ঘড়ির কাঁটার দিকে (clockwise) সবচেয়ে কাছের সার্ভারে যায়।
- Key3 (hash 20) → clockwise-এ প্রথম সার্ভার Server A (30) → Key3 যাবে Server A-তে
- Key1 (hash 100) → clockwise-এ প্রথম সার্ভার Server C (180) → Key1 যাবে Server C-তে
- Key2 (hash 170) → clockwise-এ প্রথম সার্ভার Server C (180) → Key2 যাবে Server C-তে
এখন একটা সার্ভার যোগ/বিয়োগ হলে কী ঘটে — এখানেই ম্যাজিক
ধরো Server C (hash 180) down হয়ে গেলো। শুধুমাত্র Server C-তে ম্যাপ হওয়া key-গুলো (Key1, Key2 — যেগুলো clockwise-এ Server C-তে পড়তো) এখন redirect হবে পরের clockwise সার্ভার — যেটা এখন Server D (250)।
Server C down হওয়ার পর:
Key1 (hash 100) → clockwise পরের সার্ভার এখন Server D (250)
Key2 (hash 170) → clockwise পরের সার্ভার এখন Server D (250)
কিন্তু Key3 (hash 20) → এখনও Server A (30)-এ, কোনো পরিবর্তন নেই!
মূল ফলাফল: শুধুমাত্র Server C-এর "responsibility range"-এর মধ্যে থাকা key-গুলোই পুনর্বিন্যাস হয়েছে — বাকি সব key (Key3, এবং Server A/B/D-এর responsibility range-এর সব key) অপরিবর্তিত থেকেছে। Naive modulo hashing-এ যেখানে প্রায় সব key বদলাতো, এখানে শুধু একটা ছোট অংশ (আনুমানিক 1/N ভাগ, N = সার্ভার সংখ্যা) বদলেছে।
Virtual Nodes — বাস্তবে কেন এটা যোগ করা হয়
উপরের simple উদাহরণে যদি সার্ভারগুলো ring-এ অসমানভাবে ছড়িয়ে থাকে (যেমন সব সার্ভার কাকতালীয়ভাবে ring-এর একটা ছোট অংশে জড়ো হয়ে যায়), তাহলে load অসমানভাবে বণ্টিত হবে — কিছু সার্ভার বিশাল responsibility range পাবে, কিছু সার্ভার সামান্য।
সমাধান: Virtual Nodes — প্রতিটা physical সার্ভারকে ring-এ একাধিক (সাধারণত ১০০-২০০টা) পয়েন্ট হিসেবে বসানো হয় (ভিন্ন hash function বা salt দিয়ে একই সার্ভারের একাধিক "virtual" representation তৈরি করে):
Server A → বাস্তবে ring-এ ১৫০টা ভিন্ন বিন্দুতে থাকে
(Virtual Node A1, A2, A3, ..., A150)
Server B → একইভাবে ১৫০টা ভিন্ন বিন্দুতে
Server C → একইভাবে ১৫০টা ভিন্ন বিন্দুতে
ফলাফল: প্রতিটা physical সার্ভারের "coverage" ring-এর অনেকগুলো ছোট ছোট অংশে ছড়িয়ে যায়, যা statistically load কে অনেক বেশি সমানভাবে বণ্টন করে (Law of Large Numbers-এর মতোই একটা যুক্তি — বেশি sample point মানে বেশি uniform distribution)।
Virtual Node ছাড়া সমস্যা: মাত্র কয়েকটা সার্ভার (কম virtual node) থাকলে, একটা সার্ভার down হলে তার পুরো responsibility শুধু একটা অন্য সার্ভারে গিয়ে পড়তে পারে (উপরের উদাহরণের মতো, সব দায়িত্ব শুধু Server D-তে গেলো) — এতে সেই একটা সার্ভার হঠাৎ overload হতে পারে। Virtual node দিয়ে responsibility অনেকগুলো সার্ভারের মধ্যে ছড়িয়ে যায়, single-point overload এড়ানো যায়।
তোমার Redis Cluster Experience-এর সাথে সরাসরি সংযোগ
Redis Cluster ঠিক এই একই মূল নীতি ব্যবহার করে, তবে একটা variant দিয়ে — Hash Slots (মোট 16384টা fixed slot, প্রতিটা key CRC16(key) % 16384 দিয়ে একটা slot-এ ম্যাপ হয়, এবং প্রতিটা slot একটা নির্দিষ্ট node-এ assign করা থাকে)।
কীভাবে এটা consistent hashing-এর সাথে সম্পর্কিত: এই fixed-slot approach আসলে consistent hashing-এর একটা practical, deterministic variant — node যোগ/বিয়োগ হলে, শুধু নির্দিষ্ট slot-গুলো এক node থেকে আরেকটাতে explicitly, controlled ভাবে migrate করা হয় (Redis-এর CLUSTER RESHARD কমান্ড দিয়ে), pure hash-ring-এর মতো automatic redistribution না — কিন্তু মূল উদ্দেশ্য একই: node পরিবর্তনে minimal key redistribution।
এই অভিজ্ঞতাটা ইন্টারভিউতে বলার সময়, তুমি বলতে পারো: "Redis Cluster-এ আমি hash slot rebalancing হ্যান্ডেল করেছি node scaling-এর সময়, যেটা আসলে consistent hashing-এরই একটা production-grade বাস্তবায়ন — মূল নীতিটা একই: node পরিবর্তনে সর্বনিম্ন key movement নিশ্চিত করা।"
পার্ট ৪ — Health Checks: LB কীভাবে জানে কোন Server "বেঁচে আছে"
Active Health Check
LB নিয়মিত (যেমন প্রতি ৫ সেকেন্ডে) প্রতিটা backend সার্ভারের একটা নির্দিষ্ট /health বা /ping endpoint-এ request পাঠায়। যদি সার্ভার সঠিকভাবে সাড়া দেয় (যেমন HTTP 200), সেটা "healthy" — নাহলে (timeout, error response) সেটা "unhealthy" মার্ক হয়।
LB → GET /health → Server A: 200 OK [healthy]
LB → GET /health → Server B: timeout [unhealthy candidate]
LB → GET /health → Server C: 500 Internal [unhealthy candidate]
Consecutive Failure Threshold: একটা single failure-এই সার্ভারকে বাদ দেওয়া হয় না (temporary network blip হতে পারে) — সাধারণত ৩টা consecutive failure (বা নির্দিষ্ট threshold) হলে তবেই "unhealthy" মার্ক করা হয়, rotation থেকে বাদ দেওয়া হয়।
Health check endpoint ডিজাইন করার সময় সতর্কতা: /health endpoint শুধু "process চলছে কিনা" চেক করা যথেষ্ট না — এটা downstream dependency-ও (database connection, cache connection) চেক করা উচিত, নাহলে LB একটা সার্ভারকে "healthy" মনে করবে যদিও সেটা database-এর সাথে connect করতে পারছে না এবং সব actual request fail করছে।
Passive Health Check
Active check-এর পাশাপাশি, LB actual traffic-এর response monitor করে — যদি একটা সার্ভার থেকে ধারাবাহিকভাবে error/timeout আসতে থাকে (real user request-এ), সেই সার্ভারকে সাময়িকভাবে rotation থেকে বাদ দেওয়া হয়, এমনকি active health check এখনো "healthy" বলছে থাকলেও।
কেন উভয়ই দরকার: Active check নিয়মিত interval-এ চেক করে, কিন্তু দুই check-এর মাঝখানে (যেমন ৫ সেকেন্ডের মধ্যে) যদি সার্ভার সমস্যায় পড়ে, Passive check সেটা তাৎক্ষণিকভাবে ধরতে পারে actual traffic থেকে, active check-এর জন্য অপেক্ষা না করেই।
Health Check Threshold Tuning — একটা গুরুত্বপূর্ণ Trade-off
| Threshold | সুবিধা | অসুবিধা |
|---|---|---|
| Aggressive (কম consecutive failure দরকার, কম interval) | দ্রুত bad সার্ভার সরানো যায় | Temporary blip-এও unnecessary সার্ভার বাদ পড়ে ("flapping") — সার্ভার বারবার rotation-এ ঢোকা-বেরোনো করে, যা নিজেই instability তৈরি করে |
| Lenient (বেশি consecutive failure দরকার, বেশি interval) | Flapping কম, স্থিতিশীল | সত্যিকারের bad সার্ভারেও কিছুক্ষণ traffic যেতেই থাকে, user-রা error দেখতে থাকে |
Production practice: সাধারণত একটা balanced threshold ব্যবহার হয় (যেমন ৩ consecutive failure, ৫-১০ সেকেন্ড interval), এবং exponential backoff-এর মতো ধারণা প্রয়োগ করা হয় — একবার unhealthy হলে সার্ভারকে সাথে সাথে আবার rotation-এ ফেরত না এনে, ধীরে ধীরে (কয়েকটা successful health check-এর পর) আস্থা ফিরিয়ে দেওয়া।
Graceful Removal — শুধু "নতুন request বন্ধ" করা, "চলমান request" কেটে দেওয়া না
একটা সার্ভার maintenance-এর জন্য সরাতে হলে, তাৎক্ষণিকভাবে সব connection কেটে দেওয়া উচিত না — বরং:
- LB-কে বলা হয় এই সার্ভারকে "draining" state-এ রাখতে — নতুন কোনো request আর এখানে পাঠানো হবে না
- কিন্তু ইতিমধ্যে চলমান request/connection সম্পূর্ণ হতে দেওয়া হয় (একটা grace period পর্যন্ত)
- Grace period শেষে (বা সব connection স্বাভাবিকভাবে শেষ হলে), সার্ভার সম্পূর্ণ rotation থেকে সরানো হয়
এটা zero-downtime deployment-এর (Day 170) একটা মূল ভিত্তি — deployment-এর সময় পুরনো সার্ভার instance-কে হঠাৎ kill না করে, প্রথমে LB rotation থেকে সরিয়ে (draining), চলমান request শেষ হতে দিয়ে, তারপর safely terminate করা।
পার্ট ৫ — সম্পূর্ণ কেস স্টাডি: একটা Consistent-Hashing-ভিত্তিক Caching Layer ডিজাইন (Deliverable)
ধরো তোমার একটা 5-সার্ভার Redis-backed caching layer আছে, এবং তুমি এর সামনে একটা load balancer বসাচ্ছো যেটা consistent hashing ব্যবহার করবে।
Architecture:
Client Requests (key: user_id বা session_id)
│
▼
Consistent Hash Router
(প্রতিটা Redis node-এর জন্য
~150টা virtual node ring-এ)
│
┌───────────────┼───────────────┬──────────┬──────────┐
▼ ▼ ▼ ▼ ▼
Redis Node 1 Redis Node 2 Redis Node 3 Node 4 Node 5
Scenario: Redis Node 3 down হয়ে গেলো
│
▼
শুধুমাত্র Node 3-এর virtual node-গুলোর responsibility range-এ
থাকা key-গুলো redistribute হবে (আনুমানিক ~20% keys, যেহেতু
5 নোডে সমানভাবে virtual node ছড়ানো), বাকি ~80% key-এর
জন্য কোনো পরিবর্তন নেই, cache hit ratio বজায় থাকে সেগুলোতে
Scenario: নতুন Redis Node 6 যোগ করা হলো (scaling up)
│
▼
Node 6-এর জন্য নতুন ~150টা virtual node ring-এ যোগ হয়,
প্রতিটা existing node থেকে সামান্য কিছু key (আনুমানিক
প্রতিটা থেকে ~1/6 অংশ) Node 6-এ migrate হয় — বাকি key
অপরিবর্তিত থাকে
এই ডিজাইনের গুরুত্বপূর্ণ প্রোডাকশন বিবরণ:
- Rehashing-এর সময় সাময়িক cache miss: যে key-গুলো নতুন নোডে move হচ্ছে, সেই সময়টুকুতে সেগুলোর জন্য cache miss হবে (নতুন নোডে ডেটা এখনো নেই) — origin/database থেকে আবার আনতে হবে, একবার। এটা প্রত্যাশিত এবং সাময়িক।
- Health check integration: Load balancer-এর নিজস্ব health check থাকবে প্রতিটা Redis node-এর জন্য — কোনো node unhealthy হলে সেটাকে ring থেকে সাময়িকভাবে সরিয়ে দেওয়া (virtual node বাদ দেওয়া), স্বয়ংক্রিয়ভাবে
পার্ট ৬ — Consolidation: Interview-Style প্রশ্ন
নিজে নিজে (নোট ছাড়া, জোরে বলে) উত্তর দেওয়ার চেষ্টা করো:
- L4 আর L7 Load Balancer-এর মধ্যে ঠিক পার্থক্য কী, এবং কেন L4 সাধারণত L7-এর চেয়ে দ্রুত?
- একটা microservices architecture-এ path-based routing (
/api/usersvs/api/orders) করতে হলে L4 নাকি L7 LB দরকার, এবং কেন? - Round Robin আর Least Connections-এর মধ্যে পার্থক্য — কোন ধরনের workload-এ (uniform vs variable request duration) কোনটা ভালো?
- Naive modulo hashing (
hash(key) % N) কেন সার্ভার সংখ্যা বদলালে সমস্যা তৈরি করে — একটা concrete উদাহরণ দিয়ে দেখাও। - Consistent Hashing কীভাবে এই সমস্যা সমাধান করে — hash ring concept ব্যবহার করে ব্যাখ্যা করো।
- Virtual Nodes না থাকলে কী সমস্যা হতে পারে, এবং এটা কীভাবে load distribution-কে আরও uniform করে?
- Redis Cluster-এর Hash Slot approach কীভাবে consistent hashing-এর ধারণার সাথে সম্পর্কিত?
- Active আর Passive health check-এর মধ্যে পার্থক্য কী, এবং কেন উভয়ই একসাথে থাকা প্রয়োজনীয়?
- Health check threshold খুব aggressive হলে কী সমস্যা হয় ("flapping" প্রসঙ্গে)?
- "Graceful removal / draining" কী, এবং এটা zero-downtime deployment-এর সাথে কীভাবে সম্পর্কিত?
Deliverable Exercise: পার্ট ৫-এর 5-নোড Redis caching layer-এর জন্য consistent hashing-ভিত্তিক load balancer হাতে এঁকে দেখাও — একটা node যোগ হলে এবং একটা node down হলে, key movement-এর প্রভাব উভয় ক্ষেত্রেই ডায়াগ্রামে দেখাও।
Day 11 · Reverse proxies, API gateways, service mesh basics
What: The layers that sit in front of (reverse proxy, API gateway) or between (service mesh) your services, handling routing, auth, and observability.
How to complete: Explain what an API gateway adds on top of a plain reverse proxy, and when a service mesh (e.g. Istio) becomes worth its operational cost.
Branch 1.3 — API Design (Days 12–15)
What: The contract layer between clients and your system — REST, gRPC, GraphQL — and how that contract survives changing requirements over time.
How to complete: Work through Days 12–15; you're done when you can justify a protocol choice (REST vs gRPC vs GraphQL) for a given client and defend a versioning strategy.
Day 12 · REST: resources, idempotency, pagination patterns
What: The dominant HTTP API style — modeling state as resources with verbs, and the idempotency/pagination conventions that keep large REST APIs usable.
How to complete: Design a paginated, idempotent REST API for a to-do list service, explicitly choosing cursor- vs offset-based pagination and justifying it.
Day 13 · gRPC, protobuf, streaming RPC, schema evolution
What: A binary, strongly-typed RPC framework built on HTTP/2 — faster and stricter than REST, with built-in support for streaming and schema versioning.
How to complete: Write a small protobuf schema, then explain the field-numbering rules that let you evolve it without breaking old clients.
Day 14 · GraphQL: resolvers, N+1, federation
What: A query language letting clients ask for exactly the fields they need across a graph of types — powerful, but prone to the N+1 query problem.
How to complete: Explain how the N+1 problem arises in a GraphQL resolver and how DataLoader-style batching fixes it; sketch a federated schema across 2 services.
Day 15 · Versioning, deprecation, contract testing
What: How an API changes safely once it has real clients — version headers/URLs, deprecation windows, and automated tests that catch breaking changes.
How to complete: Write a deprecation policy (timeline + client communication) for a public API endpoint, and describe how contract testing would catch a breaking change in CI.
Branch 1.4 — Caching Layer (Days 16–21)
What: The single highest-leverage technique for cutting latency and database load — and the set of failure modes (stampede, hot key) it introduces in exchange.
How to complete: Work Days 16–21 in order; you're done when you can pick a caching strategy and eviction policy for a given workload and explain how it fails under load.
Day 16 · Strategies: aside, through, behind, refresh-ahead
What: The four fundamental patterns for where the cache sits relative to reads and writes — each with different consistency and latency tradeoffs.
How to complete: Draw all four (cache-aside, write-through, write-behind, refresh-ahead) and state which one you'd pick for a read-heavy product catalog, with why.
Day 17 · Eviction: LRU, LFU, ARC, W-TinyLFU; hit-rate math
What: The policies that decide what gets kicked out of a full cache, and how to estimate the resulting hit rate for a given access pattern.
How to complete: Compare LRU vs LFU vs W-TinyLFU on a workload with a small hot set, and compute the expected hit rate for a cache sized at 10% of the working set.
Day 18 · Failure modes: stampede, hot key, penetration
What: The three classic ways caching goes wrong: everyone recomputes the same expired key at once, one key gets disproportionate traffic, or requests for non-existent keys bypass the cache entirely.
How to complete: For each failure mode, name one concrete mitigation (e.g. jittered TTLs, request coalescing, negative caching / bloom filters) and when you'd use it.
Day 19 · Redis internals: structures, memory, RDB vs AOF
What: How Redis actually stores data in memory (its core data structures) and persists it to disk via snapshotting (RDB) or an append-only log (AOF).
How to complete: Since this is a rehearsed strength, don't re-learn it — instead write out, unaided, the tradeoff between RDB and AOF and when you'd combine both.
Day 20 · Redis Cluster, Sentinel, Streams, Lua
What: Redis's scaling and HA story (Cluster for sharding, Sentinel for failover) plus two power features: Streams for lightweight messaging and Lua for atomicity.
How to complete: This is a rehearsed strength — practice articulating it fluently: explain how Redis Cluster shards keys and how Sentinel promotes a replica on failure.
Day 21 · Multi-tier caching + coherence problems
What: Stacking caches (browser → CDN → app → DB) for maximum speed, and the coherence problem that appears when one layer goes stale while others don't.
How to complete: Design a 3-tier cache for a product page and describe exactly how an update propagates (or fails to) through all three tiers.
Branch 1.5 — Relational Internals (Days 22–24)
What: What actually happens inside Postgres/MySQL below the SQL layer — how rows are stored, how concurrent transactions don't see each other's half-finished work, and how indexes make queries fast.
How to complete: Work Days 22–24; you're done when you can explain a query's execution plan and justify an index choice from first principles, not memorized rules.
Day 22 · Storage layout, MVCC, vacuum
What: How rows are physically laid out on disk, and MVCC — the mechanism that lets readers and writers proceed concurrently without blocking each other.
How to complete: Rehearsed strength — practice explaining MVCC (row versions, xmin/xmax) and why vacuum exists to reclaim dead tuples, without notes.
Day 23 · Isolation levels, phantoms, SSI, lock escalation
What: The spectrum of guarantees (read committed → serializable) about what a transaction can see mid-flight, and the anomalies each level still allows.
How to complete: Give a concrete example of a phantom read and explain how Serializable Snapshot Isolation (SSI) prevents it without pessimistic locking.
Day 24 · Indexing: B-tree, GIN, GiST, BRIN, partial, covering
What: The index types Postgres offers beyond the default B-tree, each suited to a different data shape (full-text, geometric, append-only, filtered).
How to complete: Rehearsed strength — for a given query, practice picking the right index type (e.g. GIN for JSONB, BRIN for time-ordered logs) and justifying it aloud.
🎯 GATE 1 — Day 25 · MOCK #1: URL Shortener
What: The first scored checkpoint — a full mock interview that forces you to combine everything from Phase 1 (estimation, networking, caching, relational basics) under real time pressure.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: estimation, hashing, cache design, read-heavy scale. Don't move on until you can truthfully check off:
- Size any system to ±1 order of magnitude in <5 min
- Trace an HTTP request browser→DB→browser without notes
🌳 PHASE 2 — DATA LAYER MASTERY (Days 26–50)
What: Everything that determines whether a system can actually hold and serve its data at scale — the storage engine and access pattern behind every design.
How to complete: Work the 5 branches in order, then sit Gate 2. Don't advance until you can defend a storage choice against two named alternatives.
Branch 2.1 — Postgres in Production (Days 26–30)
What: Running a relational database for real — connection limits, replicas, failover, and the query-plan literacy to fix a slow query instead of guessing.
How to complete: Work Days 26–30 in order; you're done when you can read an EXPLAIN ANALYZE output and propose a concrete fix for a slow join.
Day 26 · Connection pooling, PgBouncer modes, sizing math
What: Why a database can't handle thousands of raw client connections, and how PgBouncer's session/transaction/statement modes trade isolation for capacity.
How to complete: Rehearsed strength — practice deriving a pool size from (max_connections, concurrent app instances) and explaining transaction-mode PgBouncer.
Day 27 · Read replicas, replication lag, read-your-writes
What: Scaling reads by copying data to follower nodes, and the staleness window (replication lag) that can make a user's own write appear to vanish.
How to complete: Design a read-your-writes guarantee for a user profile page that reads from a replica, explaining exactly where you'd route the post-write read.
Day 28 · HA: streaming replication, Patroni, split-brain
What: Automated primary failover for Postgres, and the split-brain risk when two nodes both believe they're the primary at once.
How to complete: Explain how Patroni uses a distributed consensus store (etcd/Consul) to prevent split-brain during a failover, step by step.
Day 29 · Query optimization: EXPLAIN ANALYZE, join strategies
What: Reading Postgres's actual query execution plan to find the real bottleneck (sequential scan, bad join order, missing index) instead of guessing.
How to complete: Rehearsed strength — practice reading an EXPLAIN ANALYZE output live and narrating exactly which line reveals the problem and why.
Day 30 · Normalization vs denormalization — when to duplicate
What: The tradeoff between a clean normalized schema (no duplication, more joins) and a denormalized one (duplicated data, faster reads, harder writes).
How to complete: Take one normalized schema and denormalize one table for a specific read pattern, explaining exactly what write-path complexity you accepted.
Branch 2.2 — Storage Engines (Days 31–35)
What: How different databases store data under the hood — log-structured (LSM) vs B-tree, and the distributed engines (Cassandra, DynamoDB) built on top of them.
How to complete: Work Days 31–35; you're done when you can name a storage engine for a given access pattern and state its write/read amplification tradeoff.
Day 31 · LSM trees: memtable, SSTable, compaction
What: The write-optimized storage structure behind Cassandra, RocksDB, and many NoSQL stores — buffering writes in memory, flushing sorted files, and merging them.
How to complete: Draw the memtable → SSTable → compaction pipeline and explain why LSM trees favor write throughput over read latency.
Day 32 · B-tree vs LSM: write/read/space amplification
What: The three-way tradeoff between the two dominant storage structures — how much extra I/O or space each pays for a given workload.
How to complete: Fill in a comparison table (write amp, read amp, space amp) for B-tree vs LSM and state which wins for a write-heavy time-series workload.
Day 33 · Cassandra: ring, tunable consistency, hinted handoff
What: A leaderless, ring-partitioned database where you tune the consistency/availability tradeoff per query via read/write quorum settings.
How to complete: Explain how consistent hashing places a key on Cassandra's ring, and how hinted handoff covers a temporarily unreachable replica.
Day 34 · DynamoDB: partition keys, GSI/LSI, single-table design
What: A managed key-value/document store where partition key choice and index design (GSI/LSI) determine both performance and cost.
How to complete: Design a single-table DynamoDB schema for an e-commerce order system, choosing partition/sort keys and one GSI, and justify each choice.
Day 35 · Hot partitions and write-sharding mitigation
What: What happens when one partition key absorbs disproportionate traffic (a celebrity user, a viral item), and the sharding tricks that spread the load.
How to complete: Propose a write-sharding scheme (e.g. suffixing the partition key) for a hot counter, and explain how you'd merge the shards on read.
Branch 2.3 — Non-Relational & Files (Days 36–40)
What: Storage systems built for data that doesn't fit rows and columns — documents, blobs, content-addressed chunks, distributed filesystems, and distributed SQL.
How to complete: Work Days 36–40; you're done when you can pick between a document store, object storage, or distributed SQL for a given data shape and justify it.
Day 36 · Document stores: MongoDB, embedded vs referenced
What: A schema-flexible store for JSON-like documents, and the embedding-vs-referencing decision that mirrors normalization tradeoffs in a new shape.
How to complete: Model a blog-with-comments in MongoDB two ways (embedded, referenced) and state which access pattern makes each the right choice.
Day 37 · Object storage: S3 internals, multipart, lifecycle
What: Flat, infinitely-scalable blob storage — how large uploads are split into parts, and how lifecycle rules automatically tier or expire old objects.
How to complete: Explain the multipart upload protocol (init, part upload, complete) and design a lifecycle policy that moves old objects to cold storage after 90 days.
Day 38 · Content-addressed storage, chunking, Rabin dedup
What: Storing data by the hash of its content instead of a path, and Rabin fingerprinting — a way to chunk files so identical content dedupes even after edits.
How to complete: Explain why content-addressing gives free deduplication, and how Rabin chunking (vs fixed-size chunking) survives a small insertion in the middle of a file.
Day 39 · Distributed FS: GFS, HDFS, Colossus
What: Filesystems built for the same clusters running MapReduce/Spark — how they replicate blocks and separate metadata (namenode) from data (datanodes).
How to complete: Draw the read path for HDFS (client → namenode → datanode) and explain why namenode availability is a classic single point of failure to solve.
Day 40 · Distributed SQL: Spanner, CockroachDB, TiDB, Vitess
What: Systems that give you SQL and horizontal scale together — via true global clocks (Spanner) or Raft-replicated shards (CockroachDB, TiDB).
How to complete: Explain what TrueTime buys Spanner that a normal clock can't, and how CockroachDB achieves similar guarantees without atomic clocks.
Branch 2.4 — Search Infrastructure (Days 41–45)
What: How full-text search actually works — inverted indexes, tokenization, and relevance scoring — culminating in operating Elasticsearch at scale.
How to complete: Work Days 41–45; you're done when you can size an Elasticsearch cluster and explain your own CDC→ES pipeline end to end without notes.
Day 41 · Inverted indexes, postings, compression, skip lists
What: The core data structure of search — mapping each term to the list of documents containing it, compressed and skip-listed for fast intersection.
How to complete: Build a tiny inverted index by hand for 5 sentences, then explain why postings lists are compressed with delta + variable-byte encoding.
Day 42 · Tokenization, analyzers, stemming, n-grams
What: How raw text becomes searchable terms — splitting, lowercasing, stemming to a root form, and n-grams for partial/fuzzy matching.
How to complete: Trace "Running shoes!" through a standard analyzer step by step, then explain when you'd add an n-gram tokenizer instead (e.g. autocomplete).
Day 43 · Scoring: TF-IDF, BM25, precision vs recall
What: How search engines rank matching documents — term frequency weighted against how common a term is overall — and the precision/recall tradeoff in tuning it.
How to complete: Compute a toy TF-IDF score by hand for one term/document, then explain what BM25 changes about TF-IDF's saturation behavior.
Day 44 · Elasticsearch architecture, shard sizing math
What: How Elasticsearch clusters shard and replicate an index across nodes, and the sizing math (shard count vs data volume vs node count) that keeps it healthy.
How to complete: Rehearsed strength — practice deriving a shard count for a given daily index volume and retention period, out loud, from the sizing formula.
Day 45 · ES at scale: refresh, bulk index, hot-warm-cold
What: Operating Elasticsearch under real write load — refresh interval tuning, bulk indexing, and tiering old indices to cheaper "warm"/"cold" nodes.
How to complete: Rehearsed strength — narrate your own CDC → Elasticsearch pipeline end to end as a 5-minute case study, including one real tuning decision you made.
Branch 2.5 — Probabilistic & Hashing (Days 46–49)
What: Space-efficient approximate data structures that trade a small, bounded error for massive memory savings — plus the hashing schemes that keep distributed data balanced.
How to complete: Work Days 46–49; you're done when you can pick a probabilistic structure for a given constraint (memory vs exactness) and explain its error bound.
Day 46 · Vector search: embeddings, HNSW, IVF, hybrid
What: Finding the nearest vectors to a query embedding at scale — via graph-based (HNSW) or cluster-based (IVF) approximate nearest-neighbor indexes.
How to complete: Explain how HNSW's layered graph structure speeds up search versus brute-force cosine similarity, and when you'd combine vector search with keyword filters.
Day 47 · Bloom, Cuckoo, quotient filters; false-positive math
What: Probabilistic set-membership structures that answer "maybe present" or "definitely absent" in a fraction of the memory a real set would need.
How to complete: Compute the expected false-positive rate for a Bloom filter given its size and hash count, and explain one advantage Cuckoo filters have over Bloom filters.
Day 48 · HyperLogLog, Count-Min Sketch
What: Approximating cardinality ("how many unique visitors") and frequency ("how often did X appear") in near-constant memory regardless of dataset size.
How to complete: Explain, at a high level, how HyperLogLog uses the position of leading zeros in hashes to estimate cardinality, and Count-Min Sketch's error tradeoff.
Day 49 · Consistent hashing, jump hash, rendezvous hashing
What: The hashing schemes that let you add/remove nodes from a distributed system while remapping only a small fraction of keys, instead of nearly all of them.
How to complete: Draw consistent hashing's ring and show, concretely, how few keys move when one node is added — then explain when jump hash is a simpler, better fit.
🎯 GATE 2 — Day 50 · MOCK #2: Distributed Key-Value Store
What: The Phase 2 checkpoint — a mock that forces you to choose and defend a storage engine, partitioning scheme, and consistency model under interview conditions.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: partitioning, replication, consistency, engine choice. Don't move on until you can truthfully check off:
- For any access pattern: name an engine, beat two alternatives, state the cost of your choice
🌳 PHASE 3 — DISTRIBUTED SYSTEMS THEORY (Days 51–75)
What: The theory that separates senior answers from mid-level ones: reasoning correctly about consistency, consensus, and partial failure instead of gesturing at buzzwords.
How to complete: Work the 6 branches in order — they build directly on each other — then sit Gate 3. Don't advance until every consistency claim you make is precise.
Branch 3.1 — Consistency Foundations (Days 51–53)
What: The vocabulary for talking precisely about what a distributed system guarantees — CAP, PACELC, and the full spectrum from linearizable to eventual consistency.
How to complete: Work Days 51–53; you're done when you can classify a real system's guarantees correctly instead of reflexively citing CAP.
Day 51 · CAP — what it actually says, and common misuses
What: The theorem that a partitioned system must choose consistency or availability — and the many ways it gets misquoted as "pick 2 of 3, always".
How to complete: Write, in your own words, what CAP actually claims (only during a partition) and name one common CAP misconception you've heard in interviews.
Day 52 · PACELC; classify five real systems
What: CAP's extension: even without a partition, you still trade latency for consistency — PACELC makes that everyday tradeoff explicit.
How to complete: Classify 5 real systems (e.g. DynamoDB, Spanner, MongoDB, Cassandra, Postgres) on the PA/EL axis and justify each placement in one line.
Day 53 · Full spectrum: linearizable → eventual; session guarantees
What: The full ladder of consistency models between the strongest (linearizable) and weakest (eventual), including session guarantees like read-your-writes.
How to complete: Order 6 consistency models from strongest to weakest and give one system that provides each, from linearizable down to eventual.
Branch 3.2 — Replication & Partitioning (Days 54–59)
What: How data gets copied across nodes for durability (replication) and split across nodes for scale (partitioning) — and everything that can go wrong in each.
How to complete: Work Days 54–59; you're done when you can design a replication + partitioning scheme for a new system and name its failure modes upfront.
Day 54 · Single-leader mechanics, failover pitfalls, lost updates
What: The most common replication topology — one writer, many readers — and the lost-update and stale-failover bugs that appear when it fails over badly.
How to complete: Walk through a failover where an unacknowledged write is lost, and propose one mitigation (e.g. synchronous replication to at least one follower).
Day 55 · Multi-leader, conflict detection, geo-distributed writes
What: Accepting writes at multiple nodes (often per-region) for low-latency geo-distributed writes, at the cost of needing to detect and resolve conflicts.
How to complete: Design a conflict resolution strategy (last-write-wins vs merge) for a geo-distributed shopping cart and explain what each strategy loses.
Day 56 · Leaderless (Dynamo-style), quorums, W+R>N math
What: No designated leader — clients write to and read from a quorum of replicas, and the W+R>N inequality is what guarantees overlap between them.
How to complete: Pick N/W/R values for a given availability/consistency target and prove, with the inequality, that a read is guaranteed to see the latest write.
Day 57 · Anti-entropy, Merkle trees, gossip protocols
What: How leaderless systems repair replicas that drifted out of sync — comparing Merkle tree hashes to find differences efficiently, and gossip to spread state.
How to complete: Explain how a Merkle tree comparison avoids transferring an entire dataset to find a handful of differing keys between two replicas.
Day 58 · Secondary indexes in partitioned data: local vs global
What: Once data is sharded by primary key, indexing by a different field means choosing between a local index (per-shard, fast write, scatter-gather read) or a global one (fast read, cross-shard write).
How to complete: For a given query pattern, choose local vs global secondary indexing and state the exact write-path cost of your choice.
Day 59 · Rebalancing, request routing, ZooKeeper/etcd
What: How a cluster moves data when nodes are added/removed without downtime, and the coordination service (ZooKeeper/etcd) that tracks where each shard lives.
How to complete: Describe a rebalancing plan that avoids a thundering herd of data movement, and explain what ZooKeeper/etcd stores to make request routing correct.
Branch 3.3 — Consensus (Days 60–63)
What: How a group of unreliable nodes agrees on a single value or leader — the algorithmic core (Paxos, Raft) underneath every strongly-consistent distributed system.
How to complete: Work Days 60–63; you're done when you can explain Raft's leader election and log replication well enough to reason about a split-brain incident.
Day 60 · Paxos conceptually; safety vs liveness
What: The original consensus algorithm — notoriously hard to implement, but the conceptual root of every algorithm that lets nodes agree despite failures.
How to complete: Explain, without the formal proof, why Paxos guarantees safety (never two different values chosen) even though it can't guarantee liveness always.
Day 61 · Raft: election, log replication, membership change
What: The consensus algorithm designed to be understandable — explicit leader election, a replicated log, and a defined protocol for changing cluster membership.
How to complete: Draw a Raft leader election (term increment, vote request, majority) and explain how log replication commits an entry only after majority ack.
Day 62 · Split brain, fencing tokens, STONITH + real postmortems
What: What happens when a network partition causes two nodes to both believe they're the leader, and the techniques (fencing tokens, STONITH) that prevent damage.
How to complete: Read one real split-brain postmortem and explain how a fencing token would have prevented the stale leader from committing a conflicting write.
Day 63 · Distributed locks, lease expiry, the Redlock debate
What: Using a distributed system to coordinate mutual exclusion — and why lease expiry timing makes this subtler than a local lock, sparking the Redlock debate.
How to complete: Explain the core objection Martin Kleppmann raised against Redlock, and when a fencing-token-based lock is safer than a bare distributed lock.
Branch 3.4 — Time & Causality (Days 64–66)
What: Why "what time is it" is a genuinely hard distributed systems problem, and the clock schemes (logical, vector, hybrid) built to work around it.
How to complete: Work Days 64–66; you're done when you can explain why Spanner needs TrueTime and what a vector clock actually orders.
Day 64 · NTP drift, monotonic vs wall clock, skew bugs
What: Why physical clocks on different machines disagree even with NTP, and why code must distinguish a monotonic clock (for durations) from wall-clock time.
How to complete: Describe one real bug class caused by using wall-clock time for a duration measurement, and how a monotonic clock avoids it.
Day 65 · Lamport clocks, vector clocks, version vectors
What: Logical clocks that capture causal order ("happened-before") without relying on synchronized physical time — and how vector clocks detect concurrent (conflicting) events that Lamport clocks can't.
How to complete: Assign Lamport timestamps to a 3-event causal chain by hand, then explain what a vector clock reveals about two events that a Lamport clock hides.
Day 66 · Hybrid logical clocks, TrueTime, Spanner's approach
What: Combining physical and logical time (HLC), or bounding physical clock uncertainty explicitly (TrueTime) to get external consistency without full synchronization.
How to complete: Explain how Spanner's "commit wait" uses TrueTime's uncertainty bound to guarantee external consistency across data centers.
Branch 3.5 — Transactions Across Services (Days 67–70)
What: How to keep multiple services' data consistent when a single database transaction can't span them — 2PC's failure, sagas, and idempotency as the fallback.
How to complete: Work Days 67–70; you're done when you can design a saga with compensations for a multi-service booking flow.
Day 67 · 2PC: protocol, blocking problem, why it's avoided
What: The classic protocol for atomic commit across multiple databases — and the blocking problem (a crashed coordinator freezes all participants) that made it fall out of favor.
How to complete: Walk through 2PC's prepare/commit phases and identify exactly where a coordinator crash leaves participants blocked indefinitely.
Day 68 · Sagas: choreography vs orchestration, compensation
What: A sequence of local transactions with compensating actions to undo prior steps on failure — coordinated either by events (choreography) or a central orchestrator.
How to complete: Design a saga for "book flight + hotel" both ways (choreography, orchestration) and write the compensating action for each step.
Day 69 · Outbox pattern, transactional messaging, CDC correctness
What: Writing a business change and its outgoing event atomically (via an outbox table) so a message broker publish can never silently diverge from the DB write.
How to complete: Rehearsed strength — narrate the outbox pattern end to end and explain exactly what correctness problem it solves that a direct publish-after-commit doesn't.
Day 70 · Idempotency keys, dedup windows, "effectively-once"
What: Since true exactly-once delivery is impossible over a network, idempotency keys and dedup windows are how you fake it at the application layer.
How to complete: Design an idempotency-key scheme for a payment API, including how long you retain keys and what you return on a duplicate request.
Branch 3.6 — Failure Reasoning (Days 71–74)
What: How to reason about partial failure precisely — detecting it, tolerating malicious/corrupted nodes, and stating invariants clearly enough to defend a design.
How to complete: Work Days 71–74, ending with a full aloud recap of Phase 3 with no notes.
Day 71 · Failure detection, phi-accrual, timeouts vs correctness
What: Why you can never distinguish "slow" from "dead" with certainty, and how phi-accrual failure detectors give a probabilistic answer instead of a hard timeout.
How to complete: Explain why a fixed timeout is always a tradeoff between false positives and detection speed, and how phi-accrual adapts to network jitter instead.
Day 72 · Byzantine faults — and why they usually don't matter
What: Faults where a node actively lies or behaves arbitrarily (not just crashes) — rare in a single trusted datacenter, but central to blockchain-style systems.
How to complete: Explain why most internal distributed systems assume crash-stop (not Byzantine) faults, and name one context where that assumption breaks down.
Day 73 · Invariants, safety and liveness properties
What: The two categories every correctness claim falls into: safety ("nothing bad ever happens") and liveness ("something good eventually happens").
How to complete: State one safety and one liveness property for a distributed lock service, and explain why proving safety is usually easier than proving liveness.
Day 74 · Consolidation: explain all of Phase 3 aloud, no notes
What: The integration day — proving Phase 3's theory (consistency, replication, consensus, time, transactions, failure) is usable under pressure, not just read.
How to complete: Record yourself explaining all six Phase 3 branches aloud, back to back, with zero notes, then watch it back and note every hesitation.
🎯 GATE 3 — Day 75 · MOCK #3: Distributed Transaction / Booking System
What: The Phase 3 checkpoint — a mock built specifically to force saga design, isolation reasoning, and explicit statements about what breaks under partition.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: sagas, isolation, inventory consistency, failure handling. Don't move on until you can truthfully check off:
- State precisely what consistency guarantee any design provides, and what breaks under a network partition
🌳 PHASE 4 — STREAMING & EVENT-DRIVEN (Days 76–95)
What: Event-driven design — the pattern behind feeds, notifications, and analytics pipelines, and a genuine existing strength worth making dominant.
How to complete: Work the 5 branches in order, then sit Gate 4. Since this is a strength area, focus reps on articulation speed, not re-learning the material.
Branch 4.1 — Messaging Fundamentals (Days 76–77)
What: The vocabulary and guarantees underlying every messaging system — queue vs pub-sub vs log, and what "delivery guarantee" actually promises.
How to complete: Work Days 76–77; you're done when you can explain why a log (Kafka) behaves differently from a queue (SQS) for the same message.
Day 76 · Queue vs pub-sub vs log — semantics differ fundamentally
What: Three different messaging shapes: a queue (one consumer per message), pub-sub (many independent subscribers), and a log (replayable, ordered, retained).
How to complete: For a given use case (order processing, notifications, analytics), pick the right primitive of the three and explain why the other two would misbehave.
Day 77 · Delivery guarantees, ordering, backpressure
What: The three axes every message system must be evaluated on: how many times a message is delivered, whether order is preserved, and what happens when consumers fall behind.
How to complete: State the exact conditions under which "exactly-once" delivery is actually achievable, and design a backpressure strategy for a slow consumer.
Branch 4.2 — Kafka Deep Dive (Days 78–81)
What: The dominant distributed log — how it partitions, replicates, and lets producers/consumers scale independently.
How to complete: Work Days 78–81; you're done when you can explain Kafka's architecture and consumer rebalancing without hesitation.
Day 78 · Architecture: partitions, segments, ISR, controller
What: How a Kafka topic is split into ordered partitions, each partition into segment files, replicated to an in-sync-replica (ISR) set, coordinated by a controller.
How to complete: Rehearsed strength — practice drawing Kafka's architecture from a blank page: topic → partitions → segments → ISR → controller.
Day 79 · Producers: batching, acks, idempotent producer
What: How producers trade latency for throughput (batching) and durability (acks=0/1/all), and how the idempotent producer avoids duplicate writes on retry.
How to complete: Explain the durability difference between acks=1 and acks=all, and how the idempotent producer's sequence numbers prevent duplicate writes after a retry.
Day 80 · Consumer groups, rebalancing, sticky assignment
What: How multiple consumer instances split a topic's partitions among themselves, and what happens (a rebalance) when membership changes.
How to complete: Walk through a consumer joining an existing group and explain why sticky assignment reduces unnecessary partition movement during rebalance.
Day 81 · Log compaction, retention, tiered storage
What: Alternatives to simple time-based deletion — compaction keeps only the latest value per key, and tiered storage offloads old segments to cheaper storage.
How to complete: Explain when you'd use compacted retention (e.g. a changelog topic) instead of time-based retention, and what tiered storage trades off.
Branch 4.3 — Stream Processing (Days 82–86)
What: Computing over unbounded data as it arrives — windowing, state, and the architectural patterns (event sourcing, CQRS) that stream processing enables.
How to complete: Work Days 82–86; you're done when you can design a windowed aggregation and explain how it stays correct under late-arriving data.
Day 82 · Kafka Streams / Flink, local state stores
What: Stream processing frameworks that maintain local state (e.g. a running aggregate) co-located with the compute, backed by a changelog for recovery.
How to complete: Explain why a stream processor keeps state locally instead of round-tripping to a database, and how that state recovers after a crash.
Day 83 · Windowing: tumbling, sliding, session; watermarks
What: The three ways to group an unbounded stream into finite chunks for aggregation, and watermarks — the mechanism for deciding a window is "done" despite out-of-order arrivals.
How to complete: Define all three window types precisely and explain what a watermark of "5 minutes late" actually changes about when a window's result is emitted.
Day 84 · Event sourcing: replay, snapshots, tradeoffs
What: Storing every state change as an immutable event and deriving current state by replaying them — with snapshots to avoid replaying from the beginning every time.
How to complete: Design an event-sourced schema for a shopping cart, including a snapshot strategy, and state one real cost of this approach versus storing current state directly.
Day 85 · CQRS: read/write separation, projection lag
What: Splitting the write model from the read model entirely, so reads can be shaped for query performance — at the cost of a projection lag between write and read.
How to complete: Design a CQRS split for an order system and explain concretely how a client should handle the read-after-write lag on the projection.
Day 86 · Exactly-once in streams; Flink checkpointing
What: How stream processors approximate exactly-once semantics end to end via checkpointing (consistent snapshots) and transactional sinks.
How to complete: Explain Flink's checkpoint barrier mechanism and how it, combined with a transactional sink, delivers effectively-once processing.
Branch 4.4 — Operational Streaming (Days 87–89)
What: The operational realities of running streaming systems in production — schema changes, poison messages, and choosing among the many broker options.
How to complete: Work Days 87–89; you're done when you can design a DLQ strategy and justify a broker choice for a given latency/durability need.
Day 87 · Schema registry, Avro/Protobuf compatibility modes
What: A central service that validates producer/consumer schemas against each other, enforcing compatibility modes (backward/forward/full) so evolution doesn't break consumers.
How to complete: Explain the difference between backward and forward compatibility for a schema change, and which mode you'd enforce for a topic with many independent consumers.
Day 88 · DLQs, poison pills, retry topics
What: What to do with a message that a consumer can never successfully process — route it to a dead-letter queue instead of blocking the whole partition forever.
How to complete: Design a retry-topic chain (retry-1m, retry-10m, DLQ) for a payment consumer and state your criteria for when a message is truly "poison".
Day 89 · Pulsar, NATS, SQS/SNS, Kinesis — selection criteria
What: The landscape of alternatives to Kafka, each optimized differently — multi-tenancy (Pulsar), lightweight simplicity (NATS), or fully managed (SQS/Kinesis).
How to complete: Given a specific constraint (e.g. "no ops team", "multi-tenant SaaS"), pick the right broker from this list and name the one thing Kafka would cost you there.
Branch 4.5 — Analytics Storage (Days 90–94)
What: Where streamed data ends up for analysis — the lakehouse formats and OLAP engines built to query huge volumes of append-mostly data fast.
How to complete: Work Days 90–94; you're done when you can pick a table format and OLAP engine for a given analytics workload.
Day 90 · Lambda vs Kappa vs unified; reprocessing strategy
What: Architectural patterns for combining batch and streaming — running both pipelines (Lambda), streaming-only (Kappa), or a single unified engine — and how each replays history when logic changes.
How to complete: Compare Lambda vs Kappa's reprocessing story explicitly: what does each require you to do when a bug in the processing logic is found after the fact?
Day 91 · Lakehouse, Iceberg/Delta table formats
What: Table formats that add ACID transactions, schema evolution, and time travel on top of plain files in a data lake, closing the gap with a warehouse.
How to complete: Explain what problem Iceberg/Delta's metadata layer solves that raw Parquet files in S3 don't (e.g. atomic multi-file commits, snapshot isolation).
Day 92 · Parquet, ORC, encoding, predicate pushdown
What: Columnar file formats optimized for analytical scans, and predicate pushdown — skipping whole row groups using stored min/max statistics.
How to complete: Explain why columnar storage speeds up an aggregation query, and how predicate pushdown lets a query skip reading irrelevant row groups entirely.
Day 93 · ClickHouse, Druid, Pinot
What: Purpose-built OLAP engines for sub-second aggregation queries over huge event volumes — each with different ingestion and indexing tradeoffs.
How to complete: Pick one of the three for a real-time dashboard use case and name the specific ingestion or indexing feature that made it the right choice.
Day 94 · Time-series: downsampling, cardinality, retention
What: The specific challenges of time-series data — high cardinality tags exploding storage, and downsampling/retention policies to keep it bounded.
How to complete: Design a downsampling policy (raw → 1min → 1hr rollups) for metrics data and explain how high-cardinality tags could blow up this scheme.
🎯 GATE 4 — Day 95 · MOCK #4: Real-Time Analytics Pipeline
What: The Phase 4 checkpoint — a mock that forces an end-to-end streaming design with explicit reasoning about where duplicates, reordering, or loss can occur.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: streaming, windowing, OLAP storage, late data. Don't move on until you can truthfully check off:
- Design an end-to-end pipeline and state exactly where duplicates, reordering, and data loss can occur
🌳 PHASE 5 — PRODUCT SYSTEMS I (Days 96–120)
What: The canonical interview questions — feed, chat, search, rate limiter — where pattern fluency, not novel insight, is what gets rewarded.
How to complete: Work the 4 branches and 2 checkpoints in order, then sit Gate 5. Start your job application pipeline the same week — the loops take weeks to run.
Branch 5.1 — Feed & Social Graph (Days 96–99)
What: The canonical "design a news feed" problem — how to generate a personalized, ranked feed for users with wildly different follower/following counts.
How to complete: Work Days 96–99; you're done when you can design a feed's fanout strategy and defend it against the celebrity-account edge case.
Day 96 · Fanout-on-write vs read vs hybrid; celebrity problem
What: The core feed design decision — precompute each follower's feed on post (write), assemble it on request (read), or mix both — and why celebrity accounts break the naive write-fanout approach.
How to complete: Explain exactly why fanout-on-write fails for a celebrity with 100M followers, and design the hybrid approach that handles both cases.
Day 97 · Ranking: freshness decay, engagement signals
What: Ordering a feed by more than recency — combining a freshness-decay function with engagement signals (likes, comments, dwell time) into a ranking score.
How to complete: Write a toy ranking formula combining freshness decay and one engagement signal, and explain how you'd A/B test a change to its weights.
Day 98 · Social graph storage, adjacency, TAO-style design
What: Storing who-follows-whom at massive scale — adjacency list modeling and Facebook's TAO as a reference architecture for a graph-as-cache system.
How to complete: Design a social graph storage layer for "who follows X" and "does X follow Y" queries, and explain what TAO's caching layer adds on top of the DB.
Day 99 · Graph DBs, traversal cost, denormalized edges
What: When a dedicated graph database earns its keep versus a denormalized edge table in a relational/KV store, based on traversal depth and query pattern.
How to complete: State the traversal-depth threshold where a graph DB starts winning over denormalized edge tables, with a concrete query example.
🎯 CHECKPOINT — Day 100 · MOCK #5: News Feed (Twitter/Instagram)
What: A scored mock testing whether Branch 5.1's fanout/ranking/graph material holds up under live interview conditions.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: fanout strategy, ranking, celebrity problem, cache layers.
Branch 5.2 — Realtime & Messaging (Days 101–110)
What: The full "design WhatsApp/Messenger" problem — persistent connections at scale, message ordering, multi-device sync, and reliable push notifications.
How to complete: Work Days 101–110 in order; you're done when you can design a chat system's connection layer, ordering, and notification pipeline end to end.
Day 101 · WebSocket, SSE, long-poll — connection scaling
What: The three techniques for pushing data to clients without constant polling, and how each scales differently to millions of open connections.
How to complete: Compare WebSocket, SSE, and long-polling on connection cost and bidirectionality, and pick the right one for a chat app versus a live scoreboard.
Day 102 · Connection gateways, sticky routing, the C10M problem
What: Dedicated gateway servers that hold millions of persistent connections, routing messages to whichever gateway a user is stuck to (sticky routing).
How to complete: Explain why holding 10M concurrent connections (C10M) requires event-driven I/O instead of thread-per-connection, and how sticky routing finds the right gateway.
Day 103 · Message IDs, ordering, gap detection, sequence numbers
What: Giving every message a position a client can use to detect gaps and reorder out-of-sequence deliveries, which is essential once you have multiple gateways.
How to complete: Design a per-conversation sequence number scheme and explain how a client detects and recovers from a gap in the sequence.
Day 104 · Delivery receipts, read state, multi-device fanout
What: Tracking sent/delivered/read status per message per device, and fanning out a single message correctly across a user's phone, web, and desktop clients.
How to complete: Design the delivery-receipt state machine (sent → delivered → read) for a user with 3 logged-in devices, and state where each transition is recorded.
Day 105 · Offline queues, sync protocol, cold start
What: Queuing messages for a device that's offline, and the sync protocol a client runs on reconnect to catch up without re-downloading everything.
How to complete: Design a reconnect sync protocol using a last-seen sequence number, and state your queue retention limit for a device offline for a week.
Day 106 · Group fanout, large groups, broadcast amplification
What: The amplification problem when one message to a 10,000-member group becomes 10,000 individual deliveries, and the strategies to bound that cost.
How to complete: Propose a fanout strategy for a 50,000-member broadcast channel that avoids naive 1-to-50,000 amplification at send time.
Day 107 · Presence & typing indicators — cheap approximations
What: Why exact real-time presence for millions of users is expensive, and the approximations (heartbeats, debounced typing events) that make it cheap enough.
How to complete: Design a presence system using periodic heartbeats and explain the staleness window you're accepting in exchange for lower write volume.
Day 108 · E2E encryption: Signal protocol, design implications
What: How end-to-end encryption changes system design — the server can no longer read message content, which breaks server-side search, moderation, and multi-device sync naively.
How to complete: Explain the Signal protocol's double-ratchet at a high level, and name one product feature (e.g. server-side search) that E2E encryption forces you to redesign.
Day 109 · Push infra: APNs/FCM, tokens, retries, priorities
What: Delivering notifications to a backgrounded/closed app via the platform push services — device tokens, retry behavior, and priority levels.
How to complete: Rehearsed strength — practice explaining device token rotation and how you'd handle a burst of retries from APNs/FCM without duplicate notifications.
Day 110 · Notification dedup, batching, digest, quiet hours
What: Preventing notification fatigue at scale — deduplicating near-identical notifications, batching into digests, and respecting quiet hours per user.
How to complete: Rehearsed strength — narrate your own 100M+/day notification platform as a 5-minute case study covering dedup, batching, and quiet-hours logic.
🎯 CHECKPOINT — Day 111 · MOCK #6: WhatsApp / Messenger
What: A scored mock testing Branch 5.2's connection scaling, ordering, and sync material under interview time pressure.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: connection scaling, ordering, multi-device sync, offline.
Branch 5.3 — Search & Crawl (Days 112–115)
What: The infrastructure behind search-as-you-type and web-scale crawling — tries for autocomplete, ranking pipelines, and detecting near-duplicate pages.
How to complete: Work Days 112–115; you're done when you can design an autocomplete service and a polite, fresh web crawler.
Day 112 · Autocomplete: tries, top-k, prefix sharding
What: Serving ranked suggestions for a partial query in milliseconds using a trie (or precomputed top-k per prefix) sharded across servers for scale.
How to complete: Design a prefix-sharded autocomplete service for a search box and explain how you'd keep the top-k suggestions per prefix fresh as query popularity shifts.
Day 113 · Ranking pipeline: retrieval → ranking → blending
What: The multi-stage pattern behind most large-scale search/recommendation systems: cheaply retrieve a candidate set, then expensively rank it, then blend in business rules.
How to complete: Sketch a 3-stage pipeline (retrieval, ranking, blending) for a search product and explain why doing full ranking on the entire corpus wouldn't scale.
Day 114 · Web crawler: frontier, politeness, freshness
What: The components of a large-scale crawler — a URL frontier to prioritize what to fetch next, politeness rules (rate limits per host), and freshness policies for re-crawling.
How to complete: Design a crawler's frontier prioritization and politeness policy, and explain how you'd decide which pages to re-crawl more often.
Day 115 · Near-duplicate detection: SimHash, MinHash, shingling
What: Detecting pages that are nearly (not exactly) identical using locality-sensitive hashing techniques that make similar documents hash to similar values.
How to complete: Explain how SimHash's bit-difference threshold detects near-duplicates, and why shingling (overlapping n-grams) is the preprocessing step that makes it work.
Branch 5.4 — Traffic Control & Abuse (Days 116–119)
What: Protecting a system from its own users — rate limiting individual clients and detecting/mitigating coordinated abuse and attacks.
How to complete: Work Days 116–119; you're done when you can design a distributed rate limiter and name concrete abuse-mitigation layers.
Day 116 · Token/leaky bucket, sliding window — comparison
What: The core rate-limiting algorithms — token bucket (allows bursts), leaky bucket (smooths output), and sliding window (accurate but more state) — each with a different burst/accuracy tradeoff.
How to complete: Implement the token bucket algorithm on paper for a single client, then explain when sliding-window counters are worth their extra memory cost over it.
Day 117 · Distributed rate limiting: local+global hybrid
What: Rate limiting correctly across many servers — pure local counters undercount shared limits, and pure global counters add latency; hybrids balance both.
How to complete: Design a hybrid rate limiter (local approximate counter + periodic global sync via Redis) and state the over-limit error your design tolerates.
Day 118 · Bot detection, fingerprinting, CAPTCHA tradeoffs
What: Distinguishing automated abuse from real users via behavioral signals and device fingerprinting, and the user-friction cost every CAPTCHA imposes.
How to complete: Name 3 signals (beyond IP) you'd use to fingerprint a bot, and explain the tradeoff of adding a CAPTCHA step to a signup flow.
Day 119 · DDoS mitigation layers, scrubbing, edge rules
What: The layered defense against volumetric attacks — edge/CDN absorption, scrubbing centers that filter malicious traffic, and application-layer rules.
How to complete: Describe the layered path a DDoS attack meets (edge → scrubbing → app rules) and where a Layer 7 attack specifically needs to be caught.
🎯 GATE 5 — Day 120 · MOCK #7: Distributed Rate Limiter + Abuse Defense
What: The Phase 5 checkpoint — a mock combining consistency-vs-latency reasoning with adversarial thinking about how a design gets abused.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: consistency vs latency, adversarial design. Don't move on until you can truthfully check off:
- Design a feed, a chat system, and a rate limiter from cold start in 45 minutes each
⚠️ ACTION: Start applying + requesting referrals NOW — loops take 6–10 weeks; early interviews are themselves practice.
🌳 PHASE 6 — PRODUCT SYSTEMS II (Days 121–145)
What: The harder product-system questions — video, geospatial matching, money, and collaborative editing — where most candidates thin out under follow-up questions.
How to complete: Work the 5 branches and 3 checkpoints in order, then sit Gate 6. By the end, no common FAANG design question should feel unfamiliar.
Branch 6.1 — Video & Streaming (Days 121–126)
What: The full YouTube/Netflix pipeline — ingest, transcode, package, adaptively stream, and distribute video at global scale, live or on-demand.
How to complete: Work Days 121–126; you're done when you can design a video pipeline from upload to adaptive playback and explain live-streaming's tighter latency budget.
Day 121 · Chunked resumable upload, validation, ingest
What: Uploading large video files reliably over unreliable connections by splitting into chunks that can resume after a failure, then validating and ingesting them.
How to complete: Design a chunked resumable upload protocol and explain how a client resumes after a connection drop without re-uploading completed chunks.
Day 122 · Transcoding: ladders, codecs, GPU farms, orchestration
What: Converting one uploaded video into many resolution/bitrate variants (a "ladder") using codec choices and GPU-accelerated farms, orchestrated as a pipeline.
How to complete: Design a transcoding ladder (e.g. 240p–4K) for a single upload and explain how you'd orchestrate and parallelize that job across a GPU farm.
Day 123 · Packaging: HLS, DASH, CMAF, DRM basics
What: Packaging transcoded video into segments and a manifest that players can adaptively stream, plus the DRM layer that protects licensed content.
How to complete: Explain what an HLS/DASH manifest actually contains, and how DRM's encryption + license server model prevents unauthorized playback.
Day 124 · Adaptive bitrate: player heuristics, buffer models, QoE
What: How a video player decides which bitrate variant to fetch next based on buffer health and throughput estimates, optimizing for quality of experience (QoE).
How to complete: Describe a buffer-based ABR heuristic (when to step up/down bitrate) and name the QoE metric you'd optimize it against (e.g. rebuffer ratio).
Day 125 · Netflix Open Connect, ISP embedding, prepositioning
What: Netflix's approach to CDN — embedding caching appliances directly inside ISP networks and prepositioning popular content overnight before demand hits.
How to complete: Explain what problem embedding CDN nodes inside an ISP solves that a third-party CDN can't, and how prepositioning reduces peak-hour origin load.
Day 126 · Live: ingest, LL-HLS, WebRTC, fanout tree, latency budget
What: Live streaming's much tighter latency budget — low-latency HLS or WebRTC for ingest/delivery, and a fanout tree to distribute one live stream to millions.
How to complete: Compare LL-HLS vs WebRTC's latency/scale tradeoff, and design a fanout tree that distributes one live ingest stream to a million concurrent viewers.
🎯 CHECKPOINT — Day 127 · MOCK #8: YouTube / Netflix
What: A scored mock testing whether Branch 6.1's transcoding, CDN, and ABR material holds up as a full end-to-end design under interview pressure.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: transcoding pipeline, CDN strategy, ABR, storage economics.
Branch 6.2 — Geospatial & Matching (Days 128–131)
What: The full Uber/Lyft problem — indexing moving objects on a map, matching supply to demand in real time, and predicting arrival times.
How to complete: Work Days 128–131; you're done when you can design a dispatch system's geospatial index and matching logic end to end.
Day 128 · Geohash, quadtree, S2, H3 — query patterns
What: The main ways to index 2D location data for fast proximity queries — each encoding scheme (geohash, quadtree, Google's S2, Uber's H3) with different cell-shape and query tradeoffs.
How to complete: Pick one indexing scheme for "find all drivers within 2km" and explain why its cell shape/resolution suits that query better than the alternatives.
Day 129 · Proximity search, k-nearest, dynamic objects
What: Finding the k nearest points to a query location when the points themselves are constantly moving, unlike static point-in-polygon search.
How to complete: Design a k-nearest-drivers query over a geospatial index that updates as drivers move every few seconds, without re-indexing everything each update.
Day 130 · Ride matching: supply/demand, dispatch, surge
What: Assigning available drivers to waiting riders in real time, and the surge-pricing mechanism that rebalances supply and demand under a shortage.
How to complete: Design a dispatch algorithm that balances rider wait time against driver idle time, and explain what signal triggers your surge multiplier.
Day 131 · ETA prediction, routing, map-matching
What: Predicting arrival time using road-network routing plus historical/live traffic data, and map-matching — snapping noisy GPS points onto the actual road graph.
How to complete: Explain why raw GPS points need map-matching before routing, and name one signal (beyond distance) your ETA model should incorporate.
🎯 CHECKPOINT — Day 132 · MOCK #9: Uber / Lyft Dispatch
What: A scored mock testing Branch 6.2's geospatial indexing and real-time matching material as a full design under interview conditions.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: geospatial indexing, matching, realtime updates.
Branch 6.3 — Money & Correctness (Days 133–136)
What: Systems where a bug means real financial loss — inventory holds, double-entry ledgers, payment state machines, and fraud detection.
How to complete: Work Days 133–136; you're done when you can design a payment flow that's provably idempotent and a ledger that's provably reconcilable.
Day 133 · Inventory: holds, TTL reservations, oversell policy
What: Reserving inventory during checkout with a time-boxed hold, and the explicit policy decision about whether a small oversell risk is acceptable in exchange for higher throughput.
How to complete: Design a TTL-based inventory hold for checkout, including what happens if the hold expires before payment completes, and justify your oversell tolerance.
Day 134 · Double-entry ledger, immutability, reconciliation
What: Recording every financial change as two balanced, immutable entries (debit and credit) so the books can always be independently reconciled.
How to complete: Model a refund as a double-entry transaction and explain how immutability (append-only, no updates) is what makes reconciliation trustworthy.
Day 135 · Auth, capture, refund, chargeback; idempotency keys
What: The full payment lifecycle as a state machine, and why every state transition needs an idempotency key given that networks retry.
How to complete: Draw the auth → capture → refund → chargeback state machine, and explain exactly where a missing idempotency key would cause a double charge.
Day 136 · Fraud: rules + ML, velocity checks, graph signals
What: Combining fast deterministic rules (velocity checks — too many attempts too quickly) with ML scoring and graph signals (shared devices/cards across accounts).
How to complete: Design a layered fraud check (rules first, ML score second) for a checkout flow, and name one graph-based signal that catches coordinated fraud rules miss.
🎯 CHECKPOINT — Day 137 · MOCK #10: Payment / Ledger System
What: A scored mock testing whether Branch 6.3's correctness-first material holds up when an interviewer pushes on idempotency and reconciliation.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: correctness, idempotency, double-entry, reconciliation.
Branch 6.4 — Collaboration & Sync (Days 138–141)
What: The Google Docs problem — letting multiple people edit the same document concurrently and converge on the same result without a central lock.
How to complete: Work Days 138–141; you're done when you can explain how CRDTs guarantee convergence without operational transform's central-server dependency.
Day 138 · Operational transform mechanics (Google Docs lineage)
What: The original technique for concurrent editing — transforming each operation against concurrent ones so all clients converge, typically via a central server that serializes operations.
How to complete: Walk through two concurrent inserts at the same position and show how OT transforms one against the other to reach a consistent result.
Day 139 · CRDTs: state-based vs op-based, convergence
What: Data structures that mathematically guarantee convergence from concurrent updates without a central coordinator — replicating either full state or individual operations.
How to complete: Explain, with a simple example (e.g. a G-Counter), why a CRDT's merge function is guaranteed to converge regardless of message order.
Day 140 · Cursor/presence sync, undo in collaborative context
What: Syncing ephemeral state (where each user's cursor is) separately from durable document state, and why undo becomes ambiguous once edits interleave across users.
How to complete: Design a low-latency cursor-presence channel separate from the document sync channel, and explain what "undo" should mean when another user edited in between.
Day 141 · File sync: delta sync, conflict resolution, versioning
What: Syncing whole files (Dropbox-style) efficiently by transferring only changed bytes (delta sync), and resolving conflicts when the same file changes on two devices while offline.
How to complete: Design a delta-sync protocol for a large file and describe your conflict resolution policy (e.g. keep-both-copies) when two offline edits collide.
Branch 6.5 — Orchestration (Days 142–144)
What: Systems that reliably run other work on a schedule or as long-running workflows — distributed cron, DAG engines, and durable execution frameworks.
How to complete: Work Days 142–144; you're done when you can explain how a durable execution engine like Temporal survives a worker crash mid-workflow.
Day 142 · Distributed cron, DAG engines, backfills
What: Running scheduled jobs exactly once across a cluster (not once per node), modeling job dependencies as a DAG, and safely re-running historical (backfill) jobs.
How to complete: Design a distributed cron that guarantees a job runs on exactly one node, and explain how you'd safely backfill a week of missed daily jobs.
Day 143 · Temporal/Cadence, durable execution
What: Frameworks that make long-running, multi-step workflows durable — a workflow's code can crash and resume exactly where it left off, replaying from an event history.
How to complete: Explain how Temporal's event-history replay lets a workflow resume after a worker crash without re-executing already-completed steps.
Day 144 · Multi-tenancy: isolation, noisy neighbor, quotas
What: Sharing infrastructure across many tenants safely — isolating one tenant's failure or heavy usage (noisy neighbor) from affecting others via quotas and limits.
How to complete: Design a quota system that stops one tenant's spike from degrading other tenants sharing the same cluster, and name your isolation boundary (process, container, node).
🎯 GATE 6 — Day 145 · MOCK #11: Google Drive / Collaborative Docs
What: The Phase 6 checkpoint, and the last of the "harder" product systems — a mock on real-time sync and conflict resolution under pressure.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: sync protocol, conflict resolution, CRDT/OT, versioning. Don't move on until you can truthfully check off:
- No common FAANG design question is unfamiliar territory
🌳 PHASE 7 — ML & MODERN INFRASTRUCTURE (Days 146–160)
What: The 2026-era topics most candidates cannot handle — recommendation serving, LLM infrastructure, and the platform/cost layer underneath every design.
How to complete: Work the 3 branches and 2 checkpoints in order. 🔑 Exit criteria: design ML-serving/RAG without hedging, and discuss cost unprompted.
Branch 7.1 — Recommendation & Serving (Days 146–150)
What: The multi-stage architecture behind real recommendation systems — from generating candidates to ranking them to serving predictions within a latency budget.
How to complete: Work Days 146–150; you're done when you can design a multi-stage recommendation pipeline and explain training-serving skew.
Day 146 · Candidate gen → ranking → policy (multi-stage)
What: The standard architecture for recommendations at scale — cheaply narrow millions of items to hundreds (candidate gen), expensively rank those (ranking), then apply business policy on top.
How to complete: Sketch the 3-stage pipeline for a video recommendation feed and explain why skipping straight to ranking on the full catalog wouldn't scale.
Day 147 · Feature stores, online/offline parity, training-serving skew
What: A central system for computing and serving ML features consistently in both training (batch) and serving (real-time), avoiding training-serving skew.
How to complete: Explain a concrete way training-serving skew creeps in (e.g. a feature computed differently offline vs online) and how a feature store prevents it.
Day 148 · Embedding retrieval at scale, ANN serving
What: Serving nearest-neighbor lookups over millions of learned embedding vectors within a tight latency budget, using approximate nearest-neighbor indexes.
How to complete: Explain why exact nearest-neighbor search doesn't scale to millions of embeddings, and how an ANN index trades a small accuracy loss for speed.
Day 149 · Model serving: batching, GPU utilization, latency budgets
What: Serving ML model inference efficiently — dynamically batching requests to keep GPUs utilized, while staying inside a per-request latency budget.
How to complete: Design a dynamic batching strategy for a model server and explain the tradeoff between batch size (throughput) and per-request latency.
Day 150 · A/B infra: assignment, guardrails, interference
What: The infrastructure for running experiments safely at scale — consistent user assignment, automatic guardrail metrics, and detecting cross-experiment interference.
How to complete: Design a consistent hashing-based assignment scheme for an A/B test and name one guardrail metric you'd auto-halt the experiment on.
🎯 CHECKPOINT — Day 151 · MOCK #12: Recommendation System
What: A scored mock testing Branch 7.1's multi-stage retrieval and serving-latency material as a full design under interview conditions.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: multi-stage retrieval, feature stores, serving latency.
Branch 7.2 — LLM Infrastructure (Days 152–155)
What: The infrastructure layer specific to serving and building on top of large language models — efficient inference and retrieval-augmented generation (RAG).
How to complete: Work Days 152–155; you're done when you can design a RAG pipeline and discuss its cost/latency tradeoffs unprompted.
Day 152 · KV cache, continuous batching, speculative decoding
What: The three main techniques for making LLM inference fast and cheap — caching attention keys/values across tokens, batching requests dynamically, and speculatively generating tokens with a smaller draft model.
How to complete: Explain what the KV cache actually stores and why it lets each new token be generated in roughly constant time instead of reprocessing the full prompt.
Day 153 · RAG: chunking, retrieval, reranking, evaluation
What: Grounding an LLM's answers in retrieved documents instead of relying purely on parametric memory — chunking documents, retrieving relevant ones, reranking, and evaluating the whole pipeline.
How to complete: Design a RAG pipeline end to end (chunking strategy, retrieval method, reranker) and describe one metric you'd use to evaluate answer quality.
Day 154 · Vector DB internals: HNSW tuning, filtering, freshness
What: Operating a vector database for RAG retrieval in production — tuning HNSW's recall/speed tradeoff, filtering by metadata, and keeping the index fresh as documents change.
How to complete: Explain what HNSW parameter you'd tune to trade recall for latency, and how you'd support metadata filtering (e.g. by tenant) without a full rescan.
Day 155 · Prompt/context pipelines, caching, cost control
What: Managing the cost and latency of LLM calls in a real product — caching repeated prompts/responses, and structuring context windows deliberately.
How to complete: Design a prompt-caching strategy for a support-chatbot product and estimate the cost reduction from caching a common system prompt prefix.
🎯 CHECKPOINT — Day 156 · MOCK #13: LLM-Powered Product (RAG at scale)
What: A scored mock testing whether Branch 7.2's RAG and serving material holds up when pushed on cost, latency, and evaluation.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: retrieval, cost, latency, evaluation.
Branch 7.3 — Platform & Economics (Days 157–160)
What: The platform layer every modern system sits on top of, and the cost lens senior engineers apply to every infrastructure decision.
How to complete: Work Days 157–160; you're done when you discuss unit economics unprompted in any design, not only when asked.
Day 157 · Kubernetes for design interviews: scheduling, HPA, operators
What: The container orchestration layer most systems run on — how the scheduler places pods, HPA scales them automatically, and operators automate application-specific operations.
How to complete: Explain what the Kubernetes scheduler considers when placing a pod, and how HPA decides when to add replicas based on a metric.
Day 158 · Service mesh, sidecars, mTLS — and when it's overkill
What: Offloading cross-cutting concerns (mTLS, retries, observability) into a sidecar proxy next to each service, and the real operational cost that makes it overkill for smaller systems.
How to complete: Name 2 concerns a service mesh moves out of application code, and state a team size/system scale below which you'd skip it entirely.
Day 159 · Serverless, cold starts, edge compute — fit and misfit
What: Running code without managing servers — great for spiky, short-lived workloads, badly suited to workloads sensitive to cold-start latency or long-running state.
How to complete: Give one workload that fits serverless well and one that doesn't, explaining the cold-start or statefulness reason in each case.
Day 160 · Cost engineering: unit economics, egress, tiering, spot
What: Treating cost as a first-class design constraint — computing unit economics per request, minimizing cross-AZ/cross-cloud egress, tiering storage, and using spot instances where safe.
How to complete: Compute a rough unit economics figure (cost per 1000 requests) for a design you've already built, and name one concrete change that would cut it.
🌳 PHASE 8 — RELIABILITY & OPERATIONS (Days 161–175)
What: Operational maturity — the senior-level differentiator, and (like Phase 4) a genuine existing strength worth making dominant rather than re-learning.
How to complete: Work the 4 branches in order, then sit Gate 8. Focus reps on making unprompted failure-handling reflexive in every design, not just this phase's.
Branch 8.1 — Measuring Reliability (Days 161–164)
What: The vocabulary and instrumentation for talking about reliability precisely — SLIs/SLOs/error budgets, and the three observability signal types.
How to complete: Work Days 161–164; you're done when you can define an SLO with an error budget for a real service and pick the right telemetry signal to debug an incident.
Day 161 · SLI/SLO/SLA, error budgets, nines arithmetic
What: The precise vocabulary of reliability targets — an SLI measures, an SLO targets, an SLA is contractual — and the error budget an SLO implies.
How to complete: Define an SLI/SLO/error-budget triplet for a real API, and compute how many minutes of downtime a 99.9% monthly SLO actually allows.
Day 162 · Metrics vs logs vs traces; cardinality traps, telemetry cost
What: The three observability signal types, each suited to a different question, and the cardinality explosion (e.g. per-user labels) that can silently blow up metrics storage cost.
How to complete: State which signal (metric, log, trace) you'd reach for to answer 3 different debugging questions, and name one label choice that risks a cardinality explosion.
Day 163 · Distributed tracing, sampling, context propagation
What: Following a single request across many services via a shared trace ID, sampled to control volume, propagated through every service boundary.
How to complete: Explain how a trace ID propagates across an async queue boundary, and justify a sampling rate for a high-traffic endpoint.
Day 164 · Alerting: symptom vs cause, on-call, runbooks, incident command
What: Alerting on symptoms (user-facing pain) rather than causes (a specific metric threshold), backed by runbooks and a clear incident command structure.
How to complete: Rewrite a cause-based alert ("CPU > 80%") as a symptom-based one, and outline the first 3 steps of a runbook for the incident it represents.
Branch 8.2 — Failure Engineering (Days 165–169)
What: Designing systems that degrade gracefully instead of collapsing — the failure patterns that cascade, and the techniques that stop them.
How to complete: Work Days 165–169; you're done when every design you produce handles overload and partial failure without being asked.
Day 165 · Cascading failures, retry storms, thundering herd, jitter
What: How a small failure amplifies into a system-wide outage — synchronized retries (a retry storm) or synchronized cache expiry (thundering herd) overwhelming an already-struggling downstream.
How to complete: Explain how adding jitter to retry backoff prevents a retry storm, with a concrete before/after timeline.
Day 166 · Load shedding, admission control, priority queues, brownout
What: Deliberately rejecting or degrading some requests under overload to protect the system as a whole, prioritizing the requests that matter most.
How to complete: Design an admission-control policy that sheds low-priority requests first under overload, and define what a "brownout" response looks like for your service.
Day 167 · Circuit breakers, bulkheads, timeout hierarchies
What: Stopping calls to a failing dependency before they pile up (circuit breaker), isolating resource pools so one dependency's failure can't starve others (bulkhead), and setting nested timeouts consistently.
How to complete: Design a timeout hierarchy across 3 nested service calls, and explain when a circuit breaker should trip versus just retrying.
Day 168 · Chaos engineering, fault injection, game days
What: Deliberately injecting failures in production (or a close facsimile) to verify a system's resilience claims are actually true, run as scheduled "game days".
How to complete: Design a chaos experiment (e.g. kill a random replica) for a service you've built, stating your hypothesis and how you'd measure success.
Day 169 · Capacity planning, autoscaling, headroom, load testing
What: Sizing infrastructure ahead of demand — autoscaling reactively, but only on top of a deliberate headroom buffer validated by load testing.
How to complete: Compute a headroom buffer for a service given its peak load and autoscaling reaction time, and describe the load test that would validate it.
Branch 8.3 — Change & Recovery (Days 170–172)
What: Shipping changes to a live system safely, and recovering when a change (or disaster) goes wrong anyway.
How to complete: Work Days 170–172; you're done when you can design a zero-downtime schema migration and state your DR plan's RPO/RTO.
Day 170 · Blue-green, canary, progressive rollout, auto-rollback
What: Deployment strategies that limit blast radius — switching between two full environments (blue-green), rolling out to a small percentage first (canary), and rolling back automatically on regression signals.
How to complete: Design a canary rollout with an automatic rollback trigger tied to a specific error-rate threshold, and explain blue-green's tradeoff versus it.
Day 171 · Online schema migration, expand-contract, dual-write, backfill
What: Changing a database schema without downtime — adding the new shape first (expand), dual-writing both old and new, backfilling history, then removing the old shape (contract).
How to complete: Rehearsed strength — walk through an expand-contract migration for renaming a column on a live table with zero downtime, step by step.
Day 172 · DR: RPO/RTO, backups, region evacuation, drills
What: Disaster recovery planning quantified by two numbers — how much data you can afford to lose (RPO) and how fast you must be back up (RTO) — and the backup/evacuation plan that hits them.
How to complete: Define an RPO/RTO pair for a real system and describe the backup + region failover plan that would actually meet those numbers, then explain how you'd drill it.
Branch 8.4 — Security (Days 173–174)
What: The baseline security architecture every production system needs — identity, authorization, and encryption of data at rest and in transit.
How to complete: Work Days 173–174; you're done when you can explain a zero-trust auth flow and a key-rotation policy from memory.
Day 173 · OAuth2/OIDC, JWT pitfalls, session design, zero trust
What: The standard identity/authorization protocols, the common mistakes made with JWTs (no revocation, over-trusting claims), and zero-trust — verifying every request instead of trusting the network perimeter.
How to complete: Explain one common JWT pitfall (e.g. no built-in revocation) and how you'd mitigate it, then describe what "zero trust" changes about internal service calls.
Day 174 · Encryption at rest/transit, KMS, key rotation, PII
What: Encrypting stored and in-flight data using keys managed by a dedicated service (KMS), with a rotation policy, and extra handling for PII specifically.
How to complete: Design a key-rotation policy using a KMS for encrypting PII at rest, and explain how existing encrypted data is handled when the key rotates.
🎯 GATE 8 — Day 175 · MOCK #14: Monitoring / Observability Platform
What: The Phase 8 checkpoint — designing the very system that makes reliability measurable, testing whether that operational maturity is now reflexive.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: write volume, cardinality, time-series storage, query. Don't move on until you can truthfully check off:
- Every design handles partial failure by default, unprompted
🌳 PHASE 9 — INTERVIEW CRAFT & LOOP SIMULATION (Days 176–180)
What: The final phase — converting 179 days of knowledge into performance under real time pressure, which is a distinct skill from knowing the material.
How to complete: Work the 3 branches in order, then sit the Final Gate. You're ready for real loops once no rubric dimension scores below 4.
Branch 9.1 — Performance Mechanics (Day 176)
What: The meta-skill of the whole 180 days — running the 45-minute interview format itself flawlessly, independent of which system you're asked to design.
How to complete: Complete Day 176; you're done when the 45-minute framework runs on reflex, not conscious effort.
Day 176 · 45-min framework, timeboxing, diagram discipline, handling pushback — drilled to reflex
What: The repeatable structure for any system design interview — requirements, estimation, high-level design, deep dive, wrap-up — timeboxed and diagrammed consistently.
How to complete: Run 3 back-to-back mock designs using a strict internal timebox per phase, and drill your response to an interviewer pushing back on a design choice.
Branch 9.2 — Your Story (Day 177)
What: Turning real production experience (the notification platform, the CDC/ES pipeline) into tight, quantified narratives for the "tell me about a system you built" portion of interviews.
How to complete: Complete Day 177; you're done when each story runs exactly 5 minutes with real numbers and a clear tradeoff, without notes.
Day 177 · Notification platform + CDC/ES pipeline as 5-minute narratives with real numbers and tradeoffs
What: Two real production systems, reshaped into interview-ready stories that lead with scale/impact numbers and one honest tradeoff you made.
How to complete: Rehearsed strength — time yourself telling each story in exactly 5 minutes, including one specific number (e.g. "100M+ notifications/day") and one tradeoff.
Branch 9.3 — Company Calibration (Days 178–179)
What: Adjusting your delivery for each company's actual interview style — Amazon's leadership-principle framing differs from Google's or Meta's more open-ended format.
How to complete: Work Days 178–179; you're done when you've sat one mock in each company's style and adjusted for the differences you noticed.
Day 178 · MOCK #15 (Google-style) + MOCK #16 (Amazon-style, LPs)
What: Two back-to-back mocks in different company styles — Google's open-ended depth-first questioning versus Amazon's leadership-principle-anchored format.
How to complete: Sit both mocks same-day, and after each, write down one concrete delivery adjustment the style demanded that the other didn't.
Day 179 · MOCK #17 (Meta-style) + MOCK #18 (Netflix-style)
What: Two more calibration mocks — Meta's execution-speed-focused format and Netflix's high-autonomy, judgment-focused culture fit.
How to complete: Sit both mocks same-day, and compare your notes against Day 178's two styles — you should now have a felt sense of what changes per company.
🏁 FINAL GATE — Day 180
What: The last checkpoint of the entire 180-day plan — two unseen, full-length mock loops back to back, the closest simulation of the real thing before you sit it for real.
How to complete: Sit the mock cold, timed to 45 minutes, then score yourself against: MOCK #19 — Full loop, design 1 (unseen); MOCK #20 — Full loop, design 2 (unseen, under fatigue). Don't move on until you can truthfully check off:
- Ready criteria: no rubric dimension below 4
🔁 PARALLEL TRACKS — run alongside all 180 days
What: Three ongoing commitments that run underneath the whole 180-day plan — coding practice, behavioral prep, and the job pipeline — none of which fit into a single day's slot.
How to complete: Give each track its stated weekly time budget every week from Day 1, rather than deferring them until the system design phases are "done".
💻 DSA / Coding — ~5 hrs/week, every week
What: The coding-interview track running in parallel to system design — still the single most common reason candidates get rejected, regardless of how strong their system design is.
How to complete: Spend ~5 hrs/week on your Grand Algorithm project, work through NeetCode 150 twice (second pass timed), and never let this slip — it's the most common rejection reason.
🗣️ Behavioral / Leadership Principles — ~30 hrs total
What: Behavioral interview prep, weighted toward Amazon's leadership-principle format (heaviest requirement) with lighter but real prep for Google/Meta/Netflix's less structured behavioral rounds.
How to complete: Draft 15–20 STAR stories mapped to Amazon's LPs sourced from real work (the notification platform, the CDC pipeline, real incidents), spending ~30 hours total across the 180 days.
📮 Pipeline — starts Day 120
What: The actual job-application pipeline — referrals, resume, and public technical presence — which needs a multi-week head start before Phase 5's gate, since loops are slow.
How to complete: From Day 120, prioritize referrals over cold applications, quantify your resume ("100M+ notifications/day", not "worked on notifications"), and keep your Bangla technical writing + GitHub active as differentiators.