У нас есть некоторые лямбды, запускаемые очередями SQS. Лямбды выполняют интенсивную вставку в таблицы DynamoDB. Таблицы DynamoDB имеют возможность автомасштабирования записи.
При пиковых нагрузках в Lambdas приходит большое количество сообщений, и они начинают отказывать с ProvisionedThroughputExceededException. DynamoDB требуется несколько минут для масштабирования.
Мы ожидаем, что при сбое Lambda сообщения вернутся обратно в SQS и будут снова обработаны после тайм-аута видимости. Это выглядит правильным, потому что позже DynamoDB будет увеличен и сможет обрабатывать возросшие записи.
Однако мы видим странную вещь. Когда количество ошибок выполнения для Lambda растет, триггер SQS автоматически отключается. Лямбда останавливает выполнение, сообщения накапливаются в очереди.
Ручное включение триггера приводит к еще большему количеству сбоев, потому что DynamoDB все еще не масштабируется, но количество сообщений для обработки из очереди резко увеличилось.
Помогает только увеличение емкости записи DynamoDB вручную.
Почему отключается триггер SQS? Такое поведение не задокументировано.
Как избежать отключения триггера?
В общем, каков рекомендуемый способ сделать "обратное давление", чтобы ограничить скорость опроса сообщений из SQS с помощью лямбда-выражения?
Я не уверен, почему перестает работать Лямбда. Я подозреваю, что служба Lambda замечает, что она продолжает давать сбой, поэтому временно приостанавливает ее. Точно сказать не могу.
Вы можете попробовать несколько обходных путей:
Что-то в этом роде могло бы помочь :)
Служба поддержки AWS сообщает, что триггер может быть отключен из-за недостаточных разрешений для роли выполнения Lambda.
Мой вопрос:
Где документируются условия автоматического отключения лямбда-триггера? Или где узнать, почему отключился триггер (какие-то логи службы Lambda)?
Ответ службы поддержки AWS:
В настоящее время нет такой общедоступной документации, в которой упоминаются возможные причины автоматического отключения лямбда-триггера. Однако, как я упоминал ранее, наиболее вероятной причиной отключения лямбда-триггера SQS является то, что роль выполнения лямбда-функции не имеет одного или нескольких из следующих необходимых разрешений:
- sqs: ChangeMessageVisibility
- sqs: DeleteMessage
- sqs: GetQueueAttribute
- sqs: ReceiveMessage
- Доступ к соответствующим ключам KMS
- Любые применимые разрешения для нескольких учетных записей
- Кроме того, если лямбда-функция находится в VPC, тогда у лямбда-функции должны быть все разрешения для перечисления, создания и удаления ENI.
Причина отключения триггера также не будет указана в журналах лямбда-функций. Итак, я прошу вас убедиться, что у роли выполнения лямбда-функции есть все необходимые разрешения. Если роль выполнения функции Lambda имеет все необходимые разрешения, триггер SQS не должен отключаться автоматически.
В моем случае мы фактически пропустили разрешения VPC, т.е. мы не прикрепили AWSLambdaVPCAccessExecutionRole
policy для роли выполнения Lambda. (Я понятия не имею, как Lambda работала без этой политики). Прошло пять дней с момента исправления ролей, ни один триггер не отключился. Итак, это работает.
Что касается DynamoDB и «противодавления», то идея MLu правильно.
Если у вас есть только одна запись в DynamoDB для каждого сообщения SQS, вы можете просто потерпеть неудачу в Lambda, если запись не удалась. Сообщение остается в SQS и будет снова получено Lambda по истечении времени ожидания видимости. В этом случае лучше использовать размер пакета 1, чтобы обрабатывать сообщения одно за другим.
Если у вас есть несколько записей в DynamoDB для каждого сообщения SQS (умножение записи), лучше поймать ProvisionedThroughputExceededException
в Lambda и поместите неудачные записи в другую очередь с задержкой, чтобы повторить их позже другой Lambda. Обратите внимание: важно повторять каждую запись, а не исходное сообщение.
Поток данных будет таким:
Обратите внимание: любое отложенное повторение записи приемлемо, только если вы действительно можете отложить и повторить их. Они должны быть идемпотентными и не должны содержать данных в реальном времени. В противном случае может быть лучше молча игнорировать любые исключения, чтобы избежать сбоя Lambda, и поэтому удалить и забыть сообщение из SQS.