MidПрактика7 min

Bandwidth и память

Расчёт egress/ingress bandwidth, CDN offload, RAM sizing для кэша, Pareto 80/20, AWS instance types

Bandwidth: ingress vs egress

  • Ingress (inbound) -- что прилетает в ваш DC. Обычно дёшево или бесплатно (AWS: $0).
  • Egress (outbound) -- что улетает к клиентам. Дорого (AWS: $0.09/GB в интернет).

Правило: egress стоит в 5-20 раз дороже storage. 1 TB egress в месяц = $90 (AWS). 10 TB = $900.

Типичные bandwidth источники

Клиент ←── Egress (API response, static files) ──── Сервер
       ──→ Ingress (request, uploads) ───────────→

Server-to-server (внутри DC): бесплатно в пределах AZ
Cross-AZ внутри региона: $0.01/GB
Cross-region: $0.02/GB
В интернет (public): $0.09/GB (первый TB), дешевле с объёмом

CDN offload

CDN перехватывает 80-99% запросов к статическому контенту. Это радикально снижает bandwidth cost.

Без CDN:              Клиент → Ваш сервер (100% egress)
С CDN (hit 95%):      Клиент → CDN edge → Ваш сервер (5% egress)

Cost эффект

Сценарий Egress от вас CDN cost Итого
Without CDN 100 TB × $0.09 = $9 000 $0 $9 000
With CDN (95% hit) 5 TB × $0.09 = $450 100 TB × $0.02 = $2 000 $2 450

Экономия 73% + быстрее клиенту.

Что хорошо cacheable

Контент Hit ratio
Images, videos, CSS/JS 95-99%
HTML (static pages) 80-95%
API responses (public, TTL 60s) 50-80%
User-specific API 0-20%

Базовая формула bandwidth

Bandwidth (bytes/sec) = QPS × average_response_size

Пример: 3 000 RPS × 50 KB response = 150 MB/sec = 1.2 Gbps.

Для сравнения: 1 Gbps Ethernet пропускает 125 MB/s. Значит, одного гигабита мало -- нужен 10 Gbps uplink или CDN.

Типичные размеры ответов

Тип ответа Размер
JSON API (small) 1-5 KB
JSON API (средний, с pagination) 20-100 KB
HTML page (compressed) 50-200 KB
HTML + inline CSS/JS 500 KB - 2 MB
Image (avatar) 10-30 KB
Image (photo) 200 KB - 2 MB
Video chunk (HLS) 1-5 MB

RAM sizing для кэша

Главный вопрос: сколько надо RAM для кэша, чтобы покрыть X% запросов?

Правило Парето: 80/20

Для большинства consumer-сервисов 20% объектов генерируют 80% запросов. Ещё более жёстко: 5% объектов -- 50% трафика (Zipf distribution).

Формула working set

Working set = total_objects × hot_percentage × avg_size

Пример (social feed):

  • 100M users
  • 20% активны daily = 20M hot users
  • avg timeline data = 100 KB
  • working set = 20M × 100 KB = 2 TB

2 TB в одну ноду не положить. Но если цель -- покрыть 80% запросов, надо только top 20% hot users = 400 GB. Это 2-3 Redis ноды r5.12xlarge (384 GB RAM).

Cache hit ratio target

Hit ratio RAM Эффект
50% 10% от working set Снижает DB load на 50%
80% 20% от working set Снижает DB load на 80%
95% 50% от working set Снижает DB load на 95%
99% 80% от working set DB почти простаивает

Sweet spot -- 90-95%. Последние 5% cost exponentially.

AWS instance types для backend

Запомните pattern: буква = семейство, цифра = поколение.

Instance vCPU RAM Network Use case
t3.medium 2 4 GB Up to 5 Gbps Dev, мелкие сервисы
m5.xlarge 4 16 GB Up to 10 Gbps General-purpose API
m5.4xlarge 16 64 GB Up to 10 Gbps Heavy API
c5.2xlarge 8 16 GB Up to 10 Gbps CPU-bound (encode, ML)
r5.xlarge 4 32 GB Up to 10 Gbps Redis/cache small
r5.4xlarge 16 128 GB Up to 10 Gbps Postgres primary
r5.12xlarge 48 384 GB 12 Gbps Large cache node
x1e.32xlarge 128 3.9 TB 25 Gbps In-memory DB (SAP HANA)
i3.4xlarge 16 122 GB + 3.8 TB NVMe 10 Gbps Local NVMe (Cassandra)

Rule of thumb:

  • API server: m5.xlarge (4 vCPU, 16 GB) -- держит 2-5k RPS для Go, 500-1500 для PHP
  • Postgres: r5.2xlarge-r5.4xlarge для medium load
  • Redis: r5.xlarge-r5.12xlarge по working set
  • Load balancer: не нужен, используйте ALB/NLB (managed)

Network limits

1 Gbps vs 10 Gbps vs 25 Gbps

Link MB/s Response 50 KB Response 500 KB
1 Gbps 125 2 500 RPS 250 RPS
10 Gbps 1 250 25 000 RPS 2 500 RPS
25 Gbps 3 125 62 500 RPS 6 250 RPS

Практика. Для API servers 10 Gbps хватает на 10-20k RPS. Если упираетесь -- чаще проблема в CPU/DB, не в network.

Intra-DC vs cross-DC

