Free lesson · System Design Interviews
Step 2: Capacity Estimation
Pastebin's capacity estimation is where most candidates make their first architectural mistake. They estimate the QPS, see that it's low (~300 reads/sec), and conclude that this is a "simple" system. Then they forget to estimate the bandwidth and storage, which is where the real engineering challenge lives. A paste is not 300 bytes - it's 10 KB on average and up to 10 MB. That changes everything.
Let me walk you through the math the way I'd do it in an interview - thinking out loud, rounding aggressively, and making sure every number connects to a design decision. The key insight I want you to walk away with is this: Pastebin is a storage system that happens to have an API, not an API that happens to store things.
Traffic Estimation
Starting Assumptions
From our requirements conversation:
- 5 million new pastes created per day
- Read-to-write ratio: 5:1 (each paste is viewed ~5 times on average)
- Average paste size: 10 KB
- Maximum paste size: 10 MB
Write QPS (Paste Creation)
5 million writes/day
÷ 86,400 seconds/day (round to ~100,000 for mental math)
= ~50 QPS average
Peak (3x average): ~150 QPS
Fifty writes per second. A single application server can handle this without breaking a sweat. This is not a write-throughput problem. But each write carries an average of 10 KB of content - which we need to upload to object storage. Let's track that.
Read QPS (Paste Viewing)
5 million × 5 reads per paste = 25 million reads/day
25 million / 100,000 = ~250 QPS average
Peak (3x average): ~750 QPS
Two hundred fifty reads per second. Again, a single server can handle this request rate. But each read returns content - 10 KB on average. The bottleneck isn't how many requests per second; it's how many bytes per second.
flowchart TB
subgraph TRAFFIC["Traffic Summary"]
WRITE["Writes: ~50 QPS avg<br/>~150 QPS peak"]
READ["Reads: ~250 QPS avg<br/>~750 QPS peak"]
RATIO["Read:Write = 5:1"]
end
WRITE -->|"Each write = 10 KB avg<br/>Total: 500 KB/sec"| W_NOTE["Storage write throughput<br/>is the real metric"]
READ -->|"Each read = 10 KB avg<br/>Total: 2.5 MB/sec"| R_NOTE["Bandwidth is the<br/>bottleneck, not QPS"]
COMPARE["Compare to URL Shortener:<br/>URL Shortener: 100K QPS × 300 bytes = 30 MB/sec<br/>Pastebin: 250 QPS × 10 KB = 2.5 MB/sec<br/>Lower bandwidth, but much larger per-request payload"]
Traffic summary for Pastebin. Write QPS is about 50 average, peaking at 150. Read QPS is about 250 average, peaking at 750. The read-to-write ratio is 5 to 1. Unlike URL Shortener where the challenge is handling 100,000 tiny requests per second, Pastebin's challenge is handling moderate request rates with much larger payloads. Each read returns 10 kilobytes on average, making bandwidth the design concern rather than QPS.
Interview: How to present this: "We're looking at about 50 write QPS and 250 read QPS - extremely manageable from a request-rate perspective. A single server could handle this. But the interesting constraint is content size - at 10 KB average, each read returns 30x more data than a URL shortener redirect. The architecture needs to optimise for content delivery, not for request throughput. That's why I'll reach for S3 and CDN instead of just Redis."
Storage Estimation
This is where Pastebin gets interesting. Unlike URL Shortener's tidy 300 bytes per record, Pastebin stores actual content - and the size distribution matters.
Content Storage (Object Storage / S3)
Daily content volume:
5 million pastes/day × 10 KB average = 50 GB/day
Monthly: 50 GB × 30 = 1.5 TB/month
Annual: 50 GB × 365 = ~18 TB/year
5 years (without expiration): 18 TB × 5 = ~90 TB
But wait - pastes expire. If the average paste lifetime is 30 days (because most users accept the default expiration), the steady-state storage is much lower:
Steady-state with 30-day average lifetime:
50 GB/day × 30 days = ~1.5 TB at any given time
With mixed expiration (some never-expire):
- 60% expire within 30 days → 50 GB × 0.6 × 30 = 900 GB
- 25% expire within 1 year → grows to 50 GB × 0.25 × 365 = ~4.5 TB/year
- 15% never expire → grows to 50 GB × 0.15 × 365 = ~2.7 TB/year
Year 1 total: 900 GB + 4.5 TB + 2.7 TB ≈ 8 TB
Year 5 total: 900 GB + 4.5 TB + (2.7 TB × 5) ≈ 19 TB
flowchart LR
DAILY["Daily Ingestion<br/>50 GB/day"] --> EXPIRE{"Expiration?"}
EXPIRE -->|"60% expire<br/>within 30 days"| STEADY["~900 GB<br/>steady state"]
EXPIRE -->|"25% expire<br/>within 1 year"| GROWING["~4.5 TB/year<br/>moderate growth"]
EXPIRE -->|"15% never expire"| FOREVER["~2.7 TB/year<br/>unbounded growth"]
STEADY --> TOTAL["Year 1: ~8 TB<br/>Year 5: ~19 TB"]
GROWING --> TOTAL
FOREVER --> TOTAL
Storage estimation with expiration. Pastebin ingests 50 gigabytes of content per day. But pastes expire, which controls storage growth. About 60% of pastes expire within 30 days, creating a steady-state pool of about 900 gigabytes. 25% expire within a year, adding 4.5 terabytes annually. 15% never expire, adding 2.7 terabytes per year indefinitely. After 5 years, total content storage is about 19 terabytes - much less than the 90 terabytes you'd estimate without accounting for expiration. This is manageable for a single S3 bucket.
19 TB over 5 years is very manageable for S3. Amazon S3 stores exabytes of data - 19 TB is nothing. Storage cost at S3 Standard pricing (~$0.023/GB/month): roughly $440/month at year 5. This is not a cost-driven architecture problem.
Tip: Always estimate with expiration. Candidates who say "90 TB over 5 years" without accounting for expiration are overestimating by 4-5x. The interviewer knows this. Showing that you understand expiration's effect on storage growth demonstrates operational maturity. "Our steady-state storage is around 8 TB, growing by about 3 TB per year from never-expire pastes" is a much more credible estimate.
Metadata Storage (Database)
Alongside the content in S3, each paste has a metadata record in the database:
| Field | Size | Notes |
|---|---|---|
| Paste ID / short code | 8 bytes | Unique identifier |
| S3 content key | ~50 bytes | Pointer to content in object storage |
| Language type | 20 bytes | For syntax highlighting (e.g., "python", "javascript") |
| Content size (bytes) | 8 bytes | For display and rate limiting |
| Created timestamp | 8 bytes | When the paste was created |
| Expires timestamp | 8 bytes | When the paste expires |
| Creator IP | 16 bytes | For abuse detection (IPv6) |
| Title (optional) | ~100 bytes | User-provided title |
| Visibility flag | 1 byte | Public/unlisted |
| Delete token hash | 32 bytes | SHA-256 hash for delete authorization |
| Indexes overhead | ~50 bytes | B-tree indexes |
Total per metadata record: ~300 bytes (coincidentally similar to URL Shortener)
Metadata storage:
5 million records/day × 300 bytes = 1.5 GB/day
Annual: 1.5 GB × 365 = ~550 GB/year
5 years: ~2.7 TB
With expiration cleaning up 60% within 30 days:
Steady-state active records: ~150 million records
Active metadata: 150 million × 300 bytes = ~45 GB
45 GB of active metadata is tiny. A single PostgreSQL instance handles this comfortably. No sharding needed for the metadata layer.
Bandwidth Estimation
This is the calculation that matters most for Pastebin. URL Shortener's bandwidth was negligible. Pastebin's bandwidth drives the CDN and caching architecture.
Read Bandwidth (Paste Viewing)
Average case:
250 QPS × 10 KB = 2.5 MB/sec = 20 Mbps
Peak:
750 QPS × 10 KB = 7.5 MB/sec = 60 Mbps
60 Mbps peak is still well within a single server's network capacity (most servers have 1-10 Gbps NICs). But consider the worst case - what if a popular paste is 1 MB and gets 100 views/sec?
Hot large paste:
100 reads/sec × 1 MB = 100 MB/sec = 800 Mbps
This is getting close to a single server's network capacity.
This is why we need a CDN. The CDN serves the content from edge nodes, offloading bandwidth from the origin servers. Without CDN, a single viral 1 MB paste could saturate the origin server's network.
Write Bandwidth (Paste Creation)
50 QPS × 10 KB = 500 KB/sec = 4 Mbps
Peak:
150 QPS × 10 KB = 1.5 MB/sec = 12 Mbps
Write bandwidth is negligible. Uploading to S3 at 1.5 MB/sec is effortless.
The Bandwidth Asymmetry
flowchart TD
subgraph WRITE_BW["Write Bandwidth"]
WB["4 Mbps average<br/>12 Mbps peak<br/>Negligible"]
end
subgraph READ_BW["Read Bandwidth"]
RB["20 Mbps average<br/>60 Mbps peak<br/>Manageable"]
end
subgraph SPIKE_BW["Viral Paste Spike"]
SB["800 Mbps possible<br/>for a single hot paste<br/>CDN required"]
end
READ_BW -->|"Normal"| OK["Single server handles this"]
SPIKE_BW -->|"Viral content"| CDN_NEEDED["CDN absorbs spike<br/>Origin protected"]
Bandwidth asymmetry in Pastebin. Write bandwidth is negligible at 4 to 12 megabits per second. Normal read bandwidth is manageable at 20 to 60 megabits per second - a single server handles this fine. But a viral large paste can spike to 800 megabits per second, which is enough to saturate a server's network interface. This is why a CDN is essential - it absorbs bandwidth spikes at edge nodes and protects the origin servers from being overwhelmed.
Interview: What to say: "The average bandwidth is modest - 20 Mbps for reads. But Pastebin has a heavy-tail problem. A single viral paste that's 1 MB could generate 800 Mbps of bandwidth on its own. The CDN is essential not for the average case, but for the spike case. Without CDN, one popular paste could take down the entire read path."
Paste ID Space Estimation
Like URL Shortener, we need a unique identifier for each paste. But the traffic is much lower.
At 5 million pastes/day:
- Per year: 1.825 billion pastes
- 5 years: 9.125 billion pastes
- 10 years: 18.25 billion pastes
Using 8-character Base62:
62^8 = ~218 trillion possible codes
218 trillion / 18.25 billion (10 years) = 11,945x headroom
Using 6-character Base62:
62^6 = ~56.8 billion possible codes
56.8 billion / 18.25 billion (10 years) = 3.1x headroom - tight
7-character Base62:
62^7 = ~3.5 trillion possible codes
3.5 trillion / 18.25 billion (10 years) = 192x headroom - comfortable
8 characters is the safe choice for Pastebin. It gives 218 trillion codes - effectively infinite runway. 7 characters would work too, but 8 characters is still short enough for URLs and gives us an order of magnitude more headroom.
Tip: Don't waste interview time on this calculation if you've already done it for URL Shortener. Simply say: "Same approach as URL Shortener - 8-character Base62 gives us 218 trillion codes, far more than the 18 billion pastes we'll create over 10 years. I'd use the same pre-allocated counter range approach for code generation." Move on to the more interesting Pastebin-specific calculations.
S3 Request Cost Estimation
Since we're storing content in S3, let's estimate the S3 API costs - because in a real system design review, someone will ask about operational costs.
PUT requests (writes):
5 million pastes/day × 30 days = 150 million PUTs/month
At $0.005 per 1,000 PUTs: $750/month
GET requests (reads):
25 million reads/day × 30 days = 750 million GETs/month
At $0.0004 per 1,000 GETs: $300/month
Storage:
~8 TB at year 1 × $0.023/GB = ~84/month
Total S3 cost: ~,234/month at year 1
This is extremely affordable. S3 is the right storage layer - no need to run your own blob storage.
Content Compression Estimation
Most paste content is text - highly compressible. Adding gzip compression reduces storage and bandwidth:
Average paste size: 10 KB
Average compressed size (gzip): ~3 KB (70% compression ratio for text)
Storage savings:
50 GB/day uncompressed → ~15 GB/day compressed
Year 1 total: ~8 TB → ~2.5 TB compressed
Bandwidth savings:
2.5 MB/sec read bandwidth → ~0.75 MB/sec compressed
Client decompresses - transparent via Content-Encoding: gzip
Compression is free performance - every web server and browser supports it. The 70% reduction in storage and bandwidth costs is significant.
flowchart LR
ORIGINAL["Original paste<br/>10 KB (avg)"] --> GZIP["gzip compression"]
GZIP --> COMPRESSED["Compressed paste<br/>3 KB (avg)"]
COMPRESSED --> STORED["Stored in S3<br/>at 3 KB"]
COMPRESSED --> SERVED["Served to browser<br/>with Content-Encoding: gzip"]
SERVED --> BROWSER["Browser<br/>decompresses<br/>automatically"]
SAVINGS["Storage: 70% reduction<br/>Bandwidth: 70% reduction<br/>CPU: minimal (text compresses fast)"]
Content compression for Pastebin. Text content compresses extremely well with gzip - typically a 70% reduction. A 10 kilobyte average paste compresses to about 3 kilobytes. This reduces storage from 50 gigabytes per day to about 15 gigabytes per day, and reduces read bandwidth from 2.5 megabytes per second to about 0.75 megabytes per second. Compression is essentially free - every web server and browser supports gzip transparently, and text compresses very fast with minimal CPU overhead.
Interview: Mention compression proactively. "I'd store content gzip-compressed in S3 and serve it with
Content-Encoding: gzip. Text compresses 60-80% with gzip, which cuts our storage and bandwidth costs by roughly 70%. The browser decompresses automatically. This is a free optimization that I'd implement from day one."
The Complete Estimation Summary
| Metric | Value | Design Implication |
|---|---|---|
| Write QPS | 50 avg / 150 peak | Single server handles writes easily |
| Read QPS | 250 avg / 750 peak | Single server handles request rate |
| Read:Write ratio | 5:1 | Moderate - less cache-dependent than URL Shortener |
| Avg paste size | 10 KB (3 KB compressed) | Bandwidth matters more than QPS |
| Max paste size | 10 MB | Must handle large uploads and downloads |
| Daily content ingestion | 50 GB (15 GB compressed) | Manageable for S3 |
| Steady-state storage | ~8 TB year 1 (2.5 TB compressed) | Single S3 bucket, no sharding |
| Active metadata | ~45 GB | Single PostgreSQL instance |
| Peak read bandwidth | 60 Mbps (avg) / 800 Mbps (viral spike) | CDN required for spikes |
| Paste ID length | 8 chars (Base62) | 218T codes, infinite runway |
| View latency target | <200ms p99 | CDN + cache for hot pastes |
| S3 monthly cost | ~,234 at year 1 | Very affordable |
Interview: The meta-lesson for Pastebin estimation: "Two numbers tell you 80% of the architecture: the 5:1 read-write ratio and the 10 KB average content size. The 5:1 ratio means this isn't as cache-dependent as URL Shortener - the read traffic is manageable. The 10 KB average means bandwidth is the bottleneck, not QPS. Every architecture decision - S3 for storage, CDN for delivery, compression by default - follows from these two numbers."
Key Takeaways
-
Pastebin is bandwidth-bound, not QPS-bound. At 250 read QPS, request throughput is trivial. But at 10 KB per response, bandwidth accumulates - and a viral 1 MB paste can spike to 800 Mbps on its own. CDN is essential for the spike case.
-
Expiration dramatically reduces storage estimates. Without expiration: 90 TB over 5 years. With realistic expiration: ~19 TB. With compression: ~6 TB. Always estimate with expiration and compression - the naive estimate is 15x too high.
-
Content compression is a free 70% reduction. Text compresses beautifully with gzip. Store compressed, serve compressed, let the browser decompress. This should be your default for any text-content system.
-
S3 is the right storage layer for variable-size content. 19 TB of text content at
,234/month is trivially affordable. S3 handles the size variance (1 KB to 10 MB) naturally. Don't put this content in a relational database. -
Metadata and content have different storage economics. 45 GB of metadata fits in PostgreSQL. 19 TB of content goes in S3. Treat them as separate systems with separate scaling properties.
-
The paste ID space is not the interesting calculation. 8-character Base62 gives effectively infinite runway. Spend your interview time on the bandwidth and storage estimates instead - those are the numbers that drive Pastebin-specific architecture decisions.
Exercise: Exercise 1: Redo the estimation for a Pastebin that serves 50 million pastes per day (10x our estimate - closer to GitHub Gists + all Pastebin clones combined). What changes? Does the single-server write path still work? How does the CDN bill change? Is S3 still the right storage choice?
Exercise 2: Estimate the cost of the complete system at year 1. Include: 2 c5.large application servers, 1 db.r6g.large PostgreSQL instance, S3 storage and request costs, CloudFront CDN serving 750 million requests/month with 10 KB average payload, and Redis cache (1 node, r6g.large). Compare this to a URL Shortener of similar scale.
Exercise 3: The content size distribution shows that 2% of pastes are 1-10 MB. But those 2% account for what percentage of total storage? Calculate: if 2% of 5 million daily pastes = 100,000 pastes at an average of 3 MB each, that's 300 GB/day from just the large pastes - compared to 50 GB/day total. Is the distribution correct? How does this tail-heavy distribution affect caching strategy?