Горизонтальное и вертикальное масштабирование приложения
Основы3 минРедакция Innovialabs
Коротко
Вертикальное масштабирование — это более мощный сервер, горизонтальное — больше серверов за балансировщиком. Начинать проще с вертикального, но для роста и отказоустойчивости приложение нужно сделать stateless и готовым к горизонтальному.
Коротко: в чём разница
Вертикальное масштабирование (scale up) — вы увеличиваете ресурсы одного сервера: больше CPU, памяти, быстрее диск. Код менять не нужно.
Горизонтальное масштабирование (scale out) — вы запускаете несколько копий приложения на разных серверах и распределяете между ними трафик через балансировщик нагрузки. Это требует подготовки архитектуры, но почти не имеет потолка и даёт отказоустойчивость.
Сравнение подходов
| Критерий | Вертикальное | Горизонтальное |
|---|---|---|
| Изменения в коде | Не нужны | Нужны: stateless, общие сессии |
| Потолок | Самый мощный доступный сервер | Практически нет |
| Отказоустойчивость | Одна точка отказа | Падение одного узла не критично |
| Простой при росте | Часто нужен перезапуск | Узлы добавляются без остановки |
| Сложность эксплуатации | Низкая | Выше: балансировщик, мониторинг узлов |
| Стоимость | Мощное железо дорожает непропорционально | Много недорогих узлов, но больше обслуживания |
Пределы вертикального масштабирования
- Физический потолок. Рано или поздно более мощного сервера просто нет или он стоит несоразмерно дорого.
- Одна точка отказа. Сервер упал — упало всё.
- Простой при апгрейде. Смена тарифа или железа обычно означает перезагрузку.
- Не все задачи ускоряются. Если приложение упирается в однопоточный код или блокировки в базе, дополнительные ядра мало помогут.
При этом вертикальный путь — разумный старт: он быстрый, дешёвый в поддержке и закрывает рост большинства небольших проектов.
Что делает приложение горизонтально масштабируемым
Главное правило: любой экземпляр приложения должен уметь обработать любой запрос. Для этого:
- Stateless-сервис. Не храните состояние пользователя в памяти процесса.
- Общие сессии. Сессии — в Redis, базе или в подписанных токенах (например, JWT), а не в памяти конкретного сервера.
- Файлы — во внешнем хранилище. Загрузки пользователей кладите в объектное хранилище (S3-совместимое), а не на локальный диск.
- Фоновые задачи — через очередь. Cron на каждом узле запустит задачу N раз; используйте очередь или распределённую блокировку.
- Кэш — общий. Локальный кэш у каждого узла приводит к рассинхрону данных.
- Health check. Балансировщик должен знать, какой узел жив, через эндпоинт вроде
/health.
Пример простой балансировки в nginx:
upstream app {
server 10.0.0.11:3000;
server 10.0.0.12:3000;
}
server {
listen 80;
location / {
proxy_pass http://app;
}
}
А что с базой данных
Приложение масштабируется горизонтально легко, база — сложнее. Обычный порядок шагов:
- Вертикально увеличить сервер БД и оптимизировать запросы и индексы.
- Вынести чтение на реплики (read replicas).
- Добавить кэширование горячих данных.
- Только при реальной необходимости — шардирование, это заметно усложняет систему.
Когда переходить на горизонтальное
- Нагрузка регулярно упирается в лимиты одного сервера, а следующий тариф непропорционально дороже.
- Простой недопустим, и нужна отказоустойчивость.
- Трафик сильно колеблется, и выгодно добавлять узлы по требованию (автомасштабирование).
- Нужно обновлять приложение без остановки (rolling deploy).
Частые ошибки
- Масштабировать горизонтально, не убрав состояние из памяти, — пользователи «вылетают» из аккаунта.
- Добавлять серверы, когда узкое место — медленные запросы к базе.
- Не настроить мониторинг и не понимать, что именно упирается: CPU, память, диск или сеть.