如何提高aws lambda(java)对aws服务的初始调用的性能?

sqyvllje  于 2021-07-03  发布在  Java
关注(0)|答案(2)|浏览(459)

我最近试图分析在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等),我不能真正作为禁止操作来执行。
那么,其他人是否经历了相同的冷启动持续时间,我可以做些什么来提高这方面的性能(除了内存设置)

qfe3c7zg

qfe3c7zg1#

配置的并发性有助于缩短代码初始化的持续时间。除此之外,它的目标是从函数代码的执行环境设置中获得另一个开销。
请参阅此处的“打开配置的并发”部分。

tcomlyy6

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:

public void handler(Object ignored, Context context)
{
    long start = System.currentTimeMillis();

    AWSLogs client = AWSLogsClientBuilder.defaultClient();

    long clientCreated = System.currentTimeMillis();

    client.describeLogGroups();

    long apiInvoked = System.currentTimeMillis();

    System.err.format("time to create SDK client = %6d\n", (clientCreated - start));
    System.err.format("time to make API call     = %6d\n", (apiInvoked - clientCreated));
}

我用不同的内存大小运行它,每次都强制冷启动。所有时间均以毫秒为单位:

|                   |  512 MB | 1024 MB | 2048 MB | 4096 MB |
|+++++++++++++++++++|+++++++++|+++++++++|+++++++++|+++++++++|
| Create client     |    5298 |    2493 |    1272 |    1019 |
| Invoke API call   |    3844 |    2023 |    1061 |     613 |
| Billed duration   |    9213 |    4555 |    2349 |    1648 |

正如我上面所说的,增加内存的主要好处是同时增加cpu。创建和初始化一个sdk客户机是cpu密集型的,所以你能给它的cpu越多越好。
更新2:今天早上我试着用graalvm编译一个简单的aws程序。构建独立的可执行文件需要几分钟的时间,甚至由于awssdk的依赖性,它还创建了一个“回退映像”(具有嵌入式jdk)。当我比较运行时时,使用标准java运行没有区别。
一句话:使用java来处理运行时间足够长的事情,从而从hotspot中获益。使用不同的语言(python、javascript,或者go)来处理运行时间短、需要低延迟的事情。

相关问题