In short
A system design case study asks you to take one real product - a URL shortener, a social feed, a chat app, a video stream, a payments switch - and turn it into a concrete architecture: requirements, traffic and storage estimates, APIs, data model, components, and the trade-offs you chose. The skill examined is not memorising a diagram but defending numbers and failure behaviour. It is the main round for SDE-2 and above, and now appears for freshers at Flipkart, Swiggy, Zomato, Razorpay, PhonePe, Zerodha, Atlassian, Amazon, Google India, Walmart Global Tech, Uber and Ola; universities examine it in software architecture / distributed systems papers and in final-year project vivas. GATE CS does not ask open design, but its DBMS, OS and CN theory supplies every building block used here.
Explained
How to attack a case study in 35-45 minutes
- Clarify and scope (5 min). Ask for functional requirements (what the user does), non-functional ones (latency, availability, consistency, durability), and scale (DAU, read:write ratio, retention). Then say out loud what you are *not* building - interviewers reward scoping, not bravado.
- Estimate (5 min). Convert DAU into QPS, storage per day and per year, bandwidth, and number of machines. Use round numbers: 1 lakh = 10⁵, 1 crore = 10⁷, a day = 86,400 s ≈ 10⁵ s.
- Define the API (3 min). 3-6 endpoints with request/response fields. This fixes the contract before you draw boxes.
- Data model (5 min). Tables/collections, primary key, the access patterns each index serves, and the shard key. Choosing the shard key *is* the design decision.
- High-level design (8 min). Client → DNS/CDN → load balancer → API/application tier (stateless) → cache → database, with queues for anything asynchronous and object storage for blobs.
- Deep dive where the interviewer points (10 min). One or two of: hot keys, fan-out, ID generation, exactly-once semantics, geo-replication, back-pressure.
- Failures and trade-offs (5 min). What happens if a shard, a region or the cache dies; what you sacrifice (usually strong consistency or cost) and why that is acceptable for *this* product.
- Numbers to carry in your head: memory read ~100 ns, SSD read ~100 µs, same-datacentre round trip ~0.5 ms, Mumbai→Singapore ~60-70 ms, Mumbai→US-East ~220 ms; one commodity node handles roughly 1,000-5,000 simple API requests/s, a single Redis instance 50,000-100,000 ops/s, one relational primary a few thousand writes/s.
Case 1 - URL shortener and rate limiter (read-heavy, write-light)
- Requirements: POST a long URL, get a short code; GET /code redirects (HTTP 301 cacheable, 302 if you need per-hit analytics); optional expiry, custom alias, click counts.
- Scale assumed: 10 crore (100 million) new URLs/day, read:write = 100:1 → ~1,157 writes/s and ~1.16 lakh reads/s average.
- Key generation - three options: (a) hash the URL (MD5/SHA-1) and take 7 base-62 characters - collisions must be checked; (b) a distributed counter (ZooKeeper/etcd ranges, or a Snowflake-style 64-bit ID) encoded to base 62 - no collisions, but codes are guessable and sequential; (c) a pre-generated key pool in a separate "key generation service" that hands out blocks - simplest to reason about.
- Storage: key-value is the natural fit (code → long URL, owner, expiry). Shard by hash of the code so lookups are single-shard. Reads are served from cache; a 95% hit rate removes almost all database load.
- Why it is asked: it isolates ID generation, caching, and the difference between a stateless tier (easy to scale horizontally) and stateful storage (needs a shard key).
- The rate limiter sub-problem: token bucket (capacity C, refill r tokens/s - allows bursts), leaky bucket (smooths output), fixed window (cheap, but allows 2× burst at the boundary), sliding window log (exact, memory-heavy), sliding window counter (the usual compromise). Keep counters in Redis keyed by user/API-key/IP with a TTL, and return HTTP 429 with a
Retry-Afterheader.
Case 2 - Social feed and notifications (Twitter/X, Instagram, Koo-style)
- The core problem is fan-out: when a user posts, who pays the cost - the writer or the readers?
- Fan-out on write (push): at post time, insert the post ID into every follower's precomputed feed list (Redis list / Cassandra row). Reads are O(1) and fast; writes explode for celebrity accounts (10 crore followers = 10 crore inserts for one post).
- Fan-out on read (pull): store posts once; at read time, query all accounts the user follows, merge by timestamp. Writes are cheap, reads are slow and hit many shards.
- Hybrid (what production systems do): push for ordinary users, pull for a small list of "celebrity" accounts (say >1 lakh followers), merged at read time. Also skip push for inactive users.
- Ranking: a timeline is not purely chronological - a scoring service ranks candidates on recency, affinity and engagement, so the feed service returns candidate IDs and a separate hydration step fetches post content from cache.
- Data model:
posts(post_id PK, user_id, text, media_url, created_at)sharded by post_id;follows(followee_id, follower_id)sharded both ways (two copies) so "my followers" and "who I follow" are both single-shard;feed(user_id, post_id, score)sharded by user_id. - Media never goes through the API tier: the client gets a pre-signed URL, uploads straight to object storage (S3), a queue triggers transcoding into thumbnails, and the CDN serves them.
- Notifications reuse the same fan-out: an event on a queue (Kafka) → a worker expands recipients → per-channel senders (FCM/APNs push, SMS via a DLT-registered template as TRAI rules require, email), with user preference checks, de-duplication keys and retry with exponential backoff.
Case 3 - Chat and presence (WhatsApp)
- Requirements: 1-1 and group messaging, delivery receipts (sent/delivered/read), ordering per conversation, offline delivery, media, end-to-end encryption.
- Connections, not requests: clients hold a long-lived WebSocket (or XMPP/MQTT) to a *gateway* tier; the box's limit is file descriptors and memory, not CPU. A tuned Erlang/FreeBSD gateway famously held about 2 million concurrent TCP connections per machine.
- Session registry: a fast store maps user_id → gateway node. To send, the chat service looks up the recipient's node and forwards over an internal bus; if the user is offline the message goes to a durable inbox queue per user and is drained on reconnect.
- Ordering and IDs: a per-conversation monotonic sequence number (or a Snowflake ID) gives ordering without a global clock; the client sends a client-generated message ID so retries are idempotent and do not duplicate.
- Storage: messages keyed by
(conversation_id, seq)in a wide-column store (Cassandra/HBase) - an append-heavy, range-read pattern. With E2E encryption the server stores ciphertext and can delete after delivery; India's traceability debate under the IT Rules, 2021 turns on exactly this. - Groups: server-side fan-out to each member's queue; a 1,024-member group means one send becomes 1,023 deliveries, so group size is capped for a reason.
Case 4 - Video streaming at IPL scale (JioHotstar / Netflix / SonyLIV)
- Two different systems: VOD (upload → transcode → store → CDN) and live (ingest → encode → package → CDN), sharing the delivery path.
- Pipeline: ingest (RTMP/SRT) → transcoder producing an ABR ladder (e.g. 240p 0.4 Mbps, 360p 0.8, 480p 1.4, 720p 2.5, 1080p 5 Mbps) → packager into HLS/DASH segments of 2-6 s → origin storage → CDN edge → player, which switches rungs based on measured throughput and buffer level.
- Latency vs scale: segmented HLS has 15-45 s glass-to-glass delay; LL-HLS/CMAF chunked transfer cuts it to 3-8 s; WebRTC reaches sub-second but does not fan out cheaply. Cricket needs low latency because viewers hear the neighbour's TV first.
- CDN is the design. 95-99% of bytes must be served from edge caches; origin shielding and multi-CDN with real-time switching protect against one vendor's region failing. Indian ISPs host edge caches inside their networks to keep traffic local.
- Peaks are the whole problem: company-reported concurrency for the ICC World Cup 2023 final on Disney+ Hotstar was about 5.9 crore (59 million) simultaneous viewers - these are vendor-reported figures and later tournaments have claimed higher. Capacity is pre-warmed hours in advance; autoscaling alone cannot add 10× in 30 seconds when a wicket falls.
- Graceful degradation: cap the top ABR rung, disable chat/scorecard widgets, serve a static fallback - shedding features is better than a blank player.
Case 5 - Money and scarce inventory (UPI, IRCTC Tatkal, flash sales)
- Correctness beats availability here. A double debit is unacceptable; a 2-second wait is not. This is the case-study family where you choose CP over AP.
- Idempotency: every write carries a client-supplied
Idempotency-Key; the server stores key → result and replays the stored result on retry. Without it, a timeout plus a retry equals a duplicate payment. - Ledger: use double-entry append-only rows (debit one account, credit another, same transaction id); never store a mutable "balance" as the source of truth - derive it, then cache it. Reconcile against the bank/NPCI settlement file daily.
- Distributed transactions: two-phase commit blocks on coordinator failure; production systems use a saga - a sequence of local transactions with compensating actions (refund, release, cancel) - driven by a durable state machine and an outbox table so the event and the database write commit together.
- UPI shape: PSP app → NPCI switch → remitter bank → beneficiary bank, with a request-response leg plus asynchronous callbacks, mandatory timeouts, and a reversal/TAT path for stuck transactions. Scale: UPI runs in the range of 18-20 billion transactions a month in 2025 (NPCI publishes the monthly number - quote the current one), i.e. roughly 7,000 transactions/s on average with multi-×ten-thousand peaks.
- Scarce inventory (Tatkal, flash sale, concert tickets): the pattern is reserve → pay → confirm with a TTL on the reservation. Decrement a counter atomically (Redis
DECRor a single-rowUPDATE ... WHERE qty > 0), put users in a virtual queue / waiting room, and admit at a fixed rate instead of letting 50 lakh users hit the database at 10:00:00. Row-level contention on one SKU is the real bottleneck, so split stock into N logical buckets and pick one at random. - Indian compliance that changes the design: RBI's payment-data localisation directive (2018) requires end-to-end payment data to be stored in India; card data must be replaced by CoF tokens; the DPDP Act, 2023 governs consent, purpose limitation and breach notification for personal data (these duties apply from 13 May 2027 under the DPDP Rules 2025); PCI-DSS applies to card flows. Transaction caps and additional-factor rules are revised periodically by RBI/NPCI - check the current circular rather than quoting a number.
Case 6 - Location and matching (Ola, Uber, Rapido, Swiggy, Zomato, Dunzo)
- Write-heavy ingestion: every active driver pings location every 3-5 s. One lakh active drivers at one ping/4 s = 25,000 writes/s of small records - keep them in memory (Redis) with a short TTL, not in the primary database.
- Spatial index: divide the earth with geohash (or S2 cells / H3 hexagons / a quadtree). A geohash prefix is a string, so "drivers near me" becomes a prefix/range query on a 6-7 character cell plus its 8 neighbours.
- Matching: the dispatch service gathers candidates in widening rings, scores them on ETA (from a road-graph routing service, not straight-line distance), acceptance history and surge, then offers sequentially with a 10-15 s timeout per driver.
- Trip state machine: requested → accepted → arrived → started → completed → paid, each transition idempotent and persisted, because a driver's phone will lose network mid-trip.
- Sharding by city/region keeps queries local and matches the business - demand in Bengaluru never needs Kochi's data - and lets you deploy and rate-limit per city.
- Food delivery adds a second scarce resource: restaurant prep time and rider batching, so the problem becomes an assignment problem solved on a recomputed basis every few seconds.
Key points
- Requirements before boxes - functional, non-functional, scale; a design without stated assumptions cannot be judged right or wrong.
- Back-of-the-envelope - DAU → QPS → storage → bandwidth → machines; wrong by 2× is fine, wrong by 1000× is fatal.
- Read:write ratio decides the architecture: read-heavy → cache and replicas; write-heavy → partitioning, LSM stores, queues.
- Stateless application tier scales by adding nodes behind a load balancer; state is the hard part.
- Shard key choice is the single most consequential decision - it fixes which queries are cheap and where hot spots appear.
- Consistent hashing with virtual nodes lets you add or remove a node and move only ~1/N of the keys.
- Fan-out on write vs on read - push for ordinary users, pull for celebrities, hybrid in production.
- Idempotency key turns an unsafe retry into a safe one; mandatory for any payment or booking API.
- Saga + outbox replaces two-phase commit across services; compensation, not rollback.
- CDN and edge caching are what make video and static-heavy products affordable; origin traffic must be a few per cent of total.
- Queues decouple producer spikes from consumer capacity and give retries, dead-letter queues and back-pressure.
- CAP in practice - payments and ticketing choose consistency; feeds, likes and presence choose availability with eventual consistency.
- Hot key / hot shard is the most common real outage: one celebrity, one SKU, one trending match.
- Graceful degradation - shed features, serve stale cache, queue users; never fail the whole page.
- Multi-region adds 60-220 ms cross-region latency; active-active needs conflict resolution, active-passive needs a tested failover.
- Observability - p50/p95/p99 latency, error rate, saturation, plus distributed tracing; design the dashboard in the interview, it scores.
- Cost is a design constraint - egress bandwidth and cross-AZ traffic often dominate the bill, not compute.
Formulas and examples
Storage per day = writes/day × bytes per record × replication factor (usually 3)
Bandwidth (bps) = concurrent users × bitrate per user (bps)
Key space with N characters of base-62 = 62N distinct codes
Snowflake 64-bit ID = 1 unused + 41 bits ms timestamp + 10 bits machine + 12 bits sequence → 4,096 IDs per ms per machine, 2⁴¹ ms ≈ 69.7 years of range
Little's law: L = λ × W (L = requests in flight, λ = arrival rate per s, W = average latency in s)
Nodes = ceil(peak load ÷ per-node capacity) + spares (N+2 for maintenance plus one failure)
Availability in series = A₁ × A₂ × …; with k independent redundant copies = 1 − (1 − A)k
Annual downtime (minutes) = (1 − A) × 525,600
Effective read latency = h × T_cache + (1 − h) × (T_cache + T_db), h = cache hit ratio
Example 1 - URL shortener sizing. 10 crore (10⁸) new URLs/day, read:write 100:1, record 500 bytes, replication 3, retention 5 years.
- Writes: 10⁸ ÷ 86,400 ≈ 1,157/s; reads ≈ 1,157 × 100 ≈ 1.16 lakh/s; peak at 3× ≈ 3.5 lakh/s.
- Storage/day = 10⁸ × 500 B × 3 = 1.5 × 10¹¹ B = 150 GB/day → 5 years ≈ 150 × 365 × 5 GB ≈ 274 TB.
- Key space: 62⁷ = 3,521,614,606,208 (3.52 × 10¹²). At 3.65 × 10¹⁰ URLs/year, that lasts 3.52 × 10¹² ÷ 3.65 × 10¹⁰ ≈ 96 years → 7 characters is right; 6 characters (5.68 × 10¹⁰) would last only ~1.6 years.
- Nodes for reads: 3.5 lakh/s ÷ 50,000 ops/s per cache node ≈ 7 → 9 with spares.
Example 2 - Feed fan-out, push vs pull. 20 crore DAU, 5 crore posts/day, average 200 followers, each user opens the timeline 10 times/day.
- Timeline reads = 2 × 10⁸ × 10 = 2 × 10⁹/day = 23,148/s average, ~70,000/s at 3× peak.
- Push cost: 5 × 10⁷ posts × 200 = 10¹⁰ feed-row writes/day = 1.16 lakh writes/s - heavy but sequential and off the read path.
- Pull cost: each read merges 200 followees' recent posts = 2 × 10⁹ × 200 = 4 × 10¹¹ row reads/day ≈ 46 lakh row reads/s - roughly 40× the push cost.
- Conclusion: push by default. For an account with 5 crore followers, one post would need 5 × 10⁷ inserts, so pull those at read time → hybrid.
Example 3 - Live cricket bandwidth and cost. 2.5 crore (25 million) concurrent viewers, average delivered bitrate 3 Mbps, 4-hour match, CDN offload 96%.
- Peak bandwidth = 25 × 10⁶ × 3 × 10⁶ = 7.5 × 10¹³ bps = 75 Tbps; origin egress = 4% = 3 Tbps.
- Bytes/hour = 7.5 × 10¹³ ÷ 8 × 3,600 = 3.375 × 10¹⁶ B = 33.75 PB/hour; a 4-hour match ≈ 135 PB.
- At a bulk CDN rate of ₹0.05/GB: 135 × 10⁶ GB × 0.05 = ₹67.5 lakh for one match; at ₹0.50/GB it would be ₹6.75 crore - which is why CDN rate negotiation, codec efficiency (AV1/HEVC) and ABR capping are architectural decisions, not finance ones.
Example 4 - Payments capacity and availability. 600 crore (6 × 10⁹) transactions/month, peak factor 4, node capacity 2,000 TPS, per-transaction latency 40 ms.
- Average = 6 × 10⁹ ÷ (30 × 86,400) = 2,315 TPS; peak = 9,260 TPS.
- Nodes = ceil(9,260 ÷ 2,000) = 5, plus N+2 → 7 nodes.
- Little's law: L = 9,260 × 0.040 ≈ 370 requests in flight → thread pools and connection pools sized above 370, else queueing collapses.
- Availability: a chain of PSP (99.99%) × switch (99.99%) × bank (99.9%) = 0.9999 × 0.9999 × 0.999 = 0.99880 ≈ 99.88%, i.e. (1 − 0.99880) × 525,600 ≈ 630 minutes/year ≈ 10.5 hours - the weakest link dominates. Two independent 99.9% banks in parallel give 1 − (0.001)² = 99.9999%.
Example 5 - Cache hit ratio. Cache read 1 ms, database read 50 ms.
- h = 0.90 → 0.90 × 1 + 0.10 × 51 = 6.0 ms; h = 0.99 → 0.99 × 1 + 0.01 × 51 = 1.5 ms.
- Database load falls from 100% to 10% to 1% of reads - the last 9% of hit rate buys a 4× latency cut.
| Case study | Dominant load | Store of choice | Consistency | Key risk |
|---|---|---|---|---|
| URL shortener | Read-heavy 100:1 | KV store + cache | Eventual | Hot code, key collisions |
| Social feed | Write amplification | Wide-column + Redis lists | Eventual | Celebrity fan-out |
| Chat | Persistent connections | Wide-column, per-user queues | Per-conversation order | Gateway capacity, offline backlog |
| Live video | Egress bandwidth | Object storage + CDN | N/A (immutable segments) | Peak concurrency, CDN failure |
| Payments | Correctness | Relational, append-only ledger | Strong (CP) | Duplicates, partial failure |
| Ride-hailing | Location writes | In-memory geo index + RDBMS | Mixed | Hot city shard, stale locations |
| Fan-out strategy | Write cost | Read cost | Best for |
|---|---|---|---|
| Push (on write) | High | Very low | Most users, few followers |
| Pull (on read) | Very low | High | Celebrities, inactive users |
| Hybrid | Medium | Low | Production social feeds |
Where it is used
- Consumer internet at scale: Flipkart and Myntra sale events, Swiggy/Zomato dispatch, JioHotstar and SonyLIV live sport, ShareChat and Josh feeds - each is one of the case studies above in production.
- Fintech and payments: NPCI's UPI switch, PhonePe, Google Pay, Paytm, Razorpay, Cashfree; ledgering, idempotency and reconciliation are daily engineering work, with RBI localisation and DPDP Act constraints baked in.
- Public digital infrastructure: IRCTC Tatkal booking, UIDAI Aadhaar authentication, DigiLocker, GSTN return filing, ONDC - all peak-driven, scarce-resource or high-fan-out systems.
- Trading and real-time data: Zerodha, Groww and Upstox market-data fan-out at 09:15 market open - a push-vs-pull and WebSocket-gateway problem identical to Case 3.
- Job roles: backend/platform engineer, SRE, solutions architect (AWS/Azure), data platform engineer; the design round is the gate for SDE-2, SDE-3 and architect positions at Indian product companies and GCCs.
- Academic and exam use: software architecture, distributed systems and cloud-computing papers; final-year projects where the viva asks "how would this behave with 10 lakh users?"
Interview questions
- Q: How many characters does a short code need? A: Compute the key space - 62⁷ ≈ 3.5 × 10¹² codes supports 10 crore new URLs/day for about 96 years, while 62⁶ ≈ 5.7 × 10¹⁰ lasts under two years, so 7 base-62 characters.
- Q: Fan-out on write or on read for a timeline? A: Push for ordinary users because reads dominate, pull for accounts with very large follower counts, and merge the two at read time; pure pull costs roughly 40× more row reads in a typical 200-follower model.
- Q: Why is an idempotency key essential in a payments API? A: A client that times out will retry; without a stored key → result mapping the retry becomes a second debit. The key makes the operation safely repeatable.
- Q: How do you stop two users buying the last item in a flash sale? A: Make the decrement atomic at a single authoritative point - a conditional single-row update or a Redis atomic counter - then reserve with a TTL and confirm only after payment; never check-then-write in application code.
- Q: Pick the shard key for a chat message store and justify it. A:
conversation_id(hashed) withseqas the clustering key - all reads are "last N messages of one conversation", so they stay on one shard and read as a single range scan. - Q: Why does live cricket need a different design from Netflix VOD? A: VOD can pre-transcode and pre-warm caches for predictable demand; live has one encode pipeline, unpredictable 10-50× spikes and a latency budget, so it needs multi-CDN, pre-provisioned capacity and ABR capping.
- Q: What does Little's law tell you when sizing a service? A: Concurrency = throughput × latency - at 10,000 req/s and 50 ms you have 500 requests in flight, so thread and connection pools below that will queue and blow up tail latency.
- Q: Your p99 latency is 2 s while p50 is 40 ms. Where do you look? A: Tail causes - cache misses, a hot shard, GC pauses, connection-pool exhaustion, a slow downstream, or retry storms; instrument with distributed tracing rather than averaging.
- Q: How do you handle a celebrity hot key? A: Replicate the value across multiple cache keys/nodes and read a random replica, add a local in-process cache, serve stale-while-revalidate, and move that account to pull-based fan-out.
- Q: Where would you accept eventual consistency, and where never? A: Accept it for likes, follower counts, feeds, read receipts and analytics; never for account balance, seat inventory or a payment debit.
- Q: How do you locate nearby drivers efficiently? A: Index locations by geohash/S2/H3 cell in an in-memory store, query the user's cell plus neighbours, widen the radius if needed, then rank by road-network ETA rather than straight-line distance.
- Q: What happens if your primary region fails? A: State the RTO/RPO you designed for, how reads fail over to replicas, whether writes are blocked or accepted with conflict resolution, and the fact that a failover untested in a drill does not count.
Common mistakes
- Drawing boxes before stating requirements and numbers - the design cannot be defended without the assumptions it was sized for.
- Arithmetic slips in estimation - mixing bits with bytes, dropping a factor of 1,024 vs 1,000, forgetting that a day is 86,400 s, or ignoring the replication factor in storage.
- Picking a shard key that creates a hot shard - sharding tweets by user_id when one account has crores of followers, or orders by date so today's partition takes every write.
- Claiming "just use NoSQL" or "just add a cache" without naming the access pattern, the consistency model, the eviction policy or the invalidation strategy.
- Ignoring idempotency and retries, then being unable to explain why a user was charged twice when the network dropped.
- Treating autoscaling as the answer to a spike - cold starts and warm-up take minutes, so event traffic (a match, a sale, Tatkal at 10:00) must be pre-provisioned.
- No failure story and no numbers for availability - quoting "highly available" without saying what 99.9% costs in annual downtime (about 8.76 hours).
Related topics
System design basics for freshers · Caching, queues and CDNs · REST APIs · Containers: Docker and Kubernetes · AWS core services · Cloud computing basics