Aws-lambda-dotnet: C# Lambda 性能与 Node 与 Python

创建于 2016-12-12  ·  35评论  ·  资料来源: aws/aws-lambda-dotnet

第一的。 感谢您将 C# 带到 Lambda! 我喜欢它!

我做了一个快速而肮脏的性能测试来比较各种 lambda 函数的调用速度。 所有测试都是通过使用 AWS 控制台将字符串"foo"作为输入发送到每个相应函数来完成的。 测试非常简单:我只是反复单击 AWS Lambda 控制台中的Test按钮,然后选择了一个有代表性的日志语句。

Python

REPORT RequestId: 6c2026c2-c028-11e6-aecf-116ec5921e69    Duration: 0.20 ms    Billed Duration: 100 ms     Memory Size: 128 MB    Max Memory Used: 15 MB

Javascript/NodeJS

REPORT RequestId: 10a2ac96-c028-11e6-b5eb-978ea2c1c2bd    Duration: 0.27 ms    Billed Duration: 100 ms     Memory Size: 128 MB    Max Memory Used: 16 MB

C#

REPORT RequestId: d9afca33-c028-11e6-99df-0f93927a56a6    Duration: 0.85 ms    Billed Duration: 100 ms     Memory Size: 256 MB    Max Memory Used: 42 MB

这些函数以各自的默认设置部署在us-east-1中。 C# 函数是使用dotnet lambda deploy-function部署的。 Node 和 Python 函数是使用HelloWorld示例代码为每种语言部署的,并更改了实现,以便接受简单的字符串并将其转换为大写。

你可以在这里找到代码: https :

我能做些什么来优化我这边的调用时间吗? 那是你还在做的事情吗? 只是好奇状态。 谢谢!

guidance

最有用的评论

@yunspace异端! :)

C# Lambda All Things!

所有35条评论

性能是我们将始终与 Lambda 和所有受支持的运行时一起努力的事情。 每种语言都有自己的长处和短处,这就是为什么我们会有如此有趣的语言大战 :)

这个测试只是测量语言运行时的启动时间,这是 Node.js 和 Python 等动态语言与 C# 和 Java 等静态语言相比总是很快的,因为缺乏类型检查和延迟加载依赖项。

抱歉,我不是故意要关闭它的。 随意继续对话。

感谢您保持开放。 这不是批评,而是公开讨论的基础。

在您的回复中,您提到该测试测量语言启动时间。 我想更清楚地了解这一说法。 我认为在第一次点击时,应用程序已配置(如果需要)然后启动,但在随后的点击中,它已经预热。 如果它每次都启动,那么将一次性运行代码(例如读取配置值)移动到处理程序类的构造函数中没有任何好处,因为无论如何它都是在每次调用时构建的。 我不是从您的 re:Invent 演示文稿中理解的。 你能澄清一下吗? 谢谢!

为了确认我的理解,我在这里重新阅读了 Lambda 容器的工作原理: http :

@bjorg @normj在这方面的文档很模糊:(
我提供了以下反馈,希望得到澄清

  • '我们怎样才能让它变得更好?
    确切地说,可以在哪里查找“一段时间”的实际时间以获取语句:“AWS Lambda 将容器维护一段时间以期待另一个 Lambda 函数调用。”
  • 你想做什么?
    不知道为了预测性能而实际发生容器重用的可能性有多少

@bjorg您在此处发布的不是 Lambda _冷启动时间_。 但是_暖响应时间_。

当一个 C# 函数第一次从冷启动时,它可能需要几百毫秒(在我的例子中是 500 毫秒)。 一旦预热,它将保持活动状态并以类似于您发布的更快的速度处理请求(在我的情况下大约为 0.9 到 1 毫秒)。 最终它将在其生命周期结束时死亡,或者发生自动缩放并启动更多冷 lambdas。 要获得启动时间,请等待 15 分钟左右,然后单击测试。

所以是的,你仍然把东西放入构造函数中。 因为您不会在每次单击测试时获得全新的 Lambda。 但是,如果您每小时只单击一次,您将获得一个全新的 Lambda。

在优化方面,对于_冷启动时间_,您可以:

  1. 确保你总是有请求进来,24x7,这样你的 lambdas 总是温暖的
  2. 在您的 lambda 上设置定期 ping(cloudwatch 时间表或 newrelic 或其他东西),以便您的 lambda 始终保持温暖。

对于 _warm 响应时间_ 确实没有太多优化点:

  1. 一般可接受的人类响应时间是 200 毫秒
  2. 小于 1 毫秒实际上是相当不错的。 您很少会在helloworldtoUpper之外获得此费率。
  3. 如果你在你的 lambda 前面放置一个 API 网关并向全世界公开 HTTP 调用。 来自网络的平均缓存调用约为 50 毫秒。
  4. 无论如何,AWS 都会以 100 毫秒的间隔向您收费
  5. 0.85ms 可能接近普通 C# 代码的原始性能。 尝试在您的机器上的 main 方法中运行您的函数并查看。

也不要将性能与响应时间混淆。 仅仅因为当您手动顺序单击时 Node 在 20 毫秒内响应,并不意味着当每秒有 100k 自动请求泛滥并且每秒增加时它的行为方式相同。 做一些真正的并发和负载测试。 您可能会发现 Java 或 C# 等多线程语言在负载下每秒可能会处理更多请求。 我实际上在某个地方看到了 lambda 统计信息:Python = 最快的冷启动,Java = 每秒最快的热请求,但现在找不到。

无论如何,这应该有望回答您的问题。

@yunspace ,感谢您的详细撰写。 我很好奇当前的 .NET Core 实现如何将数据从原始内部调用编组到 C# 处理程序。 由于处理程序的签名可以不同(根据类型和参数数量),我假设它是通过反射调用的。 所以我的问题基本上是是否有一种方法可以在不触及封送层的情况下被调用。 例如, Foo(Stream, ILambdaContext)签名可以是预定义的处理程序模式,它绕过将有效负载转换为 POCO 实例的任何逻辑。

不幸的是,调用代码无法检查,所以我不知道它是否可以进一步优化。 我希望温暖的调用在性能上与其他运行时非常接近。

为了将原始输入 JSON 解组到 POCO,默认情况下 lambdas 使用Amazon.Lambda.Serialization.Json ,它依赖于流行的 Newtownsoft Json.Net。 但是你可以用你自己的序列化器交换这个默认实现。 请参阅处理标准数据类型部分

我明白你的意思了。 大多数序列化程序(包括 Json.Net)使用慢的反射。 为了证明这个理论,我想你可以看看Foo(Stream, ILambdaContext)给你更好的热调用响应时间。 如果是这样,那么为字符串和 POCO 推出您自己的客户序列化程序可能是值得的。

实际上,我说的不是数据反序列化器,而是调用 lambda 处理程序的方法。 由于 lambda 处理程序可以具有不同的签名(在类型和参数数量方面),调用它的方法必须依赖于反射。 AFAIK,没有办法以绕过这种便利机制的方式编写 lambda 处理程序。

我最近对此进行了一些测试,发现序列化程序确实没有产生那么大的影响。 事实上,移除几乎所有移动部件并返回静态数据或只返回空流,似乎你能得到的最好结果是在暖函数上大约 0.85 毫秒。 我怀疑调用 C# 函数的代码可能会受到指责,并且似乎只能由 lambda 团队 ( @normj ) 解决。

对于包括 Java 在内的所有其他运行时,您可以在暖函数上获得 0.22 - 0.30 毫秒。 本质上意味着 C# 的 lambda 调用开销要差 3 到 4 倍。

虽然我同意这并不能说明全部情况,因为 C# 可能会更快地完成实际工作,但这个框架开销值得研究。 我假设其中一些可能归因于它是新的,性能并不是最重要的。 此外,在没有某种类型的缓存的情况下过度使用反射也可能是罪魁祸首。

我也怀疑这是由于早期的代码。 我希望我们能看到它的样子,以便我们可以帮助优化它。 或者,使用较低级别的钩子进行试验也会有所帮助。

我也希望我们能提供帮助。 我正处于等待让 C# 核心以多种方式工作的边缘。 这是 Azure 和 Amazon 之间的一个关键决定因素。 无服务器 C# 方法比必须使用 Windows 更新、性能检查、SQL 更新等维护多台 EC2 机器要好得多。 让这些环境为客户保持最新几乎是一项全职工作。

无服务器 C# 方法更具成本效益、劳动密集型、可自动扩展和可重用。

唯一的其他突出问题是现在具有成本效益的可扩展 RDC 方法 :-)

