Подтвердить что ты не робот

OutOfMemoryError при создании AmazonS3Client в лямбда

У меня есть функция AWS Lambda, сконфигурированная только с 128 МБ памяти, запускается SNS (которая сама запускается S3) и загружает файл с S3.

В моей функции у меня есть следующее:

public class LambdaHandler {

    private final AmazonS3Client s3Client = new AmazonS3Client();

    public void gdeltHandler(SNSEvent event, Context context) {
        System.out.println("Starting");
        System.out.println("Found " + eventFiles.size() + " event files");
    }

Я прокомментировал и исключил из этого сообщения всю логику, потому что получаю OutOfMemoryError, который я выделил для создания объекта AmazonS3Client. Когда я вынимаю этот объект, я не получаю ошибку. Точный выше код приводит к OutOfMemoryError.

Я назначил 128MB памяти функции, действительно ли этого недостаточно, чтобы просто захватить учетные данные и создать экземпляр объекта AmazonS3Client?

Я попытался предоставить конструктор AmazonS3Client

new EnvironmentVariableCredentialsProvider()

а также

new InstanceProfileCredentialsProvider()

с аналогичными результатами.

Создается ли для объекта AmazonS3Client просто больше памяти?

Ниже показана трассировка стека:

Metaspace: java.lang.OutOfMemoryError java.lang.OutOfMemoryError: Метапроцесс в com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder.build(BeanDeserializerBuilder.java:347) в com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:242) в com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:143) в com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2 (DeserializerCache.java:409) в com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer (DeserializerCache.java:358) в com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2 (DeserializerCache.java:265) в com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer (DeserializerCache.java:245) в com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:143) в com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:439) в com.fasterxml.jackson.databind.ObjectReader._prefetchRootDeserializer (ObjectReader.java:1588) в com.fasterxml.jackson.databind.ObjectReader. (ObjectReader.java:185) в com.fasterxml.jackson.databind.ObjectMapper._newReader (ObjectMapper.java:558) в com.fasterxml.jackson.databind.ObjectMapper.reader(ObjectMapper.java:3108)

Когда я пытаюсь предоставить InstanceProfileCredentialsProvider или EnvironmentVariableCredentialsProvider, я получаю следующую трассировку стека:

Исключение в потоке "main" java.lang.Error: java.lang.OutOfMemoryError: Metaspace at lambdainternal.AWSLambda. (AWSLambda.java:62) в java.lang.Class.forName0 (Нативный метод) в java.lang.Class.forName(Class.java:348) at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:94) Причиняется: java.lang.OutOfMemoryError: Metaspace at java.lang.ClassLoader.defineClass1 (собственный метод) при java.lang.ClassLoader.defineClass(ClassLoader.java:763) в java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)   на java.net.URLClassLoader.defineClass(URLClassLoader.java:467) в java.net.URLClassLoader.access $100 (URLClassLoader.java:73) в java.net.URLClassLoader $1.run(URLClassLoader.java:368) в java.net.URLClassLoader $1.run(URLClassLoader.java:362) в java.security.AccessController.doPrivileged(собственный метод) в java.net.URLClassLoader.findClass(URLClassLoader.java:361) в java.lang.ClassLoader.loadClass(ClassLoader.java:424) в java.lang.ClassLoader.loadClass(ClassLoader.java:357) в lambdainternal.EventHandlerLoader $PojoMethodRequestHandler.makeRequestHandler(EventHandlerLoader.java:421)   в lambdainternal.EventHandlerLoader.getTwoLengthHandler(EventHandlerLoader.java:777)   в lambdainternal.EventHandlerLoader.getHandlerFromOverload(EventHandlerLoader.java:802)   в lambdainternal.EventHandlerLoader.loadEventPojoHandler(EventHandlerLoader.java:888)   в lambdainternal.EventHandlerLoader.loadEventHandler(EventHandlerLoader.java:740)   в lambdainternal.AWSLambda.findUserMethodsImmediate(AWSLambda.java:126)   в lambdainternal.AWSLambda.findUserMethods(AWSLambda.java:71) в lambdainternal.AWSLambda.startRuntime(AWSLambda.java:219) в lambdainternal.AWSLambda. (AWSLambda.java:60)... еще 3 START RequestId: 58837136-483e-11e6-9ed3-39246839616a Версия: $LATEST END RequestId: 58837136-483e-11e6-9ed3-39246839616a REPORT RequestId: 58837136-483e-11e6-9ed3-39246839616a Продолжительность: 15002,92 мс Продолжительность: 15000 мс. Размер памяти: 128 МБ. Используемая максимальная память: 50 МБ
2016-07-12T14: 40: 28.048Z 58837136-483e-11e6-9ed3-39246839616a Задача после 15,00 секунд

