Блог Amazon Web Services
Эксплуатация Lambda: дизайн приложений и лимиты сервиса – часть 1
Оригинал статьи: ссылка (James Beswick, Senior Developer Advocate)
В серии из трёх постов «Эксплуатация Lambda» я раскрою важные темы для разработчиков, архитекторов и системных администраторов, которые управляют и обслуживают AWS Lambda-приложения.
Хорошо спроектированное приложение на основе событий использует комбинацию из сервисов AWS и пользовательского кода для обработки и управления запросами и данными. Данная серия фокусируется на Lambda-специфичных аспектах при проектировании приложений, и на том, как Lambda взаимодействует с другими сервисами. Существует множество важных нюансов для архитекторов бессерверных решений, особенно при проектировании нагруженных систем, находящихся в промышленной эксплуатации.
Первая часть показывает, как работать с лимитами сервиса (Service Quotas), когда запрашивать их расширение, и как проектировать приложения с учётом этих лимитов. Также я расскажу, как управлять трафиком для нижестоящих в потоке обработки ресурсов.
Понимание лимитов сервиса
Сервис Lambda спроектирован для выполнения короткоживущих задач, которые не сохраняют состояние обработки между вызовами функции и не полагаются на него. Lambda вызывает пользовательский код в ответ на событие из другого сервиса AWS или запрос через AWS CLI или AWS SDK. Функция может выполняться до 15 минут для каждого вызова и использовать до 10 240 MB памяти.
Lambda спроектирована для быстрой масштабируемости с целью удовлетворения спроса вызывающей стороны, что позволяет функции масштабироваться для обслуживания возросшего трафика в ваших приложениях. Другие сервисы AWS, часто используемые в бессерверных приложениях, такие как Amazon API Gateway, Amazon SNS и AWS Step Functions, также могут масштабироваться в ответ на возросшую нагрузку. Это позволяет нашим крупнейшим клиентам создавать приложения, которые могут масштабироваться для обработки миллионов запросов без необходимости самостоятельного управления инфраструктурой.
В то же время, перед тем, как вы начнёте масштабировать приложения для таких нагрузок, необходимо разобраться, как работают встроенные ограничения сервиса, созданные для защиты вашего аккаунта AWS и рабочих нагрузок других клиентов. Сервисные лимиты существуют для всех сервисов AWS и состоят из лимитов двух типов: «жёсткие» лимиты – менять нельзя, и «мягкие» лимиты, для которых можно запросить расширения.
По умолчанию, новым аккаунтам назначен профиль лимитов, предназначенный для ознакомления с сервисами AWS. И, конечно, для рабочих нагрузок среднего или большого размера, может потребоваться увеличение данных лимитов. Обычно наши клиенты создают запросы на увеличение лимитов по мере роста использования ресурсов в рамках своих приложений. Это позволяет лимитам расширяться вместе с растущим профилем использования сервисов и помогает защитить аккаунт от лишних трат, вызванных непреднамеренным использованием сервисов.
Разные сервисы AWS имеют разные лимиты. Данные лимиты могут применяться на региональном уровне или на уровне аккаунта, и могут включать интервальные ограничения, такие как количество запросов в секунду. Например, максимальное количество IAM ролей – это лимит на уровне аккаунта, тогда как максимальное количества одновременных запусков Lambda-функций – это региональный уровень лимитов.
Чтобы узнать лимиты для вашего аккаунта, перейдите в Панель управления сервисными лимитами. Она позволяет посмотреть текущие сервисные лимиты, запросить их увеличение, и узнать текущий уровень использования в рамках лимитов. Отсюда вы можете перейти на более детальный уровень по конкретному сервису AWS, такому как Lambda:
В примере выше, отсортированном по колонке Adjustable, мы видим, что лимиты Concurrent executions, Elastic network interfaces per VPC и Function and layer storage доступны для изменений. Вы можете запросить расширение лимитов для всех них с помощью Центра поддержки AWS. Остальные элементы являются полезным справочником о других лимитах, применённых к сервису.
Проектирование в соответствии с сервисными лимитами
Большинство бессерверных приложений используют несколько сервисов AWS, и разные сервисы имеют разные лимиты для разного функционала. Как только вы спроектировали архитектуру на основе бессерверных сервисов и знаете, какие сервисы используются в приложении, вы можете сопоставить лимиты между ними, чтобы идентифицировать возможные проблемы.
В данном примере API Gateway имеет лимит тротлинга по-умолчанию в 10 000 запросов в секунду. Многие приложения используют конечные точки API Gateway для вызова Lambda-функций. Lambda имеет лимит по умолчанию на количество одновременных запусков, равный 1 000. Так как API Gateway вызывает Lambda в синхронном режиме, при настройках лимитов по умолчанию существует вероятность превышения лимитов Lambda из-за большого количества входящих запросов от API Gateway, которые Lambda должна обработать одновременно. Эту ситуацию можно исправить, запросив увеличение лимита на количество одновременных запусков Lambda в рамках аккаунта в соответствии с ожидаемым объёмом нагрузки.
Другой сложной задачей является обработка полезной нагрузки с учётом её размера в разных сервисах. Представьте приложение, которое получает полезную нагрузку от API Gateway к Lambda и затем передаёт в Amazon SQS. API Gateway поддерживает размер полезной нагрузки до 10 Mb, тогда как ограничение Lambda – 6 Mb, а максимальный размер сообщения SQS – 256 Kb. В этом примере вы можете сохранить вашу полезную нагрузку в бакете Amazon S3, вместо того чтобы загружать её напрямую в API Gateway, и передавать ссылку на объект между сервисами. Размер ссылки на объект гораздо меньше любого из лимитов перечисленных сервисов и может быть более элегантным архитектурным решением, но это, конечно же, зависит от вашего конкретного сценария.
Нагрузочное тестирование бессерверных приложений также позволяет проверить производительность вашего приложения перед использованием в промышленной эксплуатации. Бессерверные приложения могут быть нагружены в рамках тестирования гораздо проще благодаря механизмам авто-масштабирования, встроенным в большинство этих сервисов. Во время нагрузочного тестирования вы можете определить любые лимиты, которые могут быть ограничивающим фактором для масштабируемости приложения, исходя из требований по нагрузке, и запросить их расширение.
Существует несколько готовых инструментов, которыми могут воспользоваться разработчики бессерверных приложений для выполнения данной задачи. Один из самых популярных – Artillery Community Edition, инструмент с открытым исходным кодом для тестирования бессерверных API. Вы можете настроить количество запросов в секунду и общее время работы теста. Для запуска этих тестов он использует версию браузера Chromium без пользовательского интерфейса. Другaя утилита – это Gatling.
Использование нескольких аккаунтов AWS для управления лимитами
Многие клиенты запускают несколько рабочих нагрузок в облаке AWS, но при этом многие лимиты устанавливаются на уровне аккаунта AWS. Это значит, что при добавлении новых бессерверных рабочих нагрузок некоторые лимиты будут распределены на большее количество приложений, тем самым уменьшая доступные лимиты для каждого из них. Более того, если вы запускаете нагрузки, связанные с разработкой и тестированием в том же аккаунте, что и промышленные нагрузки – лимиты будут распределены на них всех. Также может случиться ситуация, при которой задачи разработки и тестирования могут неумышленно поглотить все доступные ресурсы в аккаунте, которые предполагались для промышленной эксплуатации.
Правильным подходом для решения данной ситуации будет использование нескольких аккаунтов AWS и распределение рабочих нагрузок по их выделенным аккаунтам. Это позволит избежать распределения лимитов между промышленными и тестовыми нагрузками. Используя AWS Organizations, вы можете управлять выставлением счетов, устанавливать механизмы безопасности, требования аудита и правила совместного использования ресурсов между аккаунтами вашей организации. Вы можете назначать политики на группы аккаунтов для избавления от ручного администрирования и написания пользовательских скриптов управления аккаунтами.
Одним из стандартных подходов является выделение отдельного аккаунта каждому инженеру разработки и создание выделенных аккаунтов как для тестовой, так и для промышленной среды:
Аккаунты для разработки могут содержать копии необходимых ресурсов из промышленной среды, при этом обеспечивая необходимый повышенный уровень доступа к этим ресурсам в рамках аккаунта. Каждый разработчик имеет свои лимиты в рамках своего аккаунта, таким образом они не будут влиять на ресурсы в аккаунте для промышленной среды. Разработчики могут разворачивать стеки AWS CloudFormation и шаблоны AWS Serverless Application Model (AWS SAM) в своих аккаунтах с минимальными рисками для ресурсов, находящихся в промышленной эксплуатации.
Данный подход позволяет разработчикам тестировать Lambda-функции локально на выделенных для разработки средах, при этом взаимодействуя с облачными ресурсами в их аккаунтах AWS. Это может помочь создать надёжный процесс модульного тестирования, по результатам которого разработчики могут отправлять код в Git-репозиторий, такой как AWS CodeCommit, когда посчитают нужным.
С помощью интеграции с AWS Secrets Manager вы можете хранить различные наборы ключей доступа для каждого из окружений и избавиться от необходимости сохранять их в коде приложения. По мере развёртывания приложения из аккаунта разработки в тестовый аккаунт и затем в аккаунт промышленной эксплуатации, соответствующие правильные ключи доступа будут применены автоматически. При этом вам не нужно предоставлять права к ключам доступа для каждой из сред каждому из разработчиков.
Для дополнительной информации читайте “Best practices for organizing larger serverless applications”.
Управление потоком трафика для серверных ресурсов
В то время как Lambda может быстро масштабироваться в ответ на возрастающую нагрузку, многие не-бессерверные сервисы – не могут. Если Lambda-функция взаимодействует с такими сервисами, существует вероятность перегрузить данные нижестоящие сервисы потоком данных или количеством соединений.
Amazon RDS – это один из типичных сервисов, используемых в Lambda, когда ей нужны серверные ресурсы. При этом реляционные базы данных построены на базе входящих соединений и предполагают использование небольшого количества долгоживущих соединений от клиентов, таких как веб-сервер. Это противоречит дизайну Lambda, в которой функции временные, короткоживущие, и их соединения с базой данных короткие, при этом их большое количество – от каждой из запущенных Lambda-функций. Если Lambda будет масштабироваться в сотни или тысячи экземпляров, это может перегрузить базу данных по количеству одновременных соединений. Обычно такая проблема может возникнуть для достаточно нагруженных приложений. Если вы используете Lambda для небольшого количества задач, таких как ежедневный запуск обрабоки SQL-отчётов, вы не столкнётесь с данной проблемой.
Сервис Amazon RDS Proxy был разработан для решения сценария с большим количеством входящих соединений с базой данных. Он объединяет (pool) соединения между сервисом Lambda и базой данных Amazon RDS. Это значит, что при увеличении количества экземпляров, Lambda функция сможет переиспользовать существующие соединения с базой данных с помощью Amazon RDS Proxy. Как итог, база данных не будет перегружена из-за многочисленных отдельных запросов от экземпляров Lambda-функций. И в большинстве случаев это не требует изменений в коде функции. Нужно только заменить в параметрах Lambda-функции конечную точку базы данных на конечную точку прокси-сервиса.
Для других серверных ресурсов, API или сторонних сервисов, используемых в Lambda, важно знать лимиты на количество соединений, транзакций или обмен данными. Если бессерверные приложения имеют возможность превысить какие-то из этих лимитов, используйте очередь SQS для разъединения Lambda-функции от конечного ресурса. Это позволит серверным ресурсам обрабатывать сообщения из очереди с постоянной скоростью. Очередь также гарантированно сохраняет запросы, что помогает в ситуациях, когда нижестоящие серверные ресурсы недоступны.
Выводы
Lambda работает с другими сервисами AWS для обработки и управления запросами и данными. Наш пост описывает, как интерпретировать и управлять сервисными лимитами, когда нужно расширять лимиты, и как проектировать приложения с учётом этих лимитов. Также мы рассмотрели, как управлять потоками трафика для нижестоящих серверных ресурсов.
Во второй части мы обсудим масштабирование и параллелизм Lambda-функций и различное поведение для режимов Lambda: параллелизм по запросу или пре-аллоцированный параллелизм (Provisioned Concurrency).
Для дополнительной информации, смотрите Operating Lambda: Understanding event-driven architectures series.