Вызов асинхронных внешних API с помощью AWS Step Functions

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

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

Организации должны быть уверены в том, что их системы способны справляться с проблемами производительности и простоев. В некоторых случаях вызов внешнего API может быть связан с дополнительными расходами, такими как плата за лицензию. Если с поставщиком внешнего API заключен контракт о соблюдении максимального RPS (количества запросов в секунду), система должна соответствующим образом адаптироваться.

В этой посте мы покажем вам, как будет выглядеть архитектура для вызова внешнего API с помощью AWS Step Functions, с упором на надежность.

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

Обзор

В этом решении используются вервисы AWS для вызова сторонних сервисов, и обработки асинхронных вызовов для длительных задач. Эта архитектура также доступна в разделе AWS Reference Architecture Diagrams в AWS Architecture Center.

Как показано на Рисунке 1, данная архитектура позволяет ограничивать вызовы внешнего сервиса в соответствии с требуемым максимальным RPS, используя возможности Step Functions. Step Functions тормозит основной процесс до получения колбека от внешней системы.

Рисунок 1. Асинхронный вызов внешнего API
Рисунок 1. Асинхронный вызов внешнего API

Давайте рассмотрим каждый шаг по отдельности:

  1. Step Functions настроен для обработки длительных запросов к стороннему API. Внутри рабочего процесса добавлен шаг, который приостанавливает его, используя waitForTaskToken в качестве колбека. Установлен тайм-аут, чтобы выбрасывать ошибку, если ответ не был получен.

  2. Task token и тело запроса отправляются в Amazon SQS (очередь Amazon Simple Queue Service). Amazon CloudWatch используется для мониторинга длины этой очереди. Должна быть реализована возможность изменения контракта со сторонним сервисом, если длина очереди превышает предел, определенный максимальным RPS к сторонней системе.

  3. На сообщение в SQS как на триггер срабатывает функция Lambda, запускающая requestor Step Functions (Express Workflows). Частотой вызовов можно управлять, используя размер пакета (batch) запросов, параллелизм и масштабирование лямбд (reserved and maximum concurrency), описанные более подробно далее.

  4. При необходимости можно добавить динамическую задержку внутри лямбды, которая будет настраиваться через AWS AppConfig, если вам нужна более низкая частота вызовов, чтобы соответствовать требуемому RPS.

  5. Step Functions вызывает Amazon API Gateway, выступающий в качестве http-прокси и позволяющий ограничить количество запросов до заданного RPS. Это дополнительная защита, важная при динамической настройке частоты запросов.

  6. Внешний API вызывается асинхронно, отправив данные из очереди и получив идентификатор (job ID) от внешнего сервиса. Неудачные запросы отправляются SQS в DLQ (Dead Letter Queue)

  7. Task token и job ID основного процесса сохраняются в таблице DynamoDB. Job ID используется для сопоставления запроса и ответа. Task token - для возобновления процесса, из которого был сделан запрос.

  8. После выполнения работы внешний сервис отправляет job ID через callback webhook endpoint (без перевода будет лучше - прим. пер.), реализованный с помощью API Gateway.

  9. Полученные данные преобразуются в API Gateway, помещаются в SQS, и генерируется ответ внешней системе.

  10. Лямбда забирает полученный ответ из SQS, затем извлекает сохраненный task token по job ID. Он нужен, чтобы разблокировать ожидающий рабочий процесс, вызвав SendTaskSuccess. Неудавшиеся сообщения отправляются в DLQ.

  11. В основном процессе передается job ID на следующий шаг и вызывается Step Functions для обработки ответа внешнего сервиса.

Управление частотой вызовов

Чтобы соответствовать лимитам по RPS, необходимо иметь механизм для ограничения частоты вызовов. Частота опроса сообщений из SQS (шаг 3) напрямую влияет на частоту вызовов.

