Самый быстрый способ вызвать URL-адрес HTTP/REST из AWS Lambda

Самый быстрый способ вызвать URL-адрес HTTP/REST из AWS Lambda

11 марта 2022 г.

Ответ довольно прост, если вам нужен ответ. Но что, если вы не хотите ждать ответа?


HTTP без ожидания


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


Так как же нам это сделать в NodeJS?


Давайте сначала рассмотрим наивный пример запроса (без обработки ошибок), где мы ждем ответа.


Только для этого примера мы создадим асинхронную функцию узла «запрос», которая возвращает обещание, которое мы можем ждать.


```javascript


константа https = требуется ('https')


постоянный URL = требуется('url')


запрос асинхронной функции (url, данные) {


вернуть новое обещание ((разрешить, отклонить) => {


пусть req = https.request(URL.parse(url), function (res) {


пусть тело = ''


res.on('данные', (фрагмент) => {тело += фрагмент})


res.on('конец', () => { разрешение(тело) })


требуется запись (данные)


запрос.конец()


Тогда наша лямбда будет выглядеть так:


```javascript


exports.handler = асинхронный (событие, контекст) {


let result = await request('https://metric-service.com', metrics)


вернуть результат


Чтобы вызвать наш HTTP-запрос внутри Lambda, мы используем «ожидание», которое выдает запрос, а затем ожидает ответа.


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


В течение этого времени ожидания наша функция Lambda неактивна, но AWS по-прежнему выставляет нам счет за это время. При использовании AWS Lambda вы платите за прошедшее время, а не за использованное процессорное время.


Хотя Lambda необычайно дешев, с большими объемами транзакций, эти короткие ожидания в 950 миллисекунд могут составить значительный счет.


Не ждите


Итак, что произойдет, если мы просто не вызовем «ожидание» и, следовательно, не будем ждать ответа на наш HTTP-запрос?


```javascript


exports.handler = асинхронный (событие, контекст) {


/ подождите / request('https://example.com', метрики)


вернуть «готово»


:::Информация


Странные вещи случаются


Иногда запрос отправляется, а иногда запрос не отправляется.


Иногда запрос поступает агрегатору метрик сразу, а иногда запрос поступает после следующего запуска нашей лямбды. Что происходит?


Замораживание контейнеров Lambda


Функции Lambda выполняются внутри контейнера AWS Firecracker. Когда вы возвращаетесь из функции Lambda, AWS немедленно замораживает контейнер и его глобальное состояние. При следующем вызове Lambda контейнер разморозится для обслуживания нового вызова.


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


Как решить?


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


```javascript


exports.handler = асинхронный (событие, контекст) {


/ подождите / request('https://example.com', метрики)


жду сна(100)


вернуть «готово»


Это вряд ли кажется надежным.


Ожидание передачи запроса


Правильное решение — использовать Node req.end(,,callback) API и дождаться полной отправки запроса, но не ждать получения ответа.


Вот пример:


```javascript


константа https = требуется ('https')


постоянный URL = требуется('url')


запрос асинхронной функции (url, данные) {


вернуть новое обещание ((разрешить, отклонить) => {


пусть запрос = https.request(URL.parse(url))


требуется запись (данные)


req.end(null, null, () => {


/ Запрос полностью отправлен /


разрешить (требуется)


Обратите внимание, что запрос разрешается с помощью обратного вызова end на объекте «req», а не на объекте «res» в предыдущем примере.


Эта модифицированная функция запроса должна вызываться нашей лямбдой с помощью «ожидания». В этом случае мы ждем не ответа HTTP, а полной отправки запроса. Это намного быстрее, чем 750 миллисекунд для получения ответа с нашими показателями, обычно менее 20 миллисекунд.


```javascript


exports.handler = асинхронный (событие, контекст) {


ожидание запроса('https://example.com', метрики)


вернуть «готово»


Альтернативные шаблоны проектирования


Есть много других отличных способов избежать ожидания и блокировки в функциях Lambda, таких как использование функций Step, очередей SQS и прямой вызов функций Lambda как событий без ожидания. Подумайте о наилучшем подходе для вашего приложения, но если вы должны использовать HTTP и вам не нужно ждать ответа, рассмотрите описанный выше метод, чтобы сократить время ожидания и счет за AWS.


SenseDeep


Наша SenseDeep Serverless Developer Studio использует этот метод в Watcher Lambda, который отслеживает ваши Lambda, запускает сигналы тревоги и получает данные журнала. Нам нужно, чтобы Наблюдатель был исключительно быстрым и не ждал никаких запросов REST/HTTP API. Таким образом, Наблюдатель использует этот метод без ожидания при отправке статуса обратно в сервис SenseDeep.


SenseDeep Troubleshooting


Чтобы узнать больше о SenseDeep Serverless Developer Studio и попробовать ее бесплатно, перейдите по ссылке: https://www.sensedeep.com.


Использованная литература


Вот еще несколько полезных материалов об асинхронном программировании Lambda и AWS.









Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE