我最近试图分析在aws lambda中托管的服务的一些性能问题。分解这个问题,我意识到它只是在每个容器上的第一个调用。在隔离问题时,我发现自己创建了一个新的测试项目来获得一个简单的示例。
测试项目(你可以克隆它,构建它 mvn package
,部署它 sls deploy
然后通过aws管理控制台进行测试。)
本项目有2个aws lambda功能: source
以及 target
. 这个 target
函数只返回一个空的json {}
. 这个 source
函数调用 target
使用aws lambda sdk的函数。
事件的大致持续时间 target
冷启动时功能为300-350毫秒,热启动时为1毫秒。事件的大致持续时间 source
冷启动时功能为6000-6300ms,热启动时为280ms。
冷启动时的6秒开销 source
在热调用中,获取客户端的时间为3秒,调用另一个函数的时间为3秒,分别为3毫秒和250毫秒。我得到类似的时间为其他服务,如aws-sns。
我真的不明白在这6秒钟里它在做什么,我能做些什么来避免它。在进行预热调用时,我可以获取客户机并存储引用以避免前几秒钟,但其他几秒钟来自实际使用其他服务(sns、lambda等),我不能真正作为禁止操作来执行。
那么,其他人是否经历了相同的冷启动持续时间,我可以做些什么来提高这方面的性能(除了内存设置)
2条答案
按热度按时间qfe3c7zg1#
配置的并发性有助于缩短代码初始化的持续时间。除此之外,它的目标是从函数代码的执行环境设置中获得另一个开销。
请参阅此处的“打开配置的并发”部分。
tcomlyy62#
java lambda冷启动时间慢的主要原因是需要加载类和初始化对象。对于简单的程序,这可能非常快:一个lambda除了打印“hello,world”之外什么也不做,它将在大约40毫秒内运行,这类似于python运行时。另一方面,一个spring应用程序需要更多的时间来启动,因为即使是一个简单的spring应用程序在做任何有用的事情之前也会加载数千个类。
虽然减少冷启动时间的明显方法是减少需要加载的类的数量,但这很少容易做到,而且常常是不可能的。例如,如果您在spring中编写web应用程序,那么在处理web请求之前无法初始化spring应用程序上下文。
如果这不是一个选项,并且您正在使用maven shade插件来生成一个“uberjar”,那么您应该切换到我在这里描述的组装插件。原因是lambda解压了部署包,所以一个“uberjar”变成了许多必须单独打开的小类文件。
最后,增加你的内存分配。毫无疑问,这是提高lambda性能(java或其他)所能做的最好的事情。首先,因为增加内存可以减少java垃圾收集器必须完成的工作量。其次,因为lambda获得的cpu数量取决于内存分配。在1769 mb之前,您不会获得完整的虚拟cpu。我建议对于一个java应用程序,你给它2GB;更大分配的成本通常被减少的cpu需求所抵消。
我不愿意做的一件事是为提供的并发性付费。如果您想让一台机器一直运行,请使用ecs/eks/ec2。要认识到,如果你的需求激增,你仍然会得到冷启动。
更新:假期里我花了一些时间来量化各种绩效改进技巧。完整的文字在这里,但数字值得重复。
我的示例程序与op的类似,是一个“什么都不做”的程序,它只是创建了一个sdk客户端,并使用它来调用api:
我用不同的内存大小运行它,每次都强制冷启动。所有时间均以毫秒为单位:
正如我上面所说的,增加内存的主要好处是同时增加cpu。创建和初始化一个sdk客户机是cpu密集型的,所以你能给它的cpu越多越好。
更新2:今天早上我试着用graalvm编译一个简单的aws程序。构建独立的可执行文件需要几分钟的时间,甚至由于awssdk的依赖性,它还创建了一个“回退映像”(具有嵌入式jdk)。当我比较运行时时,使用标准java运行没有区别。
一句话:使用java来处理运行时间足够长的事情,从而从hotspot中获益。使用不同的语言(python、javascript,或者go)来处理运行时间短、需要低延迟的事情。