Ссылка Bandwidth Latency Cost
Same host (loopback) 100+ GB/s < 50 µs $0
Same rack 10-25 Gbps 0.1-0.5 ms $0
Same AZ 10 Gbps 0.5-1 ms $0
Cross-AZ 10 Gbps 1-2 ms $0.01/GB
Cross-region 10 Gbps 60-150 ms $0.02/GB
Public internet limited by ISP 10-200 ms $0.09/GB egress

Worked пример: видеостриминг

Сервис на 1M concurrent viewers, 1080p HD (5 Mbps per stream).

Peak bandwidth

Total bandwidth = 1M × 5 Mbps = 5 Tbps

5 Tbps = 5 × 10^12 / 8 = 625 GB/s

Cost без CDN (невозможно)

Ежедневно (прогрев 6 часов): 625 GB/s × 3600 × 6 = 13.5 PB/day
Egress cost: 13.5 PB × $90/TB = $1.2M/day
Ежемесячно: ~$36M

С CDN (offload 99.5%)

Egress от origin: 13.5 PB × 0.005 = 67.5 TB/day → $6k/day
CDN cost: 13.5 PB × $0.01/GB = $135k/day
Total: ~$4M/month

Даже с CDN видео -- дорого. Поэтому YouTube строит свои CDN (Google Edge), Netflix использует Open Connect.

Storage для контента

1080p фильм, 2 часа = ~5-7 GB
VOD каталог 10k фильмов = 10k × 6 GB = 60 TB
Adaptive bitrate (5 качеств) = 60 × 3 = 180 TB
С replication: 540 TB

Калькулятор bandwidth + memory

<?php

declare(strict_types=1);

/**
 * Bandwidth and memory sizing helpers.
 */
final class NetworkSizing
{
    /**
     * Compute outbound bandwidth in bytes/sec for API traffic.
     */
    public static function egressBytesPerSec(int $qps, int $avgResponseBytes): int
    {
        return $qps * $avgResponseBytes;
    }

    /**
     * Monthly egress cost in USD.
     * Default AWS rate: $0.09/GB for first 10TB, averaged for simplicity.
     */
    public static function monthlyEgressCost(
        int $qps,
        int $avgResponseBytes,
        float $cdnHitRatio = 0.0,
        float $costPerGb = 0.09,
    ): float {
        $secondsPerMonth = 30 * 86_400;
        $totalBytes = $qps * $avgResponseBytes * $secondsPerMonth;
        $originBytes = $totalBytes * (1 - $cdnHitRatio);
        $gb = $originBytes / (1024 ** 3);
        return round($gb * $costPerGb, 2);
    }

    /**
     * Gbps needed for given QPS/response size.
     */
    public static function requiredGbps(int $qps, int $avgResponseBytes): float
    {
        $bitsPerSec = $qps * $avgResponseBytes * 8;
        return round($bitsPerSec / 1e9, 2);
    }
}

/**
 * Cache sizing via Pareto / working set.
 */
final class CacheSizing
{
    /**
     * Estimate RAM needed to achieve target hit ratio under Zipf distribution.
     * Approximation: hit_ratio ≈ cache_share ^ 0.3 (heavy Zipf alpha ~0.8).
     */
    public static function ramForHitRatio(
        int $totalObjects,
        int $avgObjectBytes,
        float $targetHitRatio = 0.9,
    ): int {
        // Inverse of approximation: share = hit_ratio ^ (1/0.3)
        $cacheShare = $targetHitRatio ** (1 / 0.3);
        $cachedObjects = (int) ($totalObjects * $cacheShare);
        return $cachedObjects * $avgObjectBytes;
    }

    /**
     * Working set = hot objects × size.
     */
    public static function workingSetBytes(
        int $totalObjects,
        float $hotShare,
        int $avgObjectBytes,
    ): int {
        return (int) ($totalObjects * $hotShare * $avgObjectBytes);
    }
}

// Usage:
// NetworkSizing::requiredGbps(3000, 50*1024) => 1.23 (Gbps)
// CacheSizing::ramForHitRatio(100_000_000, 1024, 0.9) => ~700 GB
## Чек-лист для capacity planning
  1. Bandwidth: QPS × avg_response_size × 8 = bits/sec. Сравните с uplink (1/10/25 Gbps).
  2. Egress cost: умножьте на секунды в месяце и на $0.09/GB (AWS public internet).
  3. CDN candidate? Если ratio cacheable > 80% -- обязательно CDN.
  4. Working set: hot_objects × avg_size. Положите в RAM (Redis cluster).
  5. Instance type: по RAM выбирайте r-family, по CPU -- c-family, универсально -- m-family.
  6. Growth: x2 per year -- закладывайте сразу.

Частые ошибки

  • Забыть egress cost. Storage $20/TB/month, egress $90/TB. Разница 4.5x.
  • Считать RAM по total data. Working set меньше total в 5-20 раз. Кэшируйте только hot.
  • Не использовать CDN. 100 TB egress direct = $9k/month. С CDN = $2k/month.
  • Cross-AZ для hot path. Межзональный трафик стоит $0.01/GB, легко добавляет $1000/месяц.

Выводы

  • 1 Gbps = 125 MB/s. 10 Gbps = 1.25 GB/s. Формула bandwidth: QPS × response_size × 8.
  • Egress дорог: $0.09/GB в интернет, используйте CDN для всего cacheable
  • Working set = 20% от total (Pareto). Cache hit 90% достижим с 20-30% RAM от full.
  • Instance types: m5 general, c5 CPU-bound, r5 memory-bound (Redis/Postgres)
  • Video streaming -- самая bandwidth-тяжёлая задача: CDN не опция, а обязательность