2021 AWS Lambda大战:所有语言的性能比较(冷启动和热启动)
Aleksandr Filichkin-5分钟阅读
让我们比较一下所有支持的运行时+2个自定义运行时(Rust和GraalVM)的性能。
将比较冷启动和热启动。
源代码在这里:https://github.com/Aleksandr-Filichkin/aws-lambda-runtimes-performance。它需要最小的本地设置(几乎所有的都是Docker化的)。
NodeJs (14.x)
Python (3.9)
Go(1.x)
Ruby(2.7)
.Net(3.1)
Java (11)
Rust(1.54.0)
GraalVM(21.2)
免责声明。
所有的基准都是在2021年9月进行的
我不是所有这些语言的专家,我很高兴看到GitHub repo中的MR有性能改进。我将支持这些 repo,并每三个月进行一次性能测试。我相信开放源码的合作 :)
测试场景
我们将测试API-Gateway->AWS Lambda->DynamoDb流程。
我们将只测试POST端点,它将把数据保存到已知的AWS区域(us-east-2)的DynamoDb表中。
主要流程
冷启动测试
我尽了一切努力来减少冷启动。
删除了无用的依赖性。
尽可能多地移到初始化阶段(例如,在Java中把所有东西移到静态),以便在启动时使用CPU的爆发。
指定了区域。
摆脱了任何DI框架
结果。
冷启动结果
冷启动结果
所有语言(除了Java和.Net)都有一个相当小的冷启动。
Java甚至不能用128Mb启动。它需要更多的内存。但GraalVM在这种情况下可以提供帮助。请随意阅读关于GraalVM和AWS Lambda的详细页面
在所有的设置中,Rust击败了所有的其它语言,唯一的例外是128MB的Python是最好的。
庞大的设置只对Java和.Net有帮助。
热启动测试
测试是向每个lambda逐一发送15,000个请求。
对于负载测试,我使用JMeter。它看起来像。
我们将检查哪些指标?
每种语言的平均(每分钟)持续时间(256MB设置,(128MB的简短结果你可以在最后找到)。
每种语言的最长(每分钟)时间(256MB设置)。
NodeJS
NodeJS有一个预期的行为。
开始的时候很慢,但经过JIT优化后会变得更好。
NodeJS 256MB的平均持续时间
NodeJS 256MB的最大持续时间
Python
具有稳定的性能:第100次和第15000次调用是一样的。
Python 256MB的平均持续时间
Python 最大持续时间为256MB
Ruby
我观察到Ruby非常奇怪的行为:平均持续时间在增长(看起来像是内存泄漏或代码中的错误)。
红宝石256MB的平均时间
红宝石 256MB 最大持续时间
.NET
最初的~1千次调用很慢,但随后它的性能非常好。
.Net 256MB的平均持续时间
.Net的最大持续时间为256MB
Golang
稳定的弹性性能。
Golang 256MB的平均持续时间
Golang 256MB的最大持续时间
Java
最初的~1千次迭代很慢,然后变得更快(JIT C1有帮助)。
Java 256MB的平均时间
Java最大持续时间为256MB
对于Java,我期望C2 JIT优化在1万次迭代后进行,但即使在2万次调用后也没有优化,而且持续时间是一样的。请看下面的屏幕。
Java 256 MB,没有C2优化。
GraalVM
正如预期的那样,GraalVM从一开始就具有稳定的良好性能。
GraalVM 256MB的平均时间
GraalVM 256MB的最大持续时间
Rust
Rust有一个持续的令人敬畏的表现。
Rust 256MB的平均持续时间
Rust 256MB的最大持续时间
全部在一起
衡量平均性能是非常棘手的,因为每一个新的lambda都有一些不同的结果(我相信这是因为lambdas在不同的硬件上分配)。我运行了3次测试,两次测试之间有30分钟的延迟,以便有3个不同的lambdas分配。
3个时间段的5K迭代(256MB Lambda)。
256 MB Lambda
此外,我还测试了128MB lambda的相同流量。在这里我们可以看到一个很大的区别。
128MB的平均温度状态
128MB的平均温度状态
最大128MB(每分钟)温热状态
我想对于CPU密集型的流程来说,编译语言和解释语言之间的差异会更大。我想,GraalVM在128MB的情况下表现不佳,因为它里面还有JVM,它需要太多的内存,而且Lambda经常执行GC。
结论
冷启动
所有语言(除了Java和.Net)都有一个相当小的冷启动。
Java甚至不能用128Mb启动。它需要更多的内存。但GraalVM在这种情况下可以提供帮助。
在所有的设置中,Rust在冷启动时都胜过所有的运行时间,唯一的例外是128MB,Python是最好的。
热启动
Golang和Rust是赢家。他们有同样出色的表现。
.Net的性能几乎与Golang和Rust相同,但只是在1千次迭代后(JIT后)。
GraalVM有一个稳定的伟大的性能,几乎与.Net相同,比Rust和Golang差一点。但对于最小的设置来说, 它的性能并不理想。
与.Net一样,Java也需要一些时间(1-3千次迭代)进行JIT(C1)。不幸的是,在这个特定的用例中,我无法在JIT C2编译后达到预期的良好性能。也许AWS只是禁用了它。
Python具有稳定的良好性能,但对于128MB的计算机来说工作速度太慢。
Ruby的性能几乎与Python相同,但我们看到在20分钟的调用后(15000次迭代后),一些持续时间在增长。
NodeJs是最慢的运行时间,经过一段时间后,它变得更好了(JIT),但仍然不够好。此外,我们看到NodeJS的最大持续时间最差。
冷+暖启动的赢家是Golang和Rust。它们总是比其他运行时更快,并表现出非常稳定的结果。