使Lambda函数更快(和更便宜)运行的提示

2020-12-08 20:25:22

AWS Lambda服务使我们能够轻松部署和运行自己的代码,而不必担心基础架构(与非无服务器技术相比)。它本质上可以无限扩展(功能强大,责任重大),并且可以与其他一系列服务连接,例如API网关,S3,AppSync,DynamoDB等。

通常,人们首先开始使用该服务创建的东西就是古老的HTTP API,例如REST甚至是GraphQL。在这种情况下,由于实际用户(潜在客户)是将调用Lambda函数的用户,因此重要的是,他们必须尽可能快地响应-,这意味着我们希望函数启动尽可能短然后,使我们的代码以最有效的方式执行必要的逻辑。

如何确保是这种情况?好吧,这就是本文的主题,在其中我们将介绍五个可以在这方面帮助您的技巧。因此,事不宜迟,我们来看一下!

给功能分配更多的RAM意味着更快的执行速度。没错。但这也意味着您要支付更多,对吧?这要看情况。有时实际上并非如此。

考虑这两个512MB RAM和1024MB RAM Lambda函数CloudWatch日志。下图还显示了日志的计费持续时间:

因此,在这里我们可以看到,使用512MB的RAM Lambda函数(蓝色),计费时间通常是200ms。但是,如果使用1024 MB的RAM(红色),即增加2倍,则记帐时间将减少到100毫秒,即减少2倍。甚至初始调用的持续时间(冷启动持续时间)也从1400ms减少到700ms。

但是请注意,结果可能会因函数执行的任务而异。例如,在某些情况下,您可能无法实现足够大的降价幅度以实现降价。换句话说,如果您设法将调用时间从140ms减少到105ms,这很好,但是仍然不会改变价格,因为两次调用的计费时间都是200ms。

在增加RAM之前,请使用不同的有效负载测试功能,然后根据结果确定是否有任何值得采取的措施。

函数的大小越大,冷启动的时间越长。 Mikhail Shilkov撰写的一篇非常不错的文章谈到了影响冷启动持续时间的各种因素,其中之一就是包装尺寸。如果您真的想深入了解,一定要读一读。

基于这个事实,我想在这里给出的建议是-注意函数的大小。尝试使用尽可能少的外部软件包。请注意,函数中包含的每个程序包也会带来附加的依赖关系,从而使情况更糟。

这样,还要注意如何实际导入软件包。如果可以仅导入特定功能,则可以这样做,而不是导入整个程序包。

例如,在使用我们经常需要与各种AWS服务进行通信的AWS开发工具包时,仅导入您将使用的实际客户端。

我想使用一些有用的工具来检查第三方包装带到桌上的东西(或者我应该说-从桌上取出)。

其中一种工具是(bundlephobia),它将为您提供软件包大小及其所有相关性的概述。绝对有用,尤其是在功能上比较相似的软件包并决定使用哪个软件包时。

另一个是Webpack Visualizer,它为您提供了最终产品Webpack捆绑包中包含的所有软件包的出色概述。例如:

是!还建议您将功能与Webpack捆绑在一起,因为这不仅会使您的功能成为单个文件,而且还将确保仅实际使用的代码进入构建,这自然会减少最终文件的数量尺寸。

配置Webpack可能会有些艰巨,但最终还是值得的。幸运的是,对于每个新的Webiny项目,捆绑过程都是为您预先配置的,因此您可以立即跳转到新项目! 😊

你们中的某些人可能已经知道,在Lambda函数中调用另一个Lambda函数通常被视为一种反模式,是的,在某些情况下,这确实是正确的。主要原因是,当另一个函数正在处理调用有效负载时,第一个函数处于空闲状态并仅在等待响应,这意味着您实际上没有为之付出任何代价。

是的,您还可以异步调用函数,而无需等待调用完成(使用InvocationType:" Event"选项),但是,在这里,我们将更多地讨论同步函数调用,这肯定是如果我们对调用的函数正在返回的实际响应感兴趣,则需要使用此命令。

让我们考虑以下示例,我认为从第一个函数调用另一个Lambda函数(并等待响应)可以认为是一种很好的方法。

上图显示了我们在Webiny上执行的SSR实现,其中包括几个AWS资源:CloudFront,API Gateway,S3,两个Lambda函数和一个数据库。

