Prowid Photos попала в подборку популярного блога. В пятницу вечером нагрузка выросла в десять раз: вместо привычных 350 RPS в пике — 3 500. Единственный сервер упёрся в 100% CPU, страницы открываются по восемь секунд, а потом начинаются ошибки 502. Что делать? Есть два пути: сделать сервер мощнее или добавить ещё серверов. От выбора зависит не только счёт за хостинг, но и то, как нужно писать приложение. В этом уроке разберём пределы одного сервера, вертикальное и горизонтальное масштабирование, главное требование к коду — stateless — и автомасштабирование.

Один сервер и его пределы

Любой сервер упирается в один из ресурсов: CPU, оперативную память, диск, сеть или число соединений с базой данных. Процесс Node.js выполняет JavaScript в одном потоке, поэтому один процесс использует одно ядро процессора (как задействовать все ядра — в уроке «Масштабирование: модуль cluster и stateless-приложения»).

Опасность в том, что сервер ломается не постепенно. Упрощённая модель очереди говорит: время ответа ≈ время обработки ÷ (1 − загрузка). При загрузке 50% запрос тратит вдвое больше времени, чем на пустом сервере, при 80% — в 5 раз, при 90% — в 10, при 95% — в 20. Реальные цифры отличаются, но «хоккейная клюшка» настоящая: поэтому серверы не грузят выше 60–70%.

Один сервер перегружается, большой сервер упирается в потолок, много серверов за балансировщиком
Один сервер перегружается, большой сервер упирается в потолок, много серверов за балансировщиком

💡 Прежде чем масштабировать, измерьте и найдите узкое место (top, docker stats, метрики). Часто дешевле добавить индекс в базе данных или кеш, чем покупать сервер.

Вертикальное и горизонтальное масштабирование

Вертикальное (scale up) — сделать один сервер мощнее: больше ядер, памяти, быстрее диск. Просто, и код менять не нужно. Но у метода есть потолок: самая большая машина у облака ограничена (сотни ядер и терабайты памяти), а цена растёт быстрее мощности. К тому же сервер остаётся один — упал он, упал весь сайт, — а при смене размера машину обычно перезапускают.

Горизонтальное (scale out) — поставить рядом ещё серверы и распределять запросы между ними (балансировщику посвящён следующий урок). Потолка почти нет, потеря одного сервера не катастрофа, наращивать можно понемногу. Цена — сложность: нужны балансировщик, аккуратный деплой, мониторинг, а приложение обязано быть stateless.

Вертикально (scale up)Горизонтально (scale out)
Что делаемодин сервер мощнеебольше серверов
Потолокесть: самая большая машинапочти нет
Отказ сервералежит всёостальные продолжают работать
Код приложенияне меняетсядолжен быть stateless
Сложностьнизкаявыше: балансировщик, деплой, состояние

Разумный порядок такой: измерить и оптимизировать, затем вырасти вертикально (самый простой шаг), но писать код так, чтобы его можно было размножить. Сколько экземпляров нужно? Берём пик, делим на нагрузку, которую безопасно дать одному экземпляру (≈ 70% от измеренного максимума), и прибавляем один запасной — экземпляры нужны не только для мощности, но и чтобы пережить падение одного из них (помните: два сервера по 99% дают 99,99%):