我已将此线程传递给服务团队以查看。 我主要维护客户端工具,比如这些库和 Visual Studio 集成,所以我不能过多地谈论服务端发生的事情。 我可以在对服务代码的限制性查看中告诉您,反射使用已优化,但总是有其他因素需要研究。

@genifycom我的理解是,与其他运行时相比,该线程正在跟踪热启动的 0.5 毫秒性能差异。 由于 Lambda 以 100 毫秒为增量计费,这种性能差异是否会阻碍您的使用? 我并不是要降低找出这种差异的底部的重要性,但 Lambda 团队目前正在努力提高性能的主要领域是冷启动时间。

澄清一下,这并没有阻止我们采用 C# Lambda(或 LambdaSharp,正如我们所命名的那样)。 这更多的是一种自豪感。 :)

完全明白!

不确定这是否是正确的地方,但我们目前正在用 C# 构建 Web 后端,并且我们的冷启动时间为几秒,有时长达十甚至更多。 不过,在第一次打击之后,一切都很好。 对于一个重要的 C# 项目,这仍然是正常的,还是我们可以做些什么来减少它? 我们喜欢能够在我们熟悉的 .NET 生态系统中工作,但这让我们有些头疼。

我假设它与我们在项目中包含的外部包以及亚马逊在冷启动期间如何处理它们有关,因为空项目似乎要好得多。 我希望有人能对此有所了解。

@normj我们看到的性能问题是否有任何更新?

@SpoonOfDoom你有没有看到每隔 10 分钟左右点击一次的建议? 这在 .Net 中永远是非常标准的做法,早在 90 年代,它就让我的托管业务成为最快的,虽然没有其他人这样做过 - 但它已经很常见了,甚至像这样的常用工具 - https://www.iis.net/downloads /microsoft/application-initialization - 推荐。 Lambda 改变了成本模型,但在某种程度上,无论他们如何设计它,都面临着同样的挑战。

@bitshop这就是我们目前正在做的事情。 我们每 10 分钟调用一次,并且在大多数情况下它都有帮助。 但是每隔几个小时我们仍然会出现一些峰值,我们再次遇到冷启动 - 运行 .Net Lambdas 的 AWS 实例似乎有最长的生命周期,然后不管当前的热/冷状态如何,都会使用一个新的实例? 我不确定。
亚马逊似乎是一个奇怪的决定,不让开发人员有机会完全防止这种情况发生(至少要付出代价)。 当然,我们现在每隔几个小时才达到峰值,但如果它是由客户而不是我们的脚本达到的,客户仍然会感到恼火,并认为我们的应用程序不可靠和/或速度很慢。

@yunspace模板 lambda 函数似乎仍然需要超过 2000 毫秒的冷启动时间。
REPORT RequestId: d1e5f56c-0ea9-11e7-bb5d-bb039f76a793 Duration: 2120.69 ms Billed Duration: 2200 ms

@normj我做错了什么吗?

更新:所以我发现如果函数采用string输入,启动时间将是 ~800 毫秒,但如果我真的为它选择了另一种类型,它将超过 2000 毫秒。

    // 800ms
    public string FunctionHandler(string input, ILambdaContext context)

    // 2000ms, Request being the other object type
    public string FunctionHandler(Request input, ILambdaContext context)

