Управление cold start при переходе к бессерверным вычислениям

Традиционный подход к размещению приложения обычно предполагает использование выделенных серверов или виртуальных машин для запуска кода и обслуживания клиентов. Переход к бессерверным вычислениям заставляет нас декомпозировать приложение и изменять его архитектуру. При этом важно на ранней стадии учесть особенности бессерверных вычислений .
Основным компонентом любых бессерверных вычислений является лямбда-функция.

Жизненный цикл лямбда-функции состоит из трех фаз:
  1. фаза инициализации — создается среда выполнения, загружается и инициализируется исходный код;
  2. фаза выполнения — вызывается лямбда-функция;
  3. фаза выключения — неиспользуемое окружение удаляется.
Именно с первой фазой связана такая особенность, как cold start.
Общие правила при создании индекса:
Если во время инициализации нет доступных лямбда-выражений для обработки следующего запроса, то создается новая среда для лямбда-выражения, которая сможет обработать этот запрос.


Время инициализации (или cold start) может занимать довольно много времени, из-за чего запрос выполняется с большой задержкой. Эта проблема особенно актуальна для приложений, где важно время отклика и где часто происходят скачки количества входящих запросов.
Для минимизации воздействия этой проблемы на приложения в Amazon AWS существует несколько подходов.
Использование интерпретируемых языков программирования для написания лямбда-функций

Первый способ — использовать для написания лямбда-функций интерпретируемые языки программирования, такие как Python или NodeJS. В компилируемых языках программирования (таких как Java, C#) инициализация приложения и его старт занимает существенно больше времени. Так что использование интерпретируемых языков в лямбда-функциях в случае cold start позволяет запускать выполнение намного быстрее.
Использование provisioned scaling

Второй способ уменьшить время cold start — использовать специальный тип масштабирования лямбда-функций — provisioned scaling. Так мы снижаем частоту возникновения cold start, не влияя на само время cold start. Provisioned scaling позволяет установить количество экземпляров, сгенерированных лямбда-функциями, которые всегда будут запущены и будут ждать запросов от клиента. Они уже «прогреты», и запрос будет обработан уже готовыми функциями.
Оптимизация лямбда-функций

Третий способ - это, скорее, целая группа способов по оптимизации самих лямбда-функций.


Часть фазы инициализации — это загрузка лямбда-кода.

  • Мы можем оптимизировать объем кода, который будет загружаться по сети. Например, для Java существуют фреймворки и библиотеки, которые позволяют сделать артефакт приложения меньше по объему. Примером такого фреймворка является Quarkus.

  • Мы также можем декомпозировать наше приложение так, чтобы в лямбда-функциях находился только необходимый код и его зависимости. Классический подход java с fat-jar, содержащей несколько сотен мегабайт, здесь является не очень хорошей практикой.

  • Для ускорения мы можем увеличить объем оперативной памяти, доступной лямбда-функции. С этим изменением меняется и вычислительная производительность. Становится доступным больше виртуальных ЦПУ, растет частота ядер. Так, например, vCPU экземпляра лямбды с 128 МБ памяти в 2 раза слабее, чем vCPU экземпляра лямбды с 256 МБ RAM.

Вывод

Мы рассмотрели проблему cold start, почему он возникает и какое влияние может оказать на приложения. Существует множество решений для борьбы с этой проблемой, некоторые из них основаны на уменьшении этой величины в числовом эквиваленте (борьба с размером артефакта и кодовой базы, выбор подходящего языка программирования), а другие помогают минимизировать количество ситуаций, когда cold start будет актуальным (с использованием расширенных правил масштабирования облачного провайдера).