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, у которых нет нужного пространства ключей.
Могу ли я просто сделать все в обработчике?
Можно, но тогда вы игнорируете множество советов в посте о том, как оптимизировать время холодного старта.
Вам необходимо учитывать компромиссы между оптимизацией выполнения ваших обработчиков и отсутствием слишком большого количества состояний, которые могут существовать между вызовами.
Удачного строительства!