Для управления частотой вызовов лямбды с SQS в качестве источника можно использовать различные параметры, такие как:

  1. Batch size: количество записей, отправляемых в функцию за раз. Для стандартной очереди это может быть до 10 000 записей. Для очереди FIFO (first-in, first-out) максимальное количество записей - 10. Использование только batch size не ограничит частоту вызовов. Его следует использовать в сочетании с другими параметрами, такими как reserved concurrency и maximum concurrency.

  2. Batch window: максимальное время, в течение которого происходит сбор записей перед вызовом лямбды, в секундах. Применим только к стандартным очередям.

  3. Maximum concurrency: устанавливает ограничения на количество одновременных экземпляров лямбды, которые могут вызываться с помощью SQS. Устанавливается на уровне источника событий.

Конфигурация этих параметров показана на Рисунке 2:

Рисунок 2
Рисунок 2

Другие параметры, которые также могут также использоваться:

  1. Reserved concurrency: гарантирует максимальное количество параллельных экземпляров лямбды. Когда lambda имеет зарезервированный пул, другие не могут использовать этот резерв. Также может быть использован для ограничения и частоты вызовов.

  2. Provisioned concurrency: создает определенное количество сред исполнения, чтобы они были готовы мгновенно использоваться при вызове вашей лямбды. Обратите внимание, что использование этого параметра влечет за собой расходы для вашей учетной записи AWS.

Дополнительные параметры показаны на Рисунке 3:

Рисунок 3
Рисунок 3

Развитие вашей архитектуры

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

Рассмотрим некоторые примеры:

  • Если внешний API не отвечает на запрос на шаге 8, возникнет тайм-аут на шаге 1. Разумный тайм-аут должен быть настроен в основной Step Functions на шаге 1. Значение этого тайм-аута должно учитывать максимальное время ответа.

    • В разделе Error handling in Step Functions описывается, как реализовать логику для различных типов ошибок. Ошибки тайм-аута настраиваются с помощью States.Timeout.

  • Динамическая задержка внутри лямбды, как упоминалось на шаге 4, должна использоваться только для пиков трафика. Если у внешней стороны очень низкий лимит RPS, рассмотрите другие альтернативы для введения задержки.

    • Например, можно использовать планировщик Amazon EventBridge Scheduler, чтобы запускать лямбду с регулярными интервалами для обработки сообщений из Amazon SQS. Это позволяет избежать затрат на простой/ожидание ваших лямбд.

Заключение

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

Мы также рассмотрели примеры обработки ошибок в Step Functions и мониторинга с помощью CloudWatch. Кроме того, данная архитектура полностью serverless, что позволяет избавиться от рутинной работы при создании высокодоступных, надежных, безопасных и экономически эффективных систем на AWS.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Интересна ли тема AWS Serverless
100% Да 1
0% Да, но не переводы 0
0% Нет 0
0% Первый раз слышу, картинка пугает 0
Проголосовал 1 пользователь. Воздержавшихся нет.
Источник: https://habr.com/ru/articles/727354/


Интересные статьи

Интересные статьи

Кризисное время всегда способствует переменам, в том числе в поиске новой профессии или приобретении опыта. Вот почему мы решили запустить рубрику Next Step о сотрудниках Х5 Tech, которые смогли помен...
Event storming — метод, который смещает акцент у событий с технического на организационный и бизнес уровни и помогает создать устойчивую модульную систему. Он нередко исп...
Кто бы что ни говорил, но я считаю, что изобретение велосипедов — штука полезная. Использование готовых библиотек и фреймворков, конечно, хорошо, но порой стоит их отложить и создать ...
В первой части статьи мы рассмотрели основы работы с утилитой SIP, предназначенной для создания Python-обвязок (Python bindings) для библиотек, написанных на языках C и C++. Мы рассмотрели основн...
Процедурные макросы в Rust — это очень мощный инструмент кодогенерации, позволяющий обходиться без написания тонны шаблонного кода, или выражать какие-то новые концепции, как сделали, к примеру, ...