Пакетирование SQS для лямбда-триггера работает не так, как ожидалось

#amazon-web-services #aws-lambda #amazon-sqs

#amazon-web-services #aws-lambda #amazon-sqs

Вопрос:

У меня есть 2 лямбда-функции и промежуточная очередь SQS. Первый лямбда-код отправляет сообщения в очередь. Затем второй лямбда-код имеет триггер для этой очереди с размером пакета 250 и окном пакета 65 секунд.

Я ожидаю, что второй лямбда-код будет запускаться партиями по 250 сообщений примерно каждые 65 секунд. Во втором Lambda я вызываю сторонний API, который ограничен 250 вызовами API в минуту (я получаю 250 токенов в минуту).

Я протестировал эту настройку с добавлением в очередь 32.000 сообщений, а вторая лямбда не собирала сообщения в пакетах, как ожидалось. Сначала он был выполнен для 15 тысяч сообщений, а затем не хватило токенов, поэтому он не обрабатывал эти сообщения.

Сторонний API основан на корзине токенов со скоростью заполнения 250 в минуту и максимальной емкостью 15 000. Ему удалось обработать первые 15 000 сообщений из-за емкости корзины, а затем не хватило емкости для обработки остальных.

Я не понимаю, что пошло не так.

введите описание изображения здесь

Комментарии:

1. Правильно ли я понимаю, что после добавления 32 тыс. сообщений в очередь SQS ваша лямбда-функция была выполнена с 15 тыс. сообщений (в одном пакете?) Вместо 250? И какова общая емкость корзины ? Это в час или общее количество токенов, которые вы когда-либо сможете использовать?

2. Чтобы уточнить: 15 Тыс. сообщений не были обработаны за один вызов Lambda, верно? Должно было быть около 60, и, согласно документам, максимальный размер пакета для стандартных SQS составляет 10 тыс.

3. Вы проверили свои Concurrent executions и Invocations метрики для своего лямбда?

4. @Marcin 41 Вызовы и параллельные выполнения 143 .

5. Да, я думаю, это подтверждает ответ @Maurice. Ваши функции выполняются параллельно, а не последовательно.

Ответ №1:

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

Вероятно, произошло то, что Lambda увидела, что в очереди есть куча сообщений, и пытается работать с ними как можно быстрее. Он создал экземпляр Lambda для обработки первого события, а затем связался с SQS и попросил дополнительной работы. Когда он получил следующий пакет сообщений, первый экземпляр все еще был занят, поэтому он масштабировался и создал второй, который параллельно работал со вторым пакетом и т.д. и т.п.

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

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

Однако это открывает вам другую проблему. Если для обработки сообщений одному лямбде требуется менее 60 секунд, Lambda вызовет его снова с другим пакетом как можно скорее, и вы можете снова превысить свой бюджет.

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

Комментарии:

1. Привет. Просто интересно, есть ли что-нибудь лучше, чем спать в течение 60 секунд? В конечном итоге вы заплатите за это время простоя. Может быть, есть способ избежать этого?

2. «Если для обработки сообщений этой единственной лямбде требуется менее 60 секунд, Lambda вызовет ее снова с другим пакетом как можно скорее, и вы можете снова превысить свой бюджет»., но поскольку я определил окно пакетной обработки, не следует ли ему выбрать следующий пакет через 60 секунд, даже если он обработал предыдущийпакет менее чем за 60 секунд?

3. @Marcin — Я думал об этом, но не смог придумать лучшего решения. При постоянной загрузке очереди определенно будет дешевле запускать контейнер fargate, чем lambda. При спорадической загрузке это может быть более экономичным.

4. @nats Это не так, как это работает. Он ожидает либо в течение настроенных 65 секунд, либо до тех пор, пока не будут доступны 250 сообщений, в зависимости от того, что произойдет раньше. Если в очереди ожидают более 250 сообщений, нет гарантии, что он будет вызываться только каждые 60 секунд.

5. О, хорошо! Таким образом, это означает, что какое бы условие ни стало истинным, оно будет вызвано снова.