Back to Scaling, Load Balancing & Performance
Q6Question 6 of 20

How do you do a back-of-envelope capacity estimate in a system-design interview?

Key Concepts
  • QPS: daily active users x actions/day / 86400 seconds, then multiply by peak factor (2-5x).
  • Storage: per-record size x daily writes x 365 x retention years, plus index and replication overhead.
  • Bandwidth: peak QPS x response size; reveals whether a CDN is needed.
  • Cache size: hot fraction (Pareto 20%) x item size x distinct items.
  • Latency numbers: memory ~100 ns, SSD ~100 us, same-DC round trip ~500 us, cross-continent ~150 ms.
  • Split read/write QPS by the read-to-write ratio to place caches and replicas.
  • The estimate drives architecture: QPS sizes the fleet, storage decides sharding, bandwidth decides CDN.

Definition

Back-of-envelope estimation turns daily active users into QPS, bytes per day into bytes per year, rate times payload into bandwidth, and the hot fraction into cache size, all anchored by the latency numbers every engineer should know.
  • QPS -- daily active users x actions/day / ~100K seconds/day, then multiply by peak factor.
  • Storage -- per-record bytes x daily writes x 365 x retention, plus indexes (~2x) and replication.
  • Bandwidth -- peak QPS x response size (bytes to bits to Mbps/Gbps).
  • Cache -- hot 20% of items x item size; check it fits a Redis node.
  • Latency numbers -- memory ~100 ns, SSD ~100 us, same-DC ~500 us, cross-continent ~150 ms.
  • Read/write split -- reads go to caches/replicas; writes hit the primary.

Before opening a new branch, the National Bank of India manager scribbles on an envelope: 10,000 customers, 2 visits per month, 700 visits per day, peak triple that at lunch, so size for 2,000 visits per hour. Estimate paper storage per year, and check if the vault is big enough. Same math, scaled to servers, storage, and cache.

Understanding the Concepts

How do you calculate QPS?

Start with daily active users and actions per user per day. Divide by 86,400 seconds (round to 100,000 for easy math). Multiply by a peak factor (typically 2-5x) to size for spikes.

JAVA
package com.bank.capacity;

public class QpsEstimate {
    public static void main(String[] args) {
        long dau = 10_000_000;         // daily active users
        int actionsPerDay = 5;          // payments per user per day
        long dailyRequests = dau * actionsPerDay; // 50M
        long avgQps = dailyRequests / 100_000;    // ~500 (round 86400 to 100K)
        long peakQps = avgQps * 4;                // ~2000

        System.out.printf("DAU: %,d%n", dau);
        System.out.printf("Daily requests: %,d%n", dailyRequests);
        System.out.printf("Avg QPS: %d, Peak QPS: %d%n", avgQps, peakQps);
    }
}
TEXT
Expected output:
DAU: 10,000,000
Daily requests: 50,000,000
Avg QPS: 500, Peak QPS: 2000

How do you estimate storage?

Multiply per-record size by daily writes, extend to yearly, apply retention, and add overhead for indexes and replication.

JAVA
package com.bank.capacity;

public class StorageEstimate {
    public static void main(String[] args) {
        long recordBytes = 1024;        // 1 KB per payment record
        long dailyWrites = 50_000_000;  // 50M payments/day
        long bytesPerDay = recordBytes * dailyWrites;  // 50 GB/day
        long bytesPerYear = bytesPerDay * 365;          // ~18 TB/year
        int retentionYears = 5;
        long rawStorage = bytesPerYear * retentionYears; // ~90 TB
        long withIndexes = rawStorage * 2;                // ~180 TB

        System.out.printf("Per day:   %d GB%n", bytesPerDay / (1024L * 1024 * 1024));
        System.out.printf("Per year:  %d TB%n", bytesPerYear / (1024L * 1024 * 1024 * 1024));
        System.out.printf("5-year with indexes: %d TB --> NEEDS SHARDING%n",
            withIndexes / (1024L * 1024 * 1024 * 1024));
    }
}
TEXT
Expected output:
Per day:   46 GB
Per year:  16 TB
5-year with indexes: 163 TB --> NEEDS SHARDING

How do you estimate bandwidth?

Multiply peak QPS by response size. Convert bytes to bits for network capacity.

JAVA
package com.bank.capacity;

public class BandwidthEstimate {
    public static void main(String[] args) {
        long peakQps = 2000;
        long responseSizeBytes = 2048;  // 2 KB
        long bytesPerSec = peakQps * responseSizeBytes; // 4 MB/s
        long bitsPerSec = bytesPerSec * 8;              // 32 Mbps

        System.out.printf("Peak bandwidth: %d MB/s = %d Mbps%n",
            bytesPerSec / (1024 * 1024), bitsPerSec / (1024 * 1024));
        System.out.println("Comfortably within one server NIC (1 Gbps)");
        System.out.println("For media-heavy responses --> need CDN");
    }
}
TEXT
Expected output:
Peak bandwidth: 3 MB/s = 30 Mbps
Comfortably within one server NIC (1 Gbps)
For media-heavy responses --> need CDN

How do you size a cache?

Apply the Pareto principle: 20% of items receive 80% of traffic. Multiply the hot item count by item size to get cache memory.

JAVA
package com.bank.capacity;

public class CacheEstimate {
    public static void main(String[] args) {
        long totalAccounts = 10_000_000;
        double hotFraction = 0.20; // Pareto: 20% get 80% of traffic
        long hotItems = (long) (totalAccounts * hotFraction); // 2M
        long itemSizeBytes = 1024; // 1 KB per cached balance
        long cacheBytes = hotItems * itemSizeBytes; // 2 GB

        System.out.printf("Hot items: %,d%n", hotItems);
        System.out.printf("Cache size: %d GB%n", cacheBytes / (1024 * 1024 * 1024));
        System.out.println("Fits one Redis node (typically 25-50 GB max)");
    }
}
TEXT
Expected output:
Hot items: 2,000,000
Cache size: 1 GB
Fits one Redis node (typically 25-50 GB max)

What are the latency numbers every engineer should know?

These numbers anchor all design decisions about where to place data and how many network hops are acceptable on the critical path.

| Operation | Approximate Latency |
|---|---|
| L1 cache reference | ~1 ns |
| Main memory reference | ~100 ns |
| SSD random read | ~100 us |
| Same-DC round trip | ~500 us |
| Read 1 MB from SSD | ~1 ms |
| Disk seek (HDD) | ~10 ms |
| Cross-continent round trip | ~150 ms |

JAVA
package com.bank.capacity;

public class LatencyNumbers {
    public static void main(String[] args) {
        System.out.println("Memory:        ~100 ns");
        System.out.println("SSD read:      ~100 us  (1000x slower than memory)");
        System.out.println("Same-DC hop:   ~500 us");
        System.out.println("HDD seek:      ~10 ms   (100x slower than SSD)");
        System.out.println("Cross-region:  ~150 ms  (300x slower than same-DC)");
        System.out.println("Key: avoid sequential cross-region calls on hot path");
    }
}
TEXT
Expected output:
Memory:        ~100 ns
SSD read:      ~100 us  (1000x slower than memory)
Same-DC hop:   ~500 us
HDD seek:      ~10 ms   (100x slower than SSD)
Cross-region:  ~150 ms  (300x slower than same-DC)
Key: avoid sequential cross-region calls on hot path

How does the estimate drive architecture decisions?

Each estimate maps to a concrete architecture choice.

