Масштабирование и производительность
Что такое масштабирование?
Масштабирование (Scaling) — это способность системы справляться с растущей нагрузкой путём добавления ресурсов. Есть два основных подхода:
┌─────────────────────────────────────────────────────────────┐
│ МАСШТАБИРОВАНИЕ │
├────────────────────────┬────────────────────────────────────┤
│ Вертикальное (Scale Up)│ Горизонтальное (Scale Out) │
│ │ │
│ Увеличиваем мощность │ Добавляем больше серверов │
│ одного сервера │ │
│ │ │
│ ┌──────────┐ │ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ ████████ │ │ │ ██ │ │ ██ │ │ ██ │ │
│ │ ████████ │ │ │ ██ │ │ ██ │ │ ██ │ │
│ │ ████████ │ │ └─────┘ └─────┘ └─────┘ │
│ │ ████████ │ │ │
│ └──────────┘ │ + Больше CPU, RAM, диска │
│ │ + Отказоустойчивость │
│ + Просто │ - Сложнее в управлении │
│ - Есть предел │ - Нужна синхронизация │
│ - Single point of │ + Нет теоретического предела │
│ failure │ │
└────────────────────────┴────────────────────────────────────┘Вертикальное масштабирование (Scale Up)
Увеличение ресурсов одного сервера: больше CPU, RAM, быстрее диски.
Плюсы:
- Простая реализация — не нужно менять архитектуру
- Нет проблем с распределённостью и синхронизацией
- Подходит для начального этапа
Минусы:
- Есть физический предел (самый мощный сервер ограничен)
- Single Point of Failure — если сервер упадёт, всё рухнет
- Стоимость растёт экспоненциально (удвоение мощности ≠ удвоение цены)
Когда использовать: начальные стадии проекта, базы данных (до определённого предела), когда данные не партиционируются.
Горизонтальное масштабирование (Scale Out)
Добавление большего количества серверов в пул.
Плюсы:
- Теоретически неограниченное масштабирование
- Отказоустойчивость — падение одного сервера не роняет систему
- Экономически эффективно (commodity hardware)
Минусы:
- Сложная архитектура (распределённые системы)
- Нужна синхронизация данных между узлами
- Требуется балансировка нагрузки
Когда использовать: высоконагруженные системы, stateless-сервисы, когда нужна отказоустойчивость.
Практика крупных компаний
Google, Netflix, Amazon используют горизонтальное масштабирование. Вместо одного суперсервера — тысячи обычных серверов, объединённых в кластер.
Балансировка нагрузки (Load Balancing)
Балансировщик нагрузки распределяет входящие запросы между несколькими серверами.
Клиенты
/ | \
/ | \
┌────▼────▼────▼────┐
│ Load Balancer │
└──┬──────┬──────┬──┘
│ │ │
┌────▼─┐ ┌──▼───┐ ┌▼─────┐
│ Srv 1│ │ Srv 2│ │ Srv 3│
└──────┘ └──────┘ └──────┘Алгоритмы балансировки
1. Round Robin
Запросы распределяются по кругу: 1 → 2 → 3 → 1 → 2 → 3 → ...
Запрос 1 → Сервер A
Запрос 2 → Сервер B
Запрос 3 → Сервер C
Запрос 4 → Сервер A (по кругу)
Запрос 5 → Сервер BПлюсы: простота, равномерное распределение. Минусы: не учитывает текущую загрузку серверов.
2. Weighted Round Robin
Как Round Robin, но серверы получают трафик пропорционально весу.
Сервер A (вес 5): █████
Сервер B (вес 3): ███
Сервер C (вес 2): ██Используется когда: серверы имеют разную мощность.
3. Least Connections
Запрос направляется на сервер с наименьшим числом активных соединений.
Сервер A: 12 соединений
Сервер B: 5 соединений ← новый запрос пойдёт сюда
Сервер C: 8 соединенийПлюсы: учитывает реальную загрузку. Идеален для: длительных соединений (WebSocket, стриминг).
4. IP Hash
Хеш IP-адреса клиента определяет сервер. Один и тот же клиент всегда попадает на один сервер.
hash(client_ip) % N = номер сервера
hash("192.168.1.1") % 3 = 0 → Сервер A
hash("10.0.0.5") % 3 = 2 → Сервер CПлюсы: sticky sessions без хранения состояния. Минусы: при добавлении/удалении серверов маршруты меняются.
5. Consistent Hashing
Решает проблему IP Hash при изменении числа серверов. Используется в распределённых кешах и БД.
Хеш-кольцо (0 ... 2^32)
┌───┐
S1 ──┤ ├── S2
│ │
Key A ──► │ │ ◄── Key B
│ │
S3 ──┤ ├── S4
└───┘
Ключ попадает на ближайший сервер
по часовой стрелке на кольце.
При добавлении S5 перераспределяется
только часть ключей (не все).Используется в: Amazon DynamoDB, Apache Cassandra, Memcached.
Уровни балансировки
| Уровень | Протокол | Описание | Пример |
|---|---|---|---|
| L4 (Transport) | TCP/UDP | Балансировка по IP и порту | HAProxy, AWS NLB |
| L7 (Application) | HTTP/HTTPS | Балансировка по URL, заголовкам, cookies | Nginx, AWS ALB |
L7 балансировка — можно маршрутизировать по URL:
/api/* → Серверы API
/static/* → CDN / Серверы статики
/admin/* → Административные серверыCDN (Content Delivery Network)
CDN — сеть географически распределённых серверов, которые кешируют и раздают контент ближе к пользователям.
Без CDN: С CDN:
Пользователь Пользователь
(Токио) (Токио)
│ │
│ 200ms │ 20ms
│ │
▼ ┌───▼───┐
┌───────┐ │ CDN │ (Edge-сервер в Токио)
│Origin │ │ Node │
│Server │ └───┬───┘
│(Нью- │ │ cache miss?
│Йорк) │ │ 200ms (один раз)
└───────┘ ┌───▼───┐
│Origin │
│Server │
└───────┘Типы CDN
Push CDN:
- Контент загружается на CDN заранее
- Вы контролируете, что и когда загружать
- Подходит для сайтов с редко меняющимся контентом
Pull CDN:
- CDN запрашивает контент с origin при первом обращении
- Автоматическое кеширование
- Подходит для сайтов с высоким трафиком
Что размещать в CDN
- Статические файлы (JS, CSS, изображения, шрифты)
- Видео и аудио
- HTML-страницы (для статических сайтов)
- API-ответы (с осторожностью, нужна стратегия инвалидации)
Примеры CDN: CloudFront (AWS), Cloudflare, Akamai, Fastly.
Репликация баз данных
Репликация — создание копий базы данных на нескольких серверах.
Master-Slave (Primary-Replica)
┌──────────┐
Запись ───► │ Master │
│ (Primary)│
└─────┬────┘
│ репликация
┌──────────┼──────────┐
│ │ │
┌────▼───┐ ┌───▼────┐ ┌──▼─────┐
│ Slave 1│ │ Slave 2│ │ Slave 3│ ◄─── Чтение
│(Replica)│ │(Replica)│ │(Replica)│
└────────┘ └────────┘ └────────┘- Master обрабатывает все записи
- Slave (реплики) обрабатывают чтения
- Подходит для систем с соотношением чтение:запись >> 1
Master-Master (Multi-Primary)
┌──────────┐ ┌──────────┐
│ Master 1 │◄───►│ Master 2 │
└────┬─────┘ └────┬─────┘
│ │
Запись/Чтение Запись/Чтение- Оба сервера принимают записи
- Более сложная синхронизация
- Риск конфликтов при одновременной записи
Синхронная vs асинхронная репликация
| Характеристика | Синхронная | Асинхронная |
|---|---|---|
| Консистентность | Сильная | Eventual |
| Latency записи | Выше (ждём подтверждения) | Ниже |
| Потеря данных | Нет | Возможна |
| Доступность | Ниже | Выше |
Шардирование баз данных
Шардирование (Sharding) — разбиение данных на части (шарды), которые хранятся на разных серверах.
Все пользователи (1M)
│
┌────────────┼────────────┐
│ │ │
┌────▼────┐ ┌───▼────┐ ┌───▼────┐
│ Shard 1 │ │ Shard 2│ │ Shard 3│
│ A - H │ │ I - P │ │ Q - Z │
│ 333K │ │ 333K │ │ 333K │
└─────────┘ └────────┘ └────────┘Стратегии шардирования
По ключу (Hash-based)
shard_id = hash(user_id) % num_shards- Равномерное распределение
- Сложно добавлять шарды (нужен rehash)
По диапазону (Range-based)
Shard 1: user_id 1 - 1,000,000
Shard 2: user_id 1,000,001 - 2,000,000
Shard 3: user_id 2,000,001 - 3,000,000- Просто добавлять шарды
- Возможна неравномерная нагрузка (hotspots)
По географии
Shard EU: пользователи из Европы
Shard US: пользователи из Америки
Shard Asia: пользователи из Азии- Низкая latency для пользователей
- Используется в глобальных системах
Проблемы шардирования
- JOINs — запросы через шарды очень дорогие
- Ребалансировка — перемещение данных при добавлении шардов
- Горячие шарды — неравномерная нагрузка
- Транзакции — распределённые транзакции сложны
Путь масштабирования: от 0 до 1M пользователей
Этап 1: Один сервер (0 - 1K пользователей)
┌─────────┐ ┌──────────────────┐
│ Клиенты │────►│ Один сервер │
└─────────┘ │ App + DB + Кеш │
└──────────────────┘Этап 2: Разделение (1K - 10K)
┌─────────┐ ┌──────────┐ ┌──────┐
│ Клиенты │────►│ App │────►│ DB │
└─────────┘ │ Server │ └──────┘
└──────────┘Этап 3: Масштабирование чтения (10K - 100K)
┌─────────┐ ┌────┐ ┌───────┐ ┌────────┐
│ Клиенты │────►│ LB │────►│ App │────►│ Master │
└─────────┘ └────┘ │Servers│ └───┬────┘
│ (x3) │ │
└───┬───┘ ┌────▼────┐
│ │ Replicas│
└───────►│ (x2) │
(чтение) └─────────┘Этап 4: Кеширование и CDN (100K - 1M)
┌─────┐
┌───►│ CDN │ (статика)
┌─────────┐ │ └─────┘
│ Клиенты │────┤
└─────────┘ │ ┌────┐ ┌─────┐ ┌───────┐ ┌────────┐
└───►│ LB │───►│ App │───►│ Redis │───►│ DB │
└────┘ │(x5) │ │ Cache │ │Sharded │
└─────┘ └───────┘ └────────┘Этап 5: Полная архитектура (1M+)
┌──────────┐ ┌─────┐ ┌────┐ ┌──────────┐
│ Клиенты │────►│ CDN │────►│ LB │────►│ API │
└──────────┘ └─────┘ └────┘ │ Gateway │
└────┬─────┘
┌───────────────┼───────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ Service │ │ Service │ │ Service │
│ A │ │ B │ │ C │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
┌────▼────┐ ┌───▼────┐ ┌───▼────┐
│ DB A │ │ DB B │ │ DB C │
│(sharded)│ │(sharded)│ │(sharded)│
└─────────┘ └────────┘ └────────┘
│
┌─────────┼─────────┐
│ │ │
┌────▼──┐ ┌──▼───┐ ┌──▼────┐
│ Redis │ │ Kafka│ │Elastic│
│ Cache │ │Queue │ │Search │
└───────┘ └──────┘ └───────┘Вопросы для собеседования
- В чём разница между вертикальным и горизонтальным масштабированием?
- Как работает Load Balancer? Какие алгоритмы вы знаете?
- Что такое Consistent Hashing и зачем он нужен?
- Объясните разницу между Push CDN и Pull CDN.
- Когда использовать Master-Slave, а когда Master-Master репликацию?
- Какие проблемы возникают при шардировании?
- Как бы вы масштабировали систему с 1000 до 1 000 000 пользователей?
Ключевой принцип
Масштабирование — это не только про технологии, но и про компромиссы. Каждое решение имеет цену: больше серверов — сложнее управление, шардирование — сложнее JOINs, кеширование — проблемы с инвалидацией. Хороший инженер понимает эти trade-offs.