对于 C# 中的两个不同的 Lamba 函数,我在 128MB 中的冷启动时间约为 21 秒,它们都接收 SNS。 S3 put trigger 与 SNS 的时间差不多。 温暖,大约 2 秒。

如果我将内存增加到 256M,我会看到鳕鱼时间下降到大约 10 秒,等等。

Lambda 日志显示我使用了 40MB 的总内存。

从功能之一,总运行时间:

128MB 冷:报告持续时间:21775.92 毫秒计费持续时间:21800 毫秒内存大小:128 MB 使用的最大内存:35 MB

128MB 热:报告持续时间:1326.76 毫秒计费持续时间:1400 毫秒内存大小:128 MB 最大使用内存:37 MB

256MB 冷:报告持续时间:11159.49 毫秒计费持续时间:11200 毫秒内存大小:256 MB 使用的最大内存:39 MB

256MB 热:报告持续时间:792.37 毫秒计费持续时间:800 毫秒内存大小:256 MB 最大已用内存:39 MB

384MB 冷:报告持续时间:7566.07 毫秒计费持续时间:7600 毫秒内存大小:384 MB 使用的最大内存:43 MB

384MB 热:报告持续时间:850.59 毫秒计费持续时间:900 毫秒内存大小:384 MB 已用最大内存:47 MB

只是为了咯咯笑:

1024MB 冷:报告持续时间:3309.12 毫秒计费持续时间:3400 毫秒内存大小:1024 MB 使用的最大内存:38 MB

1024MB 暖:报告持续时间:677.57 毫秒计费持续时间:700 毫秒内存大小:1024 MB 使用的最大内存:41 MB

这对于冷启动来说是很多开销。

相比之下,这里有一个 nodejs 函数,它完成了大约一半的工作(移植到 C# 之前的旧版本),但工作类型相同(获取 SNS,向数据库写入一些内容,将一些内容存储到 S3)但这似乎在整个板与我们拥有的其他功能:

128MB 冷:报告持续时间:262.58 毫秒计费持续时间:300 毫秒内存大小:128 MB 使用的最大内存:19 MB

128MB 热:报告持续时间:134.79 毫秒计费持续时间:200 毫秒内存大小:128 MB 使用的最大内存:19 MB

冷时开销的百分比似乎更合理。

我正在使用 Visual Studio AWS 工具上传捆绑包 - 代码在上传之前已针对目标平台进行了预编译,对吗? 有什么我想念的还是正常的? 这里报告的其他数字较小,但我不知道内存分配。

冷启动时间是构建 Slack 机器人时的一个问题,因为 Slack 在 3,000 毫秒后超时。 真的希望有一种方法可以保证实例始终可用。

我已经打开了关于这个问题的技术支持票。 如果我学到任何有用的东西,我会在这里分享。

虽然有许多变通方法可以通过 cloudwatch ping 等保持 lambda 温暖,但最终冷启动时间应该是您满意的。 您可以优化冷启动,但无法避免它们。 可以肯定的是,当自动缩放发生时,新的 lambdas 也会从冷态扩展。

@bjorg保证实例始终可用,最好考虑 EC2 或 ECS

@InsidiousForce我很惊讶你得到了 21@SpoonOfDoom这样的技术支持票可能是最好的

@yunspace异端! :)

C# Lambda All Things!

好的,在与亚马逊友好的技术支持人员进行了长时间的来回交流之后,对话的基本内容是:
您可以尝试优化您的代码 - 减少文件大小,丢弃并非绝对必要的库,尝试在启动时尽可能少地初始化静态和其他东西,当然,如所讨论的那样增加分配的内存以增加 CPU 功率在这个线程中。 通过定期调用它来保持 Lambda 的存活可以延长问题,但不能消除它。 对于大多数情况,4 分钟的间隔似乎是最佳值,但显然潜在的行为不是完全确定的,因此它不是可靠的规则。 即便如此,它也不能完全消除这个问题。

