AWS Lambda быстро стал основной рабочей лошадкой вычислительного семейства AWS. Его легко начать, он требует минимального управления и может работать на множестве различных языков (это не всегда подходит, и вы всегда должны немного критически подумать, прежде чем прыгать в него).

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

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

Сегодня я хочу рассмотреть некоторые последствия отсутствия холодного запуска вашего лямбда-выражения.

Для этого я буду использовать AWS SAM local — инструмент, который позволяет запускать лямбда-функции локально.

Каталог проекта состоит всего из двух файлов

Шаблон SAM выглядит так

AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  StateTester:
    Type: "AWS::Serverless::Function"
    Properties:
      Runtime: python3.8
      Handler: lambda_function.lambda_handler
      Events:
        Test:
          Type: Api
          Properties:
            Path: /
            Method: get

И лямбда-функция выглядит так

invocation_count = 0
def lambda_handler(event, context):
  global invocation_count
  invocation_count += 1
  return {'body': "Invocation count: " + str(invocation_count)}

Мы можем запускать эту функцию несколько раз с помощью этой команды

sam local invoke StateTester

Но мы всегда возвращаем количество вызовов, равное 1, потому что SAM local всегда воссоздает лямбда-функцию с нуля.

Далее мы можем попробовать создать API с

sam local start-api

И тогда мы можем использовать API в конечной точке по умолчанию.

127.0.0.1:3000

Но независимо от того, сколько раз мы запрашиваем конечную точку, мы всегда получаем один и тот же результат.

Глядя на вывод консоли, мы видим несколько намеков на то, что AWS SAM local все еще создает и воссоздает лямбда-контейнер каждый раз.

Вот где появляется опция warm-containers в AWS SAM local start-api. Это дает нам возможность сделать так, чтобы sam local поддерживал контейнер посредством вызовов. Получается любой вариант ( eager и lazy дадут нам довольно похожий результат).

Теперь, когда я попадаю в эту конечную точку, количество вызовов увеличивается

Забавный эксперимент — запуск небольшого скрипта powershell.

while($true){Invoke-RestMethod http://127.0.0.1:3000/;}

Пока я писал этот пост в блоге, я получил чуть менее тысячи запросов с одним и тем же контейнером.

Почему вас это должно волновать?

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

Если вы создаете какие-либо соединения с полным состоянием, такие как клиенты AWS, клиенты elasticache и т. д., они могут существовать некоторое время. Вам нужно тщательно продумать, как вы управляете своими пулами соединений, что будет делать ваша лямбда-функция, когда пулы соединений будут исчерпаны, и когда вашей лямбда-функции пора принять решение о выходе самостоятельно.

Например, что, если вы подключаетесь к кластеру Redis и используете узел конфигурации кластера, но затем кластер расширяется или изменяется конфигурация? Если вы только читаете конечную точку конфигурации при инициализации лямбда? Вы можете столкнуться с попыткой запускать запросы к узлам Redis, у которых нет нужного пространства ключей.

Могу ли я просто сделать все в обработчике?

Можно, но тогда вы игнорируете множество советов в посте о том, как оптимизировать время холодного старта.

Вам необходимо учитывать компромиссы между оптимизацией выполнения ваших обработчиков и отсутствием слишком большого количества состояний, которые могут существовать между вызовами.

Удачного строительства!