Нагрузка и масштабирование
Высоконагруженные системы: масштабирование и балансировка
1. Паттерн и его назначение
Паттерн высоконагруженной системы отвечает на один вопрос: как продолжать отвечать быстро, когда запросов становится больше, чем тянут узлы. Это классическая ситуация роста: 100 → 1000 → 10 000 запросов в секунду, и каждое удвоение по-разному бьёт по ресурсам.
Два механизма, на которых держится масштабирование:
- Вертикальное масштабирование — сделать один узел мощнее: больше ядер, памяти, быстрее диски. Простое, но упирается в потолок конкретного сервера и в цену «самой большой» машины.
- Горизонтальное масштабирование — добавить узлов и распределить работу между ними. Сложнее: нужен балансировщик, репликация данных, управление сессиями и согласованностью.
Второй элемент паттерна — балансировка нагрузки. Когда узлов несколько, каждый запрос должен попадать на свободный, а не на перегруженный. Балансировщик распределяет запросы и убирает единую точку отказа.
Для зрелой системы оба подхода объединяются: вертикалью выходят из маленьких пиков, горизонталью — из большого роста. Выбор зависит от типа нагрузки и требований по доступности.
2. Как работает (схема)
Горизонтальная схема типового высоконагруженного сервиса выглядит так:
*клиенты → балансировщик → ферма приложений (N узлов) → реплицированная БД / кэш / СХД*
Балансировщик принимает запрос, выбирает узел и перенаправляет его. Узлы приложения не хранят состояние — оно вынесено в базу и кэш. Это ключевое условие горизонтального масштабирования: если узел хранит сессию, добавить второй без пересборки нельзя.
Балансировка работает на двух уровнях:
- L4 (транспортный). Распределяет по IP и порту, без разбора содержимого. Быстрый, дешёвый, подходит для статики и базовых сервисов.
- L7 (прикладной). Видит содержимое запроса — URL, headers, куки — и может направлять по правилам. Гибче, но дороже по ресурсам.
Согласованность данных при горизонтальном масштабировании решается через репликацию. Плоскость «мастер-мастер» и «мастер-реплика» дают разный баланс между консистентностью и скоростью записи. Для недопустимости потерь смотрят консистентность и на доступность, так как это классический компромисс распределённых систем.
3. Компромиссы
| Решение | Плюс | Минус | Когда оправдано |
|---|---|---|---|
| Вертикальное масштабирование | Простое, без рефакторинга | Дорого, потолок по железу | Пики до 2–3 раз от среднего |
| Горизонтальное масштабирование | Линейный рост, отказоустойчивость | Нужны балансировщик и репликация | Постоянный рост и много узлов |
| Балансировка L4 | Быстрая, дешёвая | Не различает сервисы | Статика, сокеты, базовый баланс |
| Балансировка L7 | Гибкая, по правилам | Дороже по CPU и памяти | Разные бэкенды, канарейки, сегментация |
Нагрузка на приложение не растёт равномерно. Чтения доминируют над записями, поэтому часто балансируют чтения и выносят их на реплики, сохраняя мастер для записи. Это снижает давление на основной узел без усложнения архитектуры.
4. Реализация на отечественном стеке
Горизонтальная масштабируемость требует слоя, который не зависит от конкретной машины. На отечественном стеке это:
- Серверы из реестра Минпромторга — ферма приложений и узлы БД. Платформы DEPO, Рикор, Гравитон, Nerpa, Yadro дают линейку 1U и 2U под разные роли. Смотрите российские серверы.
- Мысль о производительности хранилища. Балансировщик снимает пик с CPU, но СХД часто становится узким местом. Узлы, реплики и кэш требуют стабильного IOPS. Подбор под нагрузку — в системах хранения данных.
- Сеть для канала к узлам. Для фермы с балансировщиком нужен быстрый аплинк и резервирование. Подбираются коммутаторы и сетевое оборудование с L3-возможностями и запасом по скорости.
- ПО. СУБД уровня Postgres Pro, Arenadata для аналитических нагрузок, middleware для балансировки. Всё это работает на реестровом железе.
Отдельно — про ГОСТ/реестр и закупку. Если масштабируетесь под госзаказчика, оборудование должно быть в реестре, иначе конфигурацию нельзя оформить по 44-ФЗ. Подробнее по процессу — в Как перейти на отечественное оборудование.
5. Расчёт нагрузки
Отправная точка — число запросов в секунду и их стоимость. Простая формула бюджета узлов:
N = RPS × t_обслуживания / (1 − запас_на_отказ)
RPS— целевые запросы в секунду (пик, не среднее).t_обслуживания— среднее время обработки одного запроса, сек.запас_на_отказ— резерв, который отдаёте под то, что узел может лечь.
Пример расчёта. Целевые 2000 RPS, средняя обработка 0,05 сек (20 мс), запас на отказ 20%:
N = 2000 × 0,05 / 0,8 = 125 рабочих единиц
Этот результат — идеальная модель без учёта состояния сессии. Считается для web-слоя, где ответ быстрый и узлы «без памяти». Если данные ещё и хранятся, часть узлов превращается в базу данных и директорию хранилища, а часть — в балансирующие приложение.
Практический пример на реальном профиле. Заказчик, ERP на 400 пользователей, пик 600 одновременных сеансов по утрам:
- 80% времени занимают чтения справочников — их выносят на реплики;
- 20% — операции записи, они идут на мастер-узел;
- три балансирующих L7-узла распределяют web-трафик;
- два узла БД в связке «мастер + реплика» закрывают пики записи и чтения.
Подобную конфигурацию под конкретный поток удобно собрать через проектирование ЦОД. Там же — прикидочный поузловой бюджет, чтобы не покупать «три мощных сервера, если хватит двух плюс реплика».
По доступности под пики используйте два ориентира:
- Норма нагрузки. N узлов держат RPS без деградации латентности.
- N 9s. Запас узлов под отказ — из доступности по SLA. Для «четырёх девяток» минимум два узла в каждом критичном слое.
Хранилище при горизонтальном масштабировании считайте отдельно: количество записей в секунду и IOPS, а не только объём. Правило и рабочие числа — в расчёте ёмкости СХД.
5.1 Типовые ошибки
| Ошибка | Причина | Решение |
|---|---|---|
| Балансировать всё, включая записи в БД | Записи плохо шардируются без реплик | Разводить чтения на реплики, записи на мастер |
| Не резервировать балансировщик | Единая точка отказа | Пара балансировщиков с общим виртуальным IP |
| Считать среднюю, а не пиковую нагрузку | Заявленный RPS «средний» | Брать пик за сутки, добавить запас 20–30% |
| Копить лишние узлы «по-максимуму» | Подстраховка без расчёта | Считать реальный прогон под пик, а не кратный |
6. Вопросы и ответы
Когда переходить на горизонтальное масштабирование? — Когда вертикаль дорожает: добавление мощности в один узел перестаёт давать расчётный прирост или упирается в потолок платформы.
Балансировка L4 или L7? — L4 для простых и быстрых сценариев (статика, сокеты), L7 — когда нужно направлять по URL, кукам или раздавать канареечную версию.
Как обойти единую точку отказа в балансировщике? — Развернуть два балансировщика в отказоустойчивой паре (active-passive или active-active) с общим виртуальным IP.
Можно ли горизонтально масштабировать базу? — Да, репликацией для чтений и шардированием для записи. Но это отдельная сложность — её тему лучше разбирать вместе с кэшированием и шардированием.
Частые вопросы
Когда переходить на горизонтальное масштабирование?
Когда вертикаль дорожает: добавление мощности в один узел перестаёт давать расчётный прирост или упирается в потолок платформы.
Балансировка L4 или L7?
L4 для простых и быстрых сценариев (статика, сокеты), L7 — когда нужно направлять по URL, кукам или раздавать канареечную версию.
Как обойти единую точку отказа в балансировщике?
Развернуть два балансировщика в отказоустойчивой паре (active-passive или active-active) с общим виртуальным IP.
Можно ли горизонтально масштабировать базу?
Да, репликацией для чтений и шардированием для записи. Но это отдельная сложность — её тему лучше разбирать вместе с кэшированием и шардированием.