РЕДАКТИРОВАТЬ 1 Если я увеличиваю память, выделенную для функции до 192 МБ, она работает нормально, хотя это, как ни странно, сообщает только о 59 МБ памяти в журналах cloudwatch. Я просто теряю оставшуюся память?

4b9b3361

Ответ 1

Я наблюдал это при использовании AWS Java SDK в функции Lambda. Казалось бы, при создании любого из AWS-клиентов (Sync или Async) вы можете выйти из Metaspace.

Я считаю, что это связано с тем, что клиент Amazon выполняет при создании экземпляра, включая создание AmazonHttpClient, а также динамическую загрузку цепочек обработчиков запросов (часть частного метода AmazonEc2Client#init()).

Возможно, что заявленное использование памяти предназначено для самой кучи, но может не включать Metaspace. На форумах AWS есть несколько тем, но ответов от AWS на этот вопрос нет.

Ответ 2

Попробуйте увеличить память, выделенную лямбдой от 128 до 256 МБ

Ответ 3

Одним из способов уменьшения холодного запуска является установка памяти на 1536 МБ и тайм-аута на 15 минут. Это даст выделенному хосту возможность запускать только вашу лямбду вместо того, чтобы запускать лямбду на общем хосте +, когда нужно запустить новый экземпляр, он будет копировать код из кэша на хосте, а не копировать из S3.

Хотя это будет дороже, и если вы не хотите этого делать, продолжайте читать ниже.

Как я могу уменьшить время холодного запуска?

1) Следуйте лучшим практикам Lambda: https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html

2) Выбрав больший объем памяти для вашей функции Думайте о памяти как о параметре "питания", поскольку он также определяет, сколько ЦП будет получать ваша функция.

3) Уменьшая размер вашей функции ZIP Вероятно, это означает уменьшение количества зависимостей, которые вы включаете в свою функцию ZIP. JAR файлы Java могут быть дополнительно уменьшены в размере с помощью ProGuard

4) [Только Java] Используйте интерфейс bytestream вместо интерфейса POJO. Библиотеки сериализации JSON, которые Lambda использует внутри, могут занять некоторое время для запуска. Это потребует от вас работы разработчика, но вы можете улучшить это, используя интерфейс потока байтов вместе с облегченной библиотекой JSON. Вот несколько ссылок, которые могут помочь: http://docs.aws.amazon.com/lambda/latest/dg/java-handler-io-type-stream.html https://github.com/FasterXML/jackson-jr

5) [Только Java] Не используйте функцию Java 8, которая заменяет анонимные классы (лямбда-выражения, ссылки на методы, ссылки на конструкторы и т.д.) Внутри мы заметили, что байт-код, связанный с Java 8 Lambda, приводит к неоптимальной производительности при запуске. Если ваш код использует любую функцию Java 8, которая заменяет анонимные классы (лямбда-выражения, ссылки на методы, ссылки на конструкторы и т.д.), Вы можете получить лучшее время запуска, вернувшись к анонимным классам.

6) Используя другое время выполнения Разные среды выполнения имеют разное время холодного запуска и разную производительность. Хотя NodeJS может быть лучше для тяжелой работы ввода-вывода, Go может быть лучше для кода, который выполняет много параллельной работы. Клиенты сделали несколько базовых тестов для сравнения производительности языков на Lambda, и вот более общее сравнение производительности различных языков программирования. Не существует универсального ответа, используйте то, что имеет смысл для ваших требований.

Основные тесты:https://read.acloud.guru/comparing-aws-lambda-performance-of-node-js-python-java-c-and-go-29c1163c2581

общее сравнение: https://benchmarksgame-team.pages.debian.net/benchmarksgame/which-programs-are-fast.html