Обзор
Между клиентом и сервером обычно находится несколько промежуточных компонентов, каждый из которых решает свою задачу: кеширование, безопасность, балансировка, маршрутизация.
┌────────┐ ┌─────────┐ ┌───────────┐ ┌──────────┐ ┌────────┐
│ Клиент ├────►│ Forward ├────►│ CDN ├────►│ Reverse ├────►│Backend │
│ │ │ Proxy │ │ (Edge) │ │ Proxy │ │Server │
│ │ │(корпор.)│ │ │ │ / LB │ │ │
└────────┘ └─────────┘ └───────────┘ └──────────┘ └────────┘
Браузер Опционально Ближайшая точка Точка входа Приложение
присутствия в дата-центр
Зачем знать для System Design
- CDN -- ключевой компонент для снижения латентности глобальных сервисов
- Reverse proxy и LB -- обязательные элементы любой production-архитектуры
- На собеседовании: «Как обеспечить низкую латентность для пользователей по всему миру?»
Forward Proxy
Что такое Forward Proxy
Forward proxy -- посредник, действующий от имени клиента. Клиент знает о прокси и направляет через него запросы.
Без прокси:
Клиент ──────────────────────► Сервер
(сервер видит IP клиента)
С Forward Proxy:
Клиент ──► Forward Proxy ──► Сервер
(сервер видит IP прокси, не клиента)
Применения
| Применение |
Описание |
| Корпоративный контроль |
Блокировка нежелательных сайтов |
| Анонимность |
Скрытие IP клиента (VPN, Tor) |
| Кеширование |
Кеш частых запросов (Squid) |
| Обход ограничений |
Доступ к заблокированным ресурсам |
| Логирование |
Аудит интернет-активности |
Пример: корпоративный прокси
┌─────────────┐
│ Сотрудник A ├──┐
└─────────────┘ │ ┌──────────────┐ ┌──────────────┐
├────►│ Squid Proxy ├────►│ Интернет │
┌─────────────┐ │ │ │ │ │
│ Сотрудник B ├──┘ │ • Кеш │ │ example.com │
└─────────────┘ │ • Фильтрация │ │ blocked.com ✗│
│ • Логирование│ └──────────────┘
└──────────────┘
Reverse Proxy
Что такое Reverse Proxy
Reverse proxy -- посредник, действующий от имени сервера. Клиент не знает о backend-серверах и обращается к прокси.
Forward Proxy: Reverse Proxy:
Клиент знает о прокси Клиент не знает о backend
Клиент ──► [FP] ──► Сервер Клиент ──► [RP] ──► Backend 1
↑ Настроен клиентом ↑ Настроен сервером │
├──► Backend 2
└──► Backend 3
Функции Reverse Proxy
┌────────────────────────────────────────────────────────┐
│ Reverse Proxy │
│ │
│ ┌────────────┐ ┌─────────────┐ ┌───────────────────┐ │
│ │ TLS │ │ Compression │ │ Rate Limiting │ │
│ │Termination │ │ (gzip, br) │ │ (защита от DDoS) │ │
│ └────────────┘ └─────────────┘ └───────────────────┘ │
│ ┌────────────┐ ┌─────────────┐ ┌───────────────────┐ │
│ │ Caching │ │ URL Rewrite │ │ Authentication │ │
│ │ (статика) │ │ / Routing │ │ (OAuth, JWT) │ │
│ └────────────┘ └─────────────┘ └───────────────────┘ │
│ ┌────────────┐ ┌─────────────┐ ┌───────────────────┐ │
│ │ Load │ │ WAF │ │ Request/Response │ │
│ │ Balancing │ │ (firewall) │ │ Transformation │ │
│ └────────────┘ └─────────────┘ └───────────────────┘ │
└────────────────────────────────────────────────────────┘
Популярные Reverse Proxy
| Инструмент |
Особенности |
Применение |
| Nginx |
Высокая производительность, event-driven |
Веб-серверы, API gateway |
| HAProxy |
Лучший для L4/L7 балансировки |
Высоконагруженные системы |
| Envoy |
Service mesh, gRPC, observability |
Kubernetes, Istio |
| Traefik |
Автоматическая конфигурация, Let's Encrypt |
Docker, Kubernetes |
| Caddy |
Автоматический HTTPS, простота |
Малые/средние проекты |
Load Balancer
Уровни балансировки
┌───────────────────────────────────────────────────────┐
│ L4 Load Balancer (Transport) │
│ │
│ Работает с: TCP/UDP пакетами │
│ Видит: IP-адреса, порты │
│ Не видит: HTTP-заголовки, cookies, URL │
│ Скорость: Очень высокая (~миллионы conn/sec) │
│ Примеры: AWS NLB, LVS, IPVS │
└───────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────┐
│ L7 Load Balancer (Application) │
│ │
│ Работает с: HTTP-запросами │
│ Видит: URL, заголовки, cookies, тело запроса │
│ Может: content-based routing, SSL termination │
│ Скорость: Ниже (~сотни тысяч req/sec) │
│ Примеры: AWS ALB, Nginx, HAProxy, Envoy │
└───────────────────────────────────────────────────────┘
Сравнение L4 vs L7
| Критерий |
L4 (Transport) |
L7 (Application) |
| Что видит |
IP, порт |
URL, заголовки, cookie |
| TLS |
Passthrough или termination |
Termination |
| Routing |
IP:port → backend |
URL path, host, headers |
| WebSocket |
Прозрачно |
Нужна поддержка Upgrade |
| Производительность |
Миллионы conn/sec |
Сотни тысяч req/sec |
| Health checks |
TCP SYN/ACK |
HTTP GET /health |
| Session affinity |
IP hash |
Cookie-based |
| Стоимость |
Ниже |
Выше |
Алгоритмы балансировки
Round Robin
Запросы распределяются по кругу:
Запрос 1 ──► Server A
Запрос 2 ──► Server B
Запрос 3 ──► Server C
Запрос 4 ──► Server A (по кругу)
Запрос 5 ──► Server B
...
Плюсы: простой, равномерный
Минусы: не учитывает нагрузку серверов
Weighted Round Robin
Server A (weight=5): получает 5 из 10 запросов (50%)
Server B (weight=3): получает 3 из 10 запросов (30%)
Server C (weight=2): получает 2 из 10 запросов (20%)
Применение: серверы с разной мощностью, canary deployment
Least Connections
Запрос направляется на сервер с наименьшим числом активных соединений:
Server A: 12 connections ─┐
Server B: 5 connections ─┼── Запрос → Server C (минимум)
Server C: 3 connections ─┘
Плюсы: адаптивный, учитывает реальную нагрузку
Применение: запросы с разным временем обработки
IP Hash
hash(client_ip) % num_servers = server_index
Client 192.168.1.1 → hash → Server A (всегда)
Client 192.168.1.2 → hash → Server C (всегда)
Client 192.168.1.3 → hash → Server B (всегда)
Плюсы: session affinity без cookies
Минусы: неравномерность при малом числе клиентов, проблемы с NAT
Consistent Hashing
0°
│
┌───────┴───────┐
S3 │ │ S1
│ Hash Ring │
│ │
S2 │ │
└───────┬───────┘
│
180°
Ключ K1 → хеш → попадает в зону S1
Ключ K2 → хеш → попадает в зону S2
При добавлении S4: перераспределяется только ~1/N ключей
При удалении S2: ключи S2 переходят к следующему серверу (S3)
Применение: кеширование, шардирование, CDN
Least Response Time
Запрос направляется на сервер с минимальным временем ответа:
Server A: avg 45ms ─┐
Server B: avg 12ms ─┼── Запрос → Server B (быстрейший)
Server C: avg 78ms ─┘
Плюсы: оптимизация латентности
Минусы: нужен мониторинг, может быть нестабильным
Health Checks
Passive (наблюдение):
LB отслеживает ответы backend
5xx ответов > порога → сервер помечен unhealthy
Active (опрос):
LB периодически отправляет проверочные запросы
LB ── GET /health ──► Server A ── 200 OK ✓
LB ── GET /health ──► Server B ── 200 OK ✓
LB ── GET /health ──► Server C ── timeout ✗ → Убрать из ротации
interval: 10 сек
threshold: 3 неудачи → unhealthy
recovery: 2 успеха → healthy
Пример конфигурации
# Nginx upstream with health checks and weights
upstream api_backend {
least_conn; # Algorithm
server 10.0.1.1:8080 weight=5; # Primary (more powerful)
server 10.0.1.2:8080 weight=3; # Secondary
server 10.0.1.3:8080 weight=2; # Tertiary
server 10.0.1.4:8080 backup; # Backup (only if all down)
keepalive 32; # Connection pooling
}
server {
listen 443 ssl http2;
server_name api.example.com;
# TLS termination
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
location /api/ {
proxy_pass http://api_backend;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
# Timeouts
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
}
location /static/ {
# Serve static files directly
root /var/www;
expires 30d;
add_header Cache-Control "public, immutable";
}
}
CDN (Content Delivery Network)
Что такое CDN
CDN -- распределённая сеть серверов (Edge/PoP), кеширующих контент ближе к пользователю.
Без CDN:
Пользователь (Москва) ──── 150ms ────► Origin (Вирджиния)
Пользователь (Токио) ──── 200ms ────► Origin (Вирджиния)
С CDN:
Пользователь (Москва) ──── 10ms ─────► PoP (Москва)
Пользователь (Токио) ──── 5ms ─────► PoP (Токио)
│ cache miss?
└── 150ms → Origin
Архитектура CDN
┌──────────────────┐
│ Origin Server │
│ (ваш сервер) │
└────────┬─────────┘
│
┌──────────────┼──────────────┐
│ │ │
┌─────▼──────┐ ┌────▼───────┐ ┌────▼───────┐
│ Shield/Mid │ │ Shield │ │ Shield │
│ (US-East) │ │ (EU-West) │ │ (AP-East) │
└─────┬──────┘ └────┬───────┘ └────┬───────┘
│ │ │
┌─────┼───┐ ┌────┼───┐ ┌─────┼───┐
│ │ │ │ │ │ │ │ │
┌─▼─┐┌─▼─┐┌▼┐ ┌─▼─┐┌─▼─┐┌▼┐ ┌─▼──┐┌─▼─┐┌▼┐
│NYC││BOS││DC│ │LDN││AMS││FR│ │TKY ││SEL││SG│
│PoP││PoP││Po│ │PoP││PoP││Po│ │PoP ││PoP││Po│
└───┘└───┘└──┘ └───┘└───┘└──┘ └────┘└───┘└──┘
Edge Points of Presence (PoPs)
Как работает CDN
1. Пользователь запрашивает: https://static.example.com/image.jpg
2. DNS резолвит static.example.com → IP ближайшего PoP (Anycast)
3. PoP проверяет кеш:
Cache HIT: Cache MISS:
PoP ── image.jpg ──► Пользователь PoP ── GET /image.jpg ──► Origin
(~5 мс) PoP ◄── image.jpg ────── Origin
PoP кеширует + отдаёт пользователю
(~150 мс первый запрос)
4. Заголовки кеширования:
Cache-Control: public, max-age=86400
CDN-Cache-Control: max-age=604800
Vary: Accept-Encoding
Что кешировать на CDN
| Контент |
Кешировать? |
TTL |
Заголовок |
| Статика (JS, CSS, изображения) |
Да |
Долго (1 год) |
Cache-Control: public, max-age=31536000, immutable |
| API-ответы (публичные) |
Да |
Короткий (60с) |
Cache-Control: public, max-age=60, s-maxage=300 |
| API-ответы (персональные) |
Нет |
- |
Cache-Control: private, no-store |
| HTML (SSR) |
Возможно |
Короткий (60с) |
Cache-Control: public, s-maxage=60, stale-while-revalidate=300 |
| Видео/аудио |
Да |
Долго |
Cache-Control: public, max-age=604800 |
Инвалидация кеша CDN
Стратегия 1: Хеш в имени файла (рекомендуется)
/assets/app.a1b2c3d4.js → Новая сборка = новый хеш = новый URL
Старый файл всё ещё в кеше, но никто его не запрашивает
Стратегия 2: Purge API
curl -X POST https://api.cloudflare.com/purge \
-d '{"files": ["https://example.com/style.css"]}'
Стратегия 3: Surrogate Keys (теги)
Surrogate-Key: product-123 homepage
Purge по тегу: все объекты с тегом "product-123"
Стратегия 4: stale-while-revalidate
Cache-Control: max-age=60, stale-while-revalidate=300
Отдаёт устаревший контент, пока обновляет в фоне
CDN провайдеры
| Провайдер |
PoPs |
Особенности |
| Cloudflare |
300+ |
WAF, DDoS, Workers (edge computing) |
| AWS CloudFront |
450+ |
Интеграция с AWS, Lambda@Edge |
| Akamai |
4000+ |
Enterprise, крупнейшая сеть |
| Fastly |
80+ |
VCL, Instant Purge, Compute@Edge |
| Google Cloud CDN |
140+ |
Интеграция с GCP |
CDN для динамического контента
Современные CDN кешируют не только статику:
Edge Computing:
┌────────┐ ┌───────────────────┐ ┌────────┐
│ Клиент ├───►│ Edge Worker ├───►│ Origin │
│ │ │ │ │ │
│ │ │ • A/B тесты │ │ │
│ │ │ • Персонализация │ │ │
│ │ │ • Auth проверка │ │ │
│ │ │ • Геолокация │ │ │
│ │◄───┤ • Трансформация │◄───┤ │
└────────┘ └───────────────────┘ └────────┘
Cloudflare Workers, AWS Lambda@Edge, Fastly Compute
Сравнительная таблица
| Критерий |
Forward Proxy |
Reverse Proxy |
Load Balancer |
CDN |
| Действует от имени |
Клиента |
Сервера |
Сервера |
Сервера |
| Клиент знает? |
Да |
Нет |
Нет |
Нет |
| Основная задача |
Анонимность, фильтрация |
Безопасность, routing |
Распределение нагрузки |
Кеширование, латентность |
| Кеширование |
Да |
Да |
Нет |
Да (основная функция) |
| TLS |
Опционально |
Termination |
L4 passthrough / L7 term |
Edge termination |
| Масштаб |
Локальный |
Один дата-центр |
Один дата-центр |
Глобальный |
| Примеры |
Squid, Privoxy |
Nginx, Envoy |
HAProxy, AWS ALB/NLB |
Cloudflare, CloudFront |
Архитектура production-системы
┌─────────┐ ┌───────────┐ ┌─────────────┐ ┌──────────┐
│ Клиент ├────►│ CDN ├────►│ L4 LB ├────►│ L7 LB / │
│ │ │(статика + │ │(TCP/UDP, │ │ Reverse │
│ │ │ edge) │ │ высокая │ │ Proxy │
└─────────┘ └───────────┘ │ пропускная │ │(routing, │
│ способность)│ │ TLS) │
└─────────────┘ └────┬─────┘
│
┌────────────────┼────────────────┐
│ │ │
┌─────▼────┐ ┌─────▼────┐ ┌─────▼────┐
│ Backend │ │ Backend │ │ Backend │
│ Server 1 │ │ Server 2 │ │ Server 3 │
└──────────┘ └──────────┘ └──────────┘
DNS + CDN + LB: полный путь запроса
1. Клиент вводит api.example.com
2. DNS (Route 53, GeoDNS) → IP ближайшего CDN PoP
3. CDN Edge:
- Cache HIT → ответ клиенту (5 мс)
- Cache MISS → запрос к Origin
4. L4 Load Balancer (NLB) → TCP → L7 Load Balancer (ALB)
5. L7 LB: TLS termination, routing по URL/headers
6. Backend обрабатывает запрос
7. Ответ возвращается клиенту, CDN кеширует (если можно)
Суммарная латентность:
Cache HIT: 5-20 мс (CDN)
Cache MISS: 50-200 мс (CDN → Origin → Backend)