Здесь применим всё из предыдущих глав к трём классическим system design задачам. Каждый расчёт -- от требований до выбора технологий, как на senior-интервью.
Example 1: URL Shortener (bit.ly)
Требования
- 100 M новых URL per month (create)
- Read:Write = 10:1 (каждую короткую ссылку открывают 10 раз)
- Retention: 5 лет (после -- archive/delete)
- Availability: 99.9%
- Redirect latency: < 100 ms global
Шаг 1: QPS
Writes:
100M / month = 100M / (30 × 86400) ≈ 38 writes/sec avg
peak (x3) = 115 writes/sec
Reads (10x writes):
380 reads/sec avg
peak = 1 150 reads/sec
Итого: 1.2k peak RPS. Это небольшая нагрузка -- один хороший instance держит.
Шаг 2: Storage
Объект URL:
- short_code: 7 chars (base62, поддерживает 62^7 ≈ 3.5×10^12 уникальных)
- long_url: ~100 bytes avg
- created_at: 8 bytes
- user_id: 16 bytes (UUID)
- metadata (clicks, geo, etc): 50 bytes
- Total per record: ~200 bytes
5 лет × 12 месяцев × 100M = 6 B URLs
Raw storage = 6 × 10^9 × 200 = 1.2 TB
+ indexes (30%) = 1.56 TB
× replication (3) = 4.7 TB
+ backups (50%) = 7 TB total
Шаг 3: Bandwidth
Redirect = 302 с Location header. Response ~300 bytes (headers + empty body).
Peak egress = 1 150 × 300 B = 345 KB/sec = 2.7 Mbps
Ничего. Обычный load balancer пропускает.
Click analytics ingestion (если трекать):
1 150 clicks/sec × 500 bytes (event) = 575 KB/sec ingress в analytics pipeline
Шаг 4: Cache sizing
Популярные ссылки читаются часто (viral), длинный хвост -- редко. Классический Zipf.
Total URLs: 6B
Hot (1% популярных дают 90% трафика): 60M URLs
Cache entry: 120 bytes (short_code + long_url + small metadata)
Working set: 60M × 120 = 7 GB
Влезает в один r5.xlarge (32 GB RAM). С запасом -- r5.2xlarge (64 GB) или Redis cluster 2-3 ноды.
Шаг 5: Выбор БД
Варианты:
- PostgreSQL: 7 TB на одной ноде тяжело, придётся шардить. Плюс: транзакции, SQL.
- MySQL со sharding: опыт YouTube. Minus: ручной шардинг.
- Cassandra/DynamoDB: key-value, отлично подходит (
short_code → long_url). Минус: нет транзакций. - Redis как source of truth: плохо -- persistence дорог, 7 TB RAM = $$$.
Рекомендация: Cassandra/DynamoDB как primary, Redis как hot cache.
Архитектура
┌────────────┐
User ──HTTP GET──▶ │ CDN │ Кэш 302 ответов (TTL 1 час)
└─────┬──────┘
│ miss
▼
┌────────────┐
│ ALB │
└─────┬──────┘
│
┌─────────┴─────────┐
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ API node │ ... │ API node │ Go/Gin, 3-5 instances m5.large
└─────┬────┘ └─────┬────┘
│ │
└──────┬─────────────┘
│
┌──────▼──────┐
│ Redis │ Cache: hot URLs, rate limit
│ (cluster) │ Hit rate > 95%
└──────┬──────┘
│ miss
┌──────▼──────┐
│ DynamoDB │ 6B records, key-value
│ / Cassandra │ RF=3, eventual consistency OK
└─────────────┘
Analytics: Click events → Kinesis/Kafka → Redshift/BigQuery
Шаг 6: Servers
- API: 5 × m5.large (2 vCPU, 8 GB) -- каждая держит 1k RPS на Go = 5k capacity на 1.2k peak load (x4 запас)
- Redis: 3 × r5.xlarge cluster
- DynamoDB: autoscale, начать с 1 500 RCU / 200 WCU
Шаг 7: Cost (AWS примерно)
| Компонент | Monthly cost |
|---|---|
| 5 × m5.large | $365 |
| 3 × r5.xlarge (Redis) | $550 |
| DynamoDB (6B items, autoscale) | $3 000 |
| S3 backup | $150 |
| CDN (CloudFront) | $400 |
| Total | ~$4 500 |
Example 2: Twitter-like feed
Требования
- 200 M DAU
- 5 tweets per active user per day
- 50 feed refreshes per user per day
- avg followers: 200 (Pareto: 20% users have 80% followers, max 100M followers)
- Home timeline latency: p99 < 500 ms
- Retention: forever (public)
Шаг 1: QPS
Tweets (writes):
200M × 5 = 1B tweets/day
avg = 1B / 86400 ≈ 12 000 tweets/sec
peak (x3) = 35 000 tweets/sec
Feed reads:
200M × 50 = 10B reads/day
avg = 115 000 reads/sec
peak = 350 000 reads/sec
350k peak reads/sec, 35k writes/sec. Это серьёзная инфра.
Шаг 2: Fan-out математика
Есть две стратегии:
- Push (fan-out on write): при твите -- записать в timeline каждого followers. Быстро читать.
- Pull (fan-out on read): при чтении -- собрать с timelines всех followed. Быстро писать.
Hybrid (используется Twitter):
- Обычные users (≤ 10k followers): push
- Celebrities (> 10k followers): pull на чтении feed'а
- Граница настраивается
Fan-out стоимость:
12 000 tweets/sec × 200 avg followers = 2.4M timeline writes/sec (push)
35 000 peak × 200 = 7M writes/sec peak
7M writes/sec -- это Redis cluster на 50-100 нод, иначе никак. Celebrities exclusion снижает на 30-50%.
Шаг 3: Storage
Tweets:
Avg tweet: text 280 B + metadata 300 B + media refs = 600 B
Daily raw: 1B × 600 B = 600 GB/day
Annually: 220 TB/year
Compressed (3x for structured): 70 TB/year
× RF=3: 210 TB/year storage
Timelines (если push):
200M users × 1000 tweets cached = 200B timeline entries
Entry size: ~100 B (tweet_id + author_id + score)
Storage: 200B × 100 B = 20 TB (in Redis!)
20 TB RAM -- это ~60 × r5.12xlarge (384 GB each). Дорого, но реально для Twitter-scale.
Media (25% tweets):
Images 25% × 500K × 1B tweets = 125B images over all time
Daily: 250M × 300 KB = 75 TB/day (невероятно, поэтому Twitter жмёт и шрафически сжимает)
Шаг 4: Cache sizing
Home timeline cache:
- 200M users, 20% active daily = 40M hot timelines
- 500 tweets per timeline × 100 B = 50 KB per timeline
- Hot cache: 40M × 50 KB = 2 TB
Это 10 × r5.12xlarge (384 GB) или 20 × r5.6xlarge (192 GB).
Шаг 5: Bandwidth
Feed read response: 20 tweets initial, ~50 KB JSON.
Peak egress = 350k RPS × 50 KB = 17.5 GB/sec = 140 Gbps
Это требует CDN + много API-нод с 10-25 Gbps uplinks. CDN кэширует public profile data, но home feed -- персонализирован, так что offload низкий (20-40%).
Шаг 6: Выбор БД
| Компонент | Технология | Обоснование |
|---|---|---|
| Tweets (authoritative) | Cassandra / Manhattan | Append-heavy, TS-sorted, шардинг по user_id |
| Timelines (hot) | Redis Cluster | Sorted sets, микросекундный доступ |
| User graph (followers) | Graph DB / sharded MySQL | Связи, обход |
| Media | S3 + CloudFront | Object storage + CDN |
| Search | Elasticsearch | Full-text, в реальном времени |
| Trending/analytics | Flink + ClickHouse | Streaming aggregation |
Архитектура
┌──────────┐
User ──WSS──▶ │ CDN/Edge │ ← Static, public data
└────┬─────┘
▼
┌──────────┐
│ ALB │
└────┬─────┘
│
┌────▼───────────────────┐
│ API Gateway (Kong) │ Auth, rate limit, routing
└──┬──────────┬──────────┘
│ │
┌───────▼─┐ ┌────▼────────┐
│ Tweet │ │ Timeline │ Go microservices
│ service │ │ service │
└───┬─────┘ └─────┬───────┘
│ │
│ ┌──────┴─────────┐
│ │ │
▼ ▼ ▼
┌──────┐ ┌─────────┐ ┌──────────┐
│Kafka │ │ Redis │ │Cassandra │
└──┬───┘ │ Cluster │ │ (tweets, │
│ └─────────┘ │ graph) │
▼ └──────────┘
┌──────────┐
│ Fan-out │ Celery/workers
│ workers │ Push timelines on write
└──────────┘
Шаг 7: Servers (rough)
| Компонент | Ноды |
|---|---|
| API servers | 500 × m5.2xlarge |
| Redis timeline cache | 60 × r5.12xlarge |
| Cassandra (tweets + graph) | 200 × i3.4xlarge |
| Kafka (events) | 50 × m5.2xlarge |
| Elasticsearch (search) | 100 × r5.2xlarge |
| Fan-out workers | 200 × c5.2xlarge |
| Media (S3) | managed |
| CDN | CloudFront, multi-region |
Примерный monthly infrastructure cost: $2-5M.
Example 3: Instagram photos
Требования
- 500 M DAU
- 2 photos upload per user per day (average; large variance)
- 50 photos viewed per user per day (scrolling feed + explore)
- Photo retention: forever
- Thumbnail sizes: original + 4 derivatives (1080w, 640w, 320w, 150w)
- Global access, p99 < 300 ms
Шаг 1: QPS
Uploads:
500M × 2 = 1B photos/day
avg = 11 500 photos/sec
peak = 35 000 photos/sec
Views:
500M × 50 = 25B views/day
avg = 290 000 views/sec
peak = 870 000 views/sec
870k peak views/sec -- но 99% идут через CDN. Origin видит ~1% = 9k RPS.
Шаг 2: Storage (photos)
Размеры:
| Variant | Avg size |
|---|---|
| Original (JPEG 90% quality, 4000x3000) | 3 MB |
| 1080w (feed) | 250 KB |
| 640w (retina) | 120 KB |
| 320w (thumb) | 40 KB |
| 150w (avatar) | 15 KB |
| Total per photo | ~3.4 MB |
Daily raw upload:
1B × 3 MB (original) = 3 PB/day originals
+ 1B × 425 KB (derivatives) = 425 TB/day
Total daily: ~3.4 PB/day
Annually: 1.2 EB (!) raw
With S3 replication (built-in): storage billed 1x
S3 Standard cost: 1 EB × $23/TB = $23M/month just for year 1
Оптимизация: тiered storage
- Hot (last 30 days): S3 Standard
- Warm (30-180 days): S3 Standard-IA
- Cold (180+ days): S3 Glacier Instant Retrieval
Costs drop ~70%.
Шаг 3: Metadata DB
Photo metadata record:
- photo_id (UUID 16B)
- user_id (16B)
- timestamp (8B)
- location (16B optional)
- caption (avg 100B)
- tags, mentions (100B avg)
- variant URLs (5 × 50B = 250B)
- Total: ~500 B
Metadata daily: 1B × 500 B = 500 GB/day
Annually: 180 TB/year
With RF=3: 540 TB/year
Это для Cassandra или DynamoDB по user_id.
Шаг 4: Bandwidth (самое важное)
Peak views: 870 000 views/sec
Avg size served: 250 KB (1080w variant, dominant)
Peak egress: 870k × 250 KB = 217 GB/sec = 1.7 Tbps
1.7 Tbps -- CDN is mandatory.
CDN hit ratio: 95% (media is highly cacheable)
Origin egress: 5% × 217 GB/s = 11 GB/s = 90 Gbps
CDN egress cost: 1.7 Tbps × 30 days × 86400 s = 5.4 EB/month
(unrealistic -- это значит триллионы долларов, CDN pricing снижается с объёмом)
Instagram использует свой edge PoP + партнёрство с CDN (Meta EdgeNetwork). За деньги извне -- $0.01-0.02/GB в bulk.
Шаг 5: Cache sizing
Feed view: 95% фото -- из последних 30 дней. Это 30B фото.
CDN edge cache (global):
Hot 10% = 3B photos × avg 250 KB = 750 TB distributed across PoPs
Per PoP (50 PoPs worldwide): 15 TB
Metadata cache (Redis):
- 100M active users feeds × 100 recent photo meta × 500 B = 5 TB
- Redis cluster: 20 × r5.12xlarge
Шаг 6: Upload pipeline
Upload flow:
Client ──POST multipart──▶ Upload API
│
▼
┌──────────────┐
│ Validate │ ClamAV virus scan,
│ + pre-sign │ EXIF strip, hash dedup
└──────┬───────┘
│
▼
┌──────────────┐
│ S3 (origin) │ Store original
└──────┬───────┘
│ S3 event
▼
┌──────────────┐
│ Resize worker│ Lambda/Fargate
│ (5 variants) │ writes back to S3
└──────┬───────┘
│
▼
┌──────────────┐
│ Write meta │ Cassandra
│ Push to feed │ Kafka → fan-out
│ of followers │
└──────────────┘
Шаг 7: Архитектура
User (mobile) ────▶ ┌────────────┐
│ CDN Edge │ Meta EdgeNetwork + CloudFront
│ (global) │ 95%+ hit ratio on media
└──┬─────┬───┘
│ │ miss
media ◀─┘ │
▼
┌────────────────┐
│ API / Feed │ Go services, 1000+ instances
│ Service │
└───┬──────┬─────┘
│ │
┌──────┘ └──────┐
▼ ▼
┌──────────────┐ ┌─────────────┐
│ Redis (feed │ │ Cassandra │ Photo metadata,
│ cache) │ │ (metadata) │ user timelines
└──────────────┘ └─────────────┘
Upload: → S3 (origin) → Lambda (resize) → S3 (derivatives) + meta DB
Fan-out: Kafka → Feed generation workers → Redis
Шаг 8: Cost sketch
| Компонент | Monthly cost (rough) |
|---|---|
| S3 (exabytes with tiering) | $15M |
| CDN egress (1.5 EB/month) | $15M |
| Cassandra cluster (500 × i3.4xlarge) | $1.5M |
| Redis (20 × r5.12xlarge) | $200k |
| API servers (1000+ instances) | $1M |
| Resize Lambda | $500k |
| Total | ~$35M/month |
(Reality check: Meta spends billions/year on infra.)
Сравнительная таблица
| Метрика | URL Shortener | Twitter feed | |
|---|---|---|---|
| DAU | ~10M | 200M | 500M |
| Peak RPS | 1 200 | 350 000 | 870 000 (views) |
| Storage/year | ~1 TB text | 210 TB | 1.2 EB |
| Cache size (hot) | 7 GB | 2 TB | 750 TB (CDN) |
| CDN critical? | Nice to have | Partially | Mandatory |
| Primary DB | DynamoDB/Cassandra | Cassandra | Cassandra + S3 |
| Monthly cost | ~$5k | ~$3M | ~$35M |
Общий pattern для любой worked example
- Read requirements -- вычлените DAU, actions, retention
- Compute QPS -- avg + peak, split read/write
- Compute storage -- raw × index × RF × backup + 5-year growth
- Compute bandwidth -- QPS × response size, CDN offload
- Compute cache -- working set (hot objects × size)
- Choose DB -- по нагрузке read/write и схеме доступа
- Draw architecture -- клиент → CDN → LB → API → cache → DB
- Estimate servers + cost -- по QPS и known instance capacity
Выводы
- URL shortener -- small scale: 1k RPS, 1 TB, $5k/month. Один r5.xlarge + DynamoDB решают.
- Twitter-like -- hybrid fan-out (push для обычных, pull для celebrities), 2 TB timeline cache
- Instagram-like -- dominated CDN и S3: текстовая БД мала, media измеряется экзабайтами
- Общий алгоритм: QPS → Storage → Bandwidth → Cache → DB → Architecture → Cost
- Peak capacity под product-specific bursts: Twitter FIFA finals 10x от normal peak