...
Back

Холодные старты — это ценовое решение, а не баг производительности

Масштабирование до нуля — это не свойство вашей платформы. Это регулятор, и если оставить его в положении по умолчанию, значит, кто-то другой решил, сколько будет стоить ваш самый медленный запрос.

Холодные старты — это ценовое решение, а не баг производительности

Холодные старты — это вопрос цены ❄️

В процессе любой миграции на serverless-архитектуру наступает момент, когда вы тратите полдня, пытаясь ускорить первый запрос. Обрезать образ. Реализовать ленивую загрузку тяжёлого модуля. Вынести клиент базы данных за пределы области видимости модуля. Всё это — реальная работа, приносящая реальную пользу, но она оптимизирует не ту переменную.

Первый запрос медленный, потому что до него ничего не было запущено. Это не баг производительности. Это поведение, на которое вы согласились, выбрав scale-to-zero. И у него есть цена, которую можно просто заплатить.


Чем вы на самом деле жертвуете

Scale-to-zero означает: когда сервисом никто не пользуется, он ничего не стоит, а тот, кто его «будит», платит за запуск.

Для многих видов нагрузки это действительно хороший компромисс. Внутренние инструменты. Стейджинг. Вебхук, который срабатывает девять раз в день. Всё, где пользователи — это вы сами, или где двухсекундный первый ответ незаметен, потому что запрос выполняется в фоне.

Но это плохой компромисс для главной страницы продукта. Не потому, что две секунды — это невыносимо, а из-за того, кто за это платит. Холодный старт с непропорционально высокой вероятностью достаётся новому посетителю, пришедшему по ссылке — тому самому трафику, на привлечение которого вы потратили больше всего и который оценивает вас, имея минимум информации. Цена реальна, и платить её приходится в самом неподходящем месте.


Сначала посчитайте, потом оптимизируйте

Полезнее не ускорять запуск, а выяснить, сколько на самом деле стоит держать один инстанс «прогретым». Эта цифра часто оказывается до смешного мала по сравнению с усилиями на оптимизацию.

Грубо говоря:

warm baseline ≈ (instance memory × instance count) × hourly rate × 730

Для небольшого сервиса с одним постоянно прогретым инстансом эта сумма часто составляет единицы долларов в месяц. Сравните это с теми часами, которые вы собирались потратить на реструктуризацию импортов в модулях, — и с посетителями, которые просто закроют вкладку.

Причина, по которой эти расчёты пропускают, в том, что min instances = 0 — это значение по умолчанию, а умолчания не ощущаются как принятые решения. Но это именно решение, и его принял за вас тот, кто написал шаблон.


Когда оптимизировать холодный старт всё-таки стоит

Плата за «прогрев» не устраняет холодные старты, а лишь делает их реже. Скачки трафика всё равно приводят к запуску новых инстансов, и эти инстансы по-прежнему стартуют «холодными». Так что путь запуска заслуживает внимания — просто не панического.

Изменения, которые дают наибольший эффект, по порядку:

  1. Не подключайтесь ни к чему на уровне модуля. Клиент базы данных или кеша, создаваемый во время импорта, заставляет каждый холодный старт ждать хендшейка. В том числе и те старты, что происходят во время скачка нагрузки, когда зависимость и так работает на пределе.
  2. Поставляйте образ меньшего размера. Время скачивания образа — это часть времени запуска. Здесь многоэтапные сборки и урезанные форматы вывода окупают себя дважды: сначала в стоимости хранения в registry, затем — в задержке.
  3. Отложите импорт тяжёлых зависимостей до того роута, где они действительно нужны. Если один редко используемый эндпоинт тянет за собой огромную зависимость, за это платит каждый холодный старт.
  4. Настраивайте concurrency осознанно. Количество одновременных запросов, которые обрабатывает один инстанс, определяет, как часто вы будете запускать новый. Слишком низкое значение — и вы постоянно получаете холодные старты при умеренной нагрузке; слишком высокое — и один медленный запрос блокирует соседние.

Заметьте, что ни один из этих способов не сводит проблему к нулю. Они лишь укорачивают «хвост» распределения. А вот настройка прогрева убирает проблему для типичных случаев.


Какой вывод стоит сделать

Настройки инфраструктуры по умолчанию — это мнения, к которым прилагается счёт. Scale-to-zero, concurrency запросов, лимиты инстансов, хранение логов — всё это «ручки», для которых кто-то выбрал разумное для кого-то значение, и ни одна из них не заявляет о себе как о выборе, который вы можете сделать.

Полезная привычка проста: для каждой унаследованной вами настройки по умолчанию умейте в одном предложении сказать, чего она вам стоит и чего будет стоить её изменить. Не для того, чтобы менять их все. А просто чтобы знать. И чтобы в следующий раз, когда медленный первый запрос подтолкнёт вас к многочасовой перекройке модулей, вы могли проверить, не решается ли проблема одной строкой в конфиге и пятью долларами.