我不会在这里过多介绍细节(可以随意查看“无服务器端渲染-终极指南”一文,但是,我们对这两个Lambda函数所做的工作实际上是拆分工作并优化成本。 Web Server Lambda配置有最少的系统资源(256MB RAM),因为它的唯一任务是返回存储在数据库中的缓存的SSR HTML。

但是,如果数据库中没有SSR HTML,则我们需要生成它,这实际上是一个繁重的过程,而使用256MB RAM来执行它根本不会削减它。因此,我们不仅仅增加了Web服务器Lambda的RAM,还调用了SSR Lambda函数,该函数包含更多的系统资源(例如-2 GB RAM),而我们只是为此付费当我们真正需要它时。如果将Web Server Lambda配置为具有相同数量的资源,只是在大多数情况下只是从数据库中拉出一些数据,那简直是浪费金钱。这样,从长远来看,我们可以节省大量资金。

如果您有一个Lambda函数,它的大小很笨重,您也可以执行此操作,这只是因为需要存在第三个依赖项,但是仍然没有那么频繁地使用它。

例如,Webiny提供的开箱即用的应用程序之一,Page Builder应用程序,有其自己的安装过程,在该过程中,我们基本上下载了初始示例页面和图像,并将它们分别插入数据库,然后将它们保存到用户的S3存储桶。此过程需要几个NPM软件包来处理文件,这可以很容易地在整个函数大小中添加数百个KB。

既然如此,我们决定完全从主要的Page Builder API函数中提取安装功能,然后将其放入单独的Page Builder安装功能中。

在这个组织中,我们不会给冗余的包增加主要的Page Builder API函数的负担,这有助于减小其大小,并且自然会影响冷启动的持续时间。

总而言之,只要您有一个密集的过程,要么需要更多的系统资源,要么需要增加整体功能大小的其他程序包,请尝试将其提取为单独的功能,尤其是在很少触发该过程的情况下。

以下技巧是一个简短但有效的技巧,不仅可以用于谈论Lambda函数,而且可以用于一般编码。

如果可能,请并行执行代码,而不要串行执行。例如,如果我们需要执行五次100ms运算,那么串行执行意味着总共需要500ms才能完成。

const操作= [a,b,c,d,e]; for(让i = 0; i< operation.length; i ++){等待操作[i](); // 100ms操作。 }

而不是串行进行操作,请尝试使用Promise.all方法并行进行操作,如下所示:

const操作= [a,b,c,d,e]; const promises = []; for(令我= 0;我<操作.length;我++){承诺。推(操作[i]()); }等待承诺。全部(承诺); // 100ms操作。

最后但并非最不重要的一点是,如果您在Lambda函数的代码中发出HTTP请求,则启用“保持活动”功能很有用。默认Node.js HTTP / HTTPS代理上的选项,因为这样可以避免在每个请求上建立TCP连接,并使我们能够始终重用现有请求:

默认情况下,默认的Node.js HTTP / HTTPS代理会为每个新请求创建一个新的TCP连接。为了避免建立新连接的成本,您可以重用现有连接。

对于像DynamoDB这样的客户端,这尤其方便,我们确实需要HTTP请求延迟尽可能低。

出色的Yan Cui已经撰写了一篇有关此选项引入的实际性能提升的好文章,他的文章-Lambda优化技巧-启用HTTP保持活动。如我们所知,在没有HTTP保持活动的情况下,DynamoDB操作的平均持续时间约为33毫秒,而启用该选项后,平均持续时间降至10毫秒!

建立新的TCP连接令人震惊的事实是,实际建立比我们尝试执行的实际客户端操作要花费更多的时间!因此,当您考虑它时,决定是否启用此选项几乎是理所当然的。

通过几乎完全从我们那里抽象出基础架构问题,并减少总体开发和维护成本,AWS Lambda(以及通常的无服务器技术)确实确实使我们的开发人员生活更轻松。但是,正如我们已经看到的那样,仍然有一些技巧非常有用,这些技巧可以帮助我们进一步优化工作流程。

希望我们在此处显示的五个技巧将对您的无服务器之旅有所帮助,但是,当然,如果您还有其他问题,疑虑或想法,请随时通过Twitter甚至直接通过我们的社区ping我松弛。

谢谢阅读!我叫Adrian,是Webiny的全职开发人员。在业余时间,我想写一些关于现代前端和后端Web开发工具的经验,希望它可以对其他开发人员有所帮助。如果您有任何疑问,评论或想打个招呼,请随时通过Twitter与我联系。

Webiny是一个开放源代码框架,可帮助开发人员和组织构建在无服务器基础结构之上运行的应用程序。

学到更多 希望在您的收件箱中获得更多像这样的出色文章。 我们每周仅发送一份新闻稿,请勿发送垃圾邮件,也不会与第三方共享您的数据。