【.com快译】概述如今,Serverless已经成为各种云应用程序最普遍的部署模型。在这个领域,AWSLambda可谓是最“硬核”的工具。大多数开发者或多或少都有使用Lambda快速构建和运行云函数代码的经验。然而,AWS管理和处理可扩展性、高可用性(HA)、安全性和性能,不像AI机器人,它通过自我学习和优化配置来改进所有云原生(cloud-native)。指数。因此,开发者在设计时需要特别注意和学习如何在成本和性能之间取得平衡。在本文中,我将分享:通过了解Lambda的工作原理,如何合理、充分地使用Lambda。高可用当我们在运行一个Lambda函数时,它实际上是运行在一个默认可以访问外网的VPC(VirtualPrivateCloud)上。但是,它不能同时访问任何其他私有VPC。这里所谓的“访问外网”是指只能访问S3和DynamoDB的AWS服务;无法访问其他VPC下运行的AWS资源(如RDS、Elasticsearch等)。如果一个函数运行在由Lambda管理的VPC上,Lambda将负责其在VPC区域的多个AZ(可用区)中的可用性。但是在大多数企业应用场景中,我们确实需要同时访问RDS和其他VPC资源。因此,我们需要保证以下两个方面:设计Lambda,通过选择不同AZ的多个子网实现高可用。如果一个AZ发生故障,则需要为其他AZ分配足够的IP地址来处理并发的Lambda请求。(注意每次Lambda执行都需要有一个私有IP地址来处理请求。)因此,我们需要在子网中分配足够的IP地址来实现HA。并发尽管AWSLambda会以自己的方式实现可扩展性,但对于有限的资源,Lambda会遵循以下并发执行限制:Accountlevel-默认情况下,它会参考每个region中的所有函数,将值设置为1000。函数级别——默认情况下,它会使用“UnreservedAccountConcurrencylimit”,但这不是一个很好的方法。为了避免耗尽所有帐户级别的并发,它限制了其他功能。因此,我们应该为每个函数保留一个单独的并发数,这样如果由于某种原因事件数量激增,它只会受到影响并在该函数内被隔离。注意-AWS始终维护一个至少有100个并发执行的未预留并发池,以处理未专门设置的函数请求。也就是说,您最多只能分配900个。如果我们在专用VPC上运行Lambda怎么办?在这种情况下,我们需要根据功能的ENI(ElasticNetworkInterfaces,弹性网络接口)扩展性来请求足够的IP地址。您可以使用以下公式估算ENI的大致容量:Concurrentexecutions*(MemoryinGB/3GB)其中:并发执行-是工作负载的预期并发(每秒调用数*平均执行持续时间,以秒为单位)。内存大小-是为Lambda函数配置的内存量(以GB为单位)。在Lambda中进行并发设计时,我们还应该始终考虑其他集成服务(如DynamoDB、RDS等)的限制。我们需要根据这些服务可以处理的最大连接数来调整函数的并发限制。Throttling上文“并发”中提到,一旦函数事件激增并超过并发限制,Lambda将无法再处理任何新的请求。如果不及时处理,会影响业务系统。如果Lambda调用处于同步模式,它将立即收到429类型的错误代码。此外,如果在功能级别或帐户级别设置限制,它还可以接收一些其他信息。因此APIGateway等调用服务需要处理此类重试问题。如果Lambda调用是异步的,Lambda只会在丢弃事件之前尝试两次。因此,如果函数无法处理事件,我们应该使用SQS或SNS定义的DLQ(DeadLetterQueue)进行后期调试处理。如果我们忘记定义DLQ,这些消息将被直接丢弃。如果Lambda调用是基于轮询方式,我们进一步细分两种情况:如果是流式(Kinesis),会不断重试,直到超时(最多7天)。如果是非流式(SQS),则会将消息放回队列中,只有在Visibilitytimelimit到期后才开始重试,并继续执行,直到能够顺利完成处理,或者超过保留期。内存和成本的平衡在Lambda中,内存和CPU是密切相关的,也就是说,如果你增加内存,CPU分配也应该增加。因此,如果我们需要减少Lambda的执行时间,那么我们应该增加内存和CPU。但是,如果你进行过详细的实验,你会发现在一定的限制下,单纯增加内存只会增加获取成本,并不会明显减少执行时间。目前市面上很少有开源工具可以帮助我们找到最优的资源配置。我个人倾向于使用CloudWatch的各种日志来监控内存使用情况和执行时间,然后调整相应的配置。微调内存参数可以对AWS的整体成本产生更大的影响,我以此来寻找最佳平衡点。性能-冷启动与热启动当我们第一次调用Lambda时,它会从S3下载代码和所有依赖项以创建容器并在执行代码之前启动相应的应用程序。整个过程(代码执行除外)所花费的时间称为冷启动时间。并且一旦容器启动并运行,Lambda已经为后续调用进行了初始化,它只需要执行应用程序的逻辑即可。因此,这段时间称为热启动时间。那么问题来了,到底是缩短冷启动时间还是缩短热启动时间呢?原则上,作为完整执行时间的一部分,冷启动占用了大部分时间,所以我们需要想办法减少它。但是在实践中,我们可以通过高质量的代码来减少热启动时间。接下来,我们来讨论如何提高Lambda的整体性能:选择Nodejs和Python等解释型语言,而不是Java或C++,以减少冷启动时间。如果出于某种原因必须选择Java,请使用SpringCloudFunctions而不是SpringBootWeb框架。由于我们搭建弹性网卡的时间较长,会增加冷启动时间,除非您需要专用IP地址的VPC资源,否则请使用默认网络环境。个人解读:随着新版AWSLambda即将发布,这方面应该会有所改善。删除与运行函数无关的所有依赖项。只保留那些需要的。使用各种全局/静态变量和Singleton对象,这些变量可以保持活动状态,直到容器发生故障。因此,任何后续调用都不必重新初始化这些变量和对象。请使用全局定义的数据库连接,以便它们可以在后续调用中重复使用。如果您选择Java,请使用简单的IoC依赖注入,如Dagger和Guice,而不是Spring框架。此外,如果您选择Java,请将依赖项.jar文件与函数代码分开,以加快解包过程。如果选择Nodejs,请将Functionjs文件的大小控制在600个字符以内,并使用V8运行环境(runtime)。V8优化器能够内联主体小于600个字符(包括各种注释)的函数。同样,如果您选择Nodejs,您可以使用代码压缩和/或uglification来减小包的大小,从而大大减少下载包所花费的时间。在某些情况下,我曾看到包大小从10MB减小到1MB的情况。缩小-将删除所有空格、换行符和注释。丑化——混淆并简化所有变量。例如,原始代码:varorganizationname="xyz"varbigArray=[1,2,3,4,5,6]//writesomecodefor(varindex=0;index<6;index++){console.log(bigArray[index]);缩小后:varorganizationname="xyz",bigArray=[1,2,3,4,5,6]for(varindex=0;index<6;index++)console.log(bigArray[index]);丑化后:for(varo=”myname”,a=[1,2,3,4,5,6],e=0;e<6;e++)console.log(a[e])网上有很多文章提及:Lambda的执行环境已经有AWSSDKforNodejs和Python。所以我们不必将它们添加到依赖项中。虽然这个特性有利于提升性能,但是却隐藏着一个问题:SDK库会定期升级最新的补丁。为了不影响Lambda的各种行为,必须使用自己的依赖管理方式。安全性为每个功能分配一个IAM角色。单个IAM角色应该只映射一个函数,即使有多个函数需要相同的IAM策略也是如此。当需要强化特定功能安全策略时,这将有助于维护最小特权策略。由于Lambda将在共享VPC上运行,因此不建议在代码中保留AWS凭证。在大多数情况下,IAM执行角色足以使用AWSSDK连接到各种AWS服务。如果函数需要跨帐户调用服务,则可以使用不同的凭据。因此,我们需要使用AWS的SecurityTokenService中的AssumeRoleAPI(参见https://docs.aws.amazon.com/STS/latest/APIReference/Welcome.html)并检索各种临时凭证。如果该函数需要存储长期凭证(例如数据库凭证、访问密钥),请将环境变量与加密助手或AWSSystemManager一起使用。可测试性既然AWSLambda允许用户的代码在云端运行,那么我们如何在本地进行测试呢?虽然Lambda没有提供直接测试的URL,但是我们可以根据要启动的事件源系统进行测试。我们可以使用AWSSAM(参见https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html)对Lambda函数进行本地测试。它为CLI提供了一个类似Lambda的本地执行环境。我们可以获得API网关的localhostURL,它将在本地调用Lambda函数。我们可以使用localstack(参见https://github.com/localstack/localstack)开源项目来创建一个包含大量AWS资源/服务的本地环境。它可以与其他AWS服务一起运行Lambda。由于它以API的形式提供所有服务并在后端作为Docker容器运行,因此您还可以将AWSSAM与localstack集成。将业务逻辑放在Lambda处理程序之外。处理程序函数应该只用于检索输入并将它们传递给其他函数/方法。这些函数/方法会将它们解析成与我们的应用程序相关的变量,然后进一步使用它们。此过程不仅将业务逻辑与处理程序分开,而且还可以在我们创建的对象和函数的上下文中进行测试。Blue/GreenDeployment通过Lambda自带的Versioning和Alias功能,我们可以发布一个函数的多个版本。同时,我们可以在单独的容器中并行调用每个版本。默认情况下,版本签名由$LATEST表示。在开发过程中,我们可以使用这些版本创建dev/UAT等多个环境。但是,由于每次我们上传新代码,版本都会递增,客户端会指向最新版本。所以在生产环境中一定不要直接使用Versioning,而是可以使用Alias。别名可以指向一个函数的特定版本。因此,如果您的代码发生变化,并且发布了更新的版本,事件源仍将指向相同的别名。我们只需要管理何时需要将Alias指向新版本。这将启用蓝/绿部署。我们可以使用一些sampleevent来测试新版本,确认正常后,我们可以通过修改Alias指向来切换访问流量。同时,如果我们发现有什么问题,我们可以快速回滚到原来的版本。我个人认为CloudWatch可以很好地配合Lambda,为用户提供Lambda执行的各种详细信息。Lambda可以自动跟踪请求数量、每个请求的执行时间、导致错误的请求数量,并发布相关的CloudWatch指标。同时,您还可以使用这些指标自定义各种CloudWatch告警功能。或者,我们可以使用X-Ray来识别Lambda执行中的各种潜在瓶颈。当我们试图可视化执行函数所花费的时间时,它非常有用。此外,X-Ray还有助于跟踪连接到整个过程的所有下游系统。其他建议不要使用AWSLambda控制台开发将直接用于生产的代码。由于代码版本控制不是自动的,如果误点击保存按钮,生产环境中的工作代码将被完全覆盖。它不与GitHub或其他代码存储库集成。它不能导入到AWS开发工具包之外的模块中。因此,如果您需要特定的库,您必须从一开始就在本地开发自己的函数,创建一个.zip文件,然后将其上传到AWSLambda中。请使用AWSSAM或无服务器框架进行开发。就Lambda部署的CI/CD计划而言,它实际上与其他交付计划没有什么不同。各种环境变量和参数存储可用于将代码与配置分开。总结在本文中,我们讨论了在设计和部署Lambda时值得参考和使用的各种最佳实践。我们可以根据实际应用的编码语言和用例,不断提升业务系统的性能。当然,我们也可以借鉴其他云平台的这些最佳实践,以及Kubernetes的serverless平台。希望你能将这些实践运用到自己成熟的生产环境和应用中。原标题:AWSLambdaBestPractices,作者:RajeshBhojwani
