我有一个AWS Lambda函数,配置只有128MB内存,由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: Metaspace at 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)at java.lang.Class.forName0(Native Method)at java.lang.Class.forName(Class.java:348)at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:94)引起: java.lang.OutOfMemoryError:Metaspace at java.lang.ClassLoader.defineClass1(Native Method)at java.lang.ClassLoader.defineClass(ClassLoader.java:763)at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) 在java.net.URLClassLoader.defineClass(URLClassLoader.java:467)at java.net.URLClassLoader.access $ 100(URLClassLoader.java:73)at java.net.URLClassLoader $ 1.run(URLClassLoader.java:368)at java.net.URLClassLoader $ 1.run(URLClassLoader.java:362)at java.security.AccessController.doPrivileged(Native Method)at java.net.URLClassLoader.findClass(URLClassLoader.java:361)at java.lang.ClassLoader.loadClass(ClassLoader.java:424)at java.lang.ClassLoader.loadClass(ClassLoader.java:357)at 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)at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:219)at lambdainternal.AWSLambda。(AWSLambda.java:60)......还有3个START RequestId:58837136-483e-11e6-9ed3-39246839616a版本:$ LATEST END RequestId:58837136-483e-11e6-9ed3-39246839616a报告RequestId: 58837136-483e-11e6-9ed3-39246839616a Duration:15002.92 ms Billed 持续时间:15000毫秒内存大小:128 MB最大使用内存:50 MB
2016-07-12T14:40:28.048Z 58837136-483e-11e6-9ed3-39246839616a任务 15点后超时
编辑1 如果我将分配给该功能的内存增加到192MB,它可以正常工作,但奇怪的是,报告只在云计算日志中使用59MB内存。我只是丢失了其余的记忆吗?
答案 0 :(得分:18)
在Lambda函数中使用AWS Java SDK时,我一直在观察这一点。 在创建任何AWS客户端(同步或异步)时,您可能会离开Metaspace。
我认为这是由于亚马逊客户端在实例化时正在执行的操作,包括创建AmazonHttpClient以及动态加载请求处理程序链(AmazonEc2Client#init()
私有方法的一部分)。
报告的内存使用量可能是Heap本身,但可能不包括Metaspace。 AWS论坛上有几个主题,但AWS没有就此问题做出回应。
答案 1 :(得分:4)
尝试将分配给lambda的内存从128增加到256 MB
答案 2 :(得分:1)
如何减少冷启动时间?
1)遵循Lambda最佳做法: https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html
2)通过为功能选择更大的内存设置 将内存视为“电源”设置,因为它还决定了函数将接收多少CPU。
3)通过减小功能ZIP的大小 这可能意味着减少您在函数ZIP中包含的依赖项数量。 使用ProGuard可以进一步减小Java JAR的大小
4)[仅Java]使用字节流接口代替POJO接口。 Lambda内部使用的JSON序列化库可能需要一些时间才能启动。这将需要您完成开发工作,但是您可以通过使用字节流接口和轻量级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功能来替代匿名类(lambda,方法引用,构造函数引用等)。 我们在内部注意到与Java 8 Lambda相关的字节码似乎导致次优的启动性能。如果您的代码使用的任何Java 8功能都可以替换匿名类(lambda,方法引用,构造函数引用等),则可以通过返回到匿名类来缩短启动时间。
6)通过使用其他运行时 不同的运行时具有不同的冷启动时间和不同的运行时性能。虽然NodeJS可能适合繁重的IO工作,但Go可能适合执行大量并发工作的代码。客户已经完成了一些基本基准测试以比较Lambda上的语言性能,这是对不同编程语言性能的更一般的比较。没有一个万能的答案,请使用适合您要求的答案。
一般比较:https://benchmarksgame-team.pages.debian.net/benchmarksgame/which-programs-are-fast.html