不幸的是,最重要的是,您只能通过执行所有这些操作才能做到这一点,并且在某些时候分配更多内存不再可行。 您将始终有这些冷启动时间,虽然您可能能够减少它们,但您可能无法将它们减少到对于面向公众的 API 或类似的东西来说是合理的程度 - 似乎如果您不能一次又一次地等待,那么 C# Lambda 不适合你,如果你想要轻松部署和自动扩展,你最好使用 EC2 实例或者(就像我们现在正在做的那样)Elastic Beanstalk .
我们现在将 Lambda 转换为 ASP.NET Web api 项目,这使我们仍然可以从 Visual Studio 进行舒适的部署并保留一些自动扩展选项。

TL;DR:似乎没有可靠的方法来解决这个问题。 请改用 EBS 或 EC2。

因缺乏活动而关闭。 此外,此 repo 主要用于支持客户端库和工具。 此讨论的更好地方是 Lambda 服务团队监控的Lambda 论坛

大家好!
我写了一篇文章,我比较了 Python、PHP、Java、Ruby 和 C#。
你能检查一下并发表你的看法吗? (这不是纯粹的技术资料,而是对初学者更概括)
https://www.cleveroad.com/blog/python-vs-other-programming-languages

这篇文章对我没有帮助。

首先,这不是比较。 页面上的标题写着“使用 Python 优于其他语言的优势”,所以这显然不是比较。

其次,没有一种语言可以满足所有要求!

例如,使用脚本语言构建复杂的框架非常困难。 你关于 Python 的观点是“我们可以说 Python 是一种简约的语言。它很容易编写和阅读。当需要考虑一个问题时,开发人员可以专注于这个问题,而不是语言和它的语法。” 甚至没有开始帮助处理丰富的模型和模型组件之间的交互。

尽管我们似乎已经开始认为微服务可以解决所有问题,但我在这个游戏中已经足够长的时间知道这是一种非常幼稚的方法。

问题有多种形式。

我同意genifycom。 除此之外,如果不是完全错误的话,有些观点似乎是可疑的。 例如,说你不能在 Python 中做基于网络的应用程序(我假设这意味着分布式计算?)似乎是不知情的,并且说 C# 没有很多可用的库是一个奇怪的声明,考虑到大约有 100k 包可用仅在 Nuget 上
此外,Python 没有“解决问题的一种方法”——总是有多种方法可以解决问题,而这通常与语言没有任何关系。
然后有一点你似乎自相矛盾,你在图表中说 Python 不能做跨平台应用程序(嗯?这似乎是错误的),然后在文本中说“Python 与几乎所有现代操作系统兼容” .
还有其他一些小问题——例如,理论上你可以用记事本在 C# 中编码并通过命令行编译,不需要 IDE,而像 IntelliJ 这样的合适的 IDE 也使 Python 开发更加容易。

除此之外,我不确定几乎一年不活动的 GitHub 问题是否是宣传您的博客的正确方式。

genifycom 和 SpoonOfDoom 感谢您的意见,我会考虑到这一点。

关于如何从 .NET 角度为 lambda 处理程序提高 c# 代码效率的任何提示?
我试图解决的一些示例问题:
1) 将 lambda 函数设为静态会增加 Lambda 上下文的重用并提高性能吗?
2)如果我制作 Functions 类(它具有所有 lambda 处理程序)单例类,它会提高性能吗?
3)如果我制作常量/只读变量并在 lambda 函数之间共享它,它会提高性能吗?

如果有人有任何信息,请建议

@niraj-bpsoftware 你为什么要试一试并在这里发布你的发现? 我很想看看是否有明显的差异。 老实说,如果其中任何一个产生影响,我会感到非常惊讶。

1) 上述实例化的好处,即函数生命周期内的一次性固定成本似乎绝对是最小的,并且远远超出任何可测量的阈值。

2)我不能说这个,因为我不这样做。 但是,如果您的处理程序是不同的 lambda 函数,那么它们一开始就没有任何共享,因为据我所知,它们都在单独的进程/容器中运行。

3) 同上。

此页面是否有帮助?
0 / 5 - 0 等级