| Estimate | Architecture Decision |
|---|---|
| QPS | Fleet size (via Little's Law or threads-per-pod) |
| Storage/year | Single node vs sharding |
| Read/write split | Where caches and replicas go |
| Bandwidth | Whether a CDN is mandatory |
| Latency numbers | Avoid sequential cross-region calls on hot path |

JAVA
package com.bank.capacity;

public class ArchitectureFromEstimate {
    public static void main(String[] args) {
        long peakQps = 2000;
        long storagePerYearTb = 16;
        long cacheSizeGb = 1;

        System.out.println("Peak QPS " + peakQps + " --> 4 pods at 500 QPS each");
        System.out.println("Storage " + storagePerYearTb + " TB/year --> sharding needed");
        System.out.println("Cache " + cacheSizeGb + " GB --> one Redis node");
        System.out.println("Bandwidth 30 Mbps --> single NIC OK, no CDN needed");
    }
}
TEXT
Expected output:
Peak QPS 2000 --> 4 pods at 500 QPS each
Storage 16 TB/year --> sharding needed
Cache 1 GB --> one Redis node
Bandwidth 30 Mbps --> single NIC OK, no CDN needed

What are common mistakes?

The most common mistake is over-precision. The goal is the right power of ten, not three decimal places.

JAVA
package com.bank.capacity;

public class CommonMistakes {
    public static void main(String[] args) {
        // WRONG: calculating to 3 decimal places
        System.out.println("WRONG: 'QPS is exactly 578.703'");
        System.out.println("CORRECT: 'QPS is roughly 500-600, peak ~2000'");

        // WRONG: sizing for average, not peak
        System.out.println("WRONG: '500 QPS average, provision for 500'");
        System.out.println("CORRECT: 'peak is 4x average = 2000, provision for 2000'");

        // WRONG: forgetting indexes and replication in storage
        System.out.println("WRONG: '18 TB/year raw'");
        System.out.println("CORRECT: '18 TB x 2 (indexes) x 3 (replicas) = 108 TB'");
    }
}
TEXT
Expected output:
WRONG: 'QPS is exactly 578.703'
CORRECT: 'QPS is roughly 500-600, peak ~2000'
WRONG: '500 QPS average, provision for 500'
CORRECT: 'peak is 4x average = 2000, provision for 2000'
WRONG: '18 TB/year raw'
CORRECT: '18 TB x 2 (indexes) x 3 (replicas) = 108 TB'

What should a senior engineer know?

  • State assumptions out loud; the interviewer wants to see reasoning, not just numbers.
  • Always size for peak, not average.
  • Split reads from writes early because they have different scaling strategies.
  • These numbers are the starting point; validate with real load tests before production.
  • The right power of ten tells you whether you need one server or a thousand.
JAVA
package com.bank.capacity;

public class SeniorInsights {
    public static void main(String[] args) {
        System.out.println("1. State assumptions: '10M DAU, 5 actions/day'");
        System.out.println("2. Size for peak (4x average), not average");
        System.out.println("3. Split reads (cache + replicas) from writes (primary)");
        System.out.println("4. Validate with load tests before production");
        System.out.println("5. Right power of ten > precise decimal");
    }
}
TEXT
Expected output:
1. State assumptions: '10M DAU, 5 actions/day'
2. Size for peak (4x average), not average
3. Split reads (cache + replicas) from writes (primary)
4. Validate with load tests before production
5. Right power of ten > precise decimal

Visual Overview

DIAGRAM
  Back-of-Envelope Flow

  Input: 10M DAU, 5 actions/day
  ┌────────────────────────────────────────┐
  │ QPS: 10M x 5 / 100K = 500 avg         │
  │      x 4 peak factor = 2000 peak      │
  ├────────────────────────────────────────┤
  │ Storage: 1KB x 50M/day = 50 GB/day    │
  │          x 365 = 18 TB/year           │
  │          x 5 years x 2 (indexes)      │
  │          = 180 TB --> NEEDS SHARDING   │
  ├────────────────────────────────────────┤
  │ Bandwidth: 2000 x 2KB = 4 MB/s (32Mb) │
  │            --> single NIC OK           │
  ├────────────────────────────────────────┤
  │ Cache: 20% of 10M x 1KB = 2 GB        │
  │        --> one Redis node              │
  └────────────────────────────────────────┘

  Estimate --> Architecture
  QPS        --> fleet size
  Storage    --> sharding
  Bandwidth  --> CDN?
  Cache      --> Redis topology

Key Takeaway

A back-of-envelope capacity estimate grounds an architecture in physical reality. You derive QPS from daily active users and actions, scale daily storage to yearly, compute bandwidth from rate times payload, and size the cache from the hot fraction. The latency numbers anchor everything: memory is roughly 1,000 times faster than SSD, SSD is 1,000 times faster than HDD seek, and a cross-continent round trip is 150 ms no matter how fast the server.

The estimate drives architecture decisions: QPS sizes the fleet, storage per year decides sharding, the read/write split places caches and replicas, bandwidth decides whether a CDN is mandatory, and the latency numbers keep slow cross-region calls off the critical path.

At National Bank of India, Pankaj estimated a transaction-history service: 10M DAU at 5 actions gave 500 average and 2,000 peak QPS, the write volume projected to over 160 TB with indexes so it needed sharding, and the hot 20% of accounts fit in about 2 GB of Redis on one node.

Remember one sentence: turn users and actions into QPS, bytes per day into bytes per year, rate times payload into bandwidth, and the hot fraction into cache size, all anchored by the latency numbers, because the right power of ten tells you whether you need one server or a thousand.

---

Share
Use ← → arrow keys to navigate