当选择无服务器和Lambda来搭建云架构时,你需要了解固有的限制,以便在应用程序和代码的规模以及复杂性开始增长时进行扩展。
在构建应用程序代码时,无服务器是快速升级的一个好选择,但有一个常见的误解,即无服务器意味着DevOpsLess或NoOps,而事实并非如此。
更重要的是,有时你必须提前在设计和架构上进行投资,以避免后来遇到瓶颈或招致大量技术债务。
一、无服务器问题的快速概述
当应用程序开始增长时,如果你不提前计划,很快就会遇到无服务器范式特有的挑战。很多人在开始尝试无服务器时很可能意识不到,为什么他们需要提前设计。
节流
Lambda节流是可以同时运行的实例数量的结果。
AWS Lambda默认一个账户的区域并发限制为1000,也就是可以同时处理1000个请求。一旦到达上限,新的请求会被节流。当然你可以请求提高此阈值,不过要注意,这会产生成本影响。因此在检查架构设计并确保你确实需要它之前,不应自动提高阈值。
需要直面的现实是,你同时运行的事件或服务越多,你就会越快地遇到瓶颈。如果你计划安全在无服务器架构上运行,那么就有必要在编写第一行代码的时候就考虑到这一点。
即使今天你只需要满足小规模请求的设计,但必须尽早考虑,当你有数千个(甚至更多)租户或客户时,这是否会线性缩放。根据构建资源、Lambda和微服务的方式(以及每个服务的“微”程度),如果将服务分解为太小的块,则最终可能会由于过多并行事件的限制而中断整个服务链流。
这意味着需要充分了解当前正在处理的流量(以每分钟事件的形式),甚至是服务处理的峰值和异常流量。所有这些都需要考虑,此外还需要考虑每种调用所采用的通信调用方法——同步或异步(稍后会更深入地研究)——其中,使用同步调用,每个服务或系统调用都会叠加起来,并可能使系统过载。
重要的是要意识到节流的工作方式并不是完全可预测的。因此,即使你有适当的监视以确保你不会达到1000个并行事件,并且你认为你已经覆盖了,但这实际上可能在你的第一个峰值时发生,其中节流可能发生在更低的阈值,因为这本质上是意外行为(但在AWS文档中有记录)。因此,一个好的实践是,以一种能够在这种情况发生时恢复的方式构建你的系统(例如等幂性和重试)。
超时
顾名思义,无服务器不运行在永远运行的服务器上,它们提供临时运行时,函数运行时最多只有15分钟的总窗口。这可能会影响服务可以处理的输入的大小。当你从头开始设计函数时,输入的大小随着处理时间的增加而不断增加,你可能会在运行时遇到超时。
因此,对于运行时随输入大小线性扩展的服务或函数,建议的设计模式是将输入拆分为块或批处理,并在不同的Lambda中处理它们。这样做时,使用队列也是一个很好的实践,从而避免节流。
事件大小
事件驱动的设计模式在基于无服务器的系统中很常见,很多时候需要链中的各种服务来进行事件处理,包括API网关、SQS(Amazon Simple Queue Service)、事件桥接器、SNS(Amazon 的发布/订阅服务),其中每种服务都有不同的事件大小限制。你使用的每个资源可能都有需要注意的不同大小限制,在发送大型有效负载时,沿链传递数据可能会中断。
这意味着你不能在资源之间发送无限的有效负载,并且在构建函数和服务时需要注意这一点。链中的每一个资源都能够处理不同大小的有效负载,这意味着如果不提前考虑这一点,并确保可以在系统服务和资源中接收此有效负载,则会遇到失败事件。
一种解决方案,本质上是一种变通方法,可以通过利用支持有效负载大小的不同资源,在S3存储桶中传递大型有效负载。(提示:搜索“AWS 服务配额”以了解有关你使用的资源的更多信息,这是一个很好的入门参考)
幂等性
所谓的幂等性,是分布式环境下的一个常见问题,一般是指我们在进行多次操作时,所得到的结果是一样的,即多次运算结果是一致的。也就是说,用户对于同一操作,无论是发起一次请求还是多次请求,最终的执行结果是一致的,不会因为多次点击而产生副作用。
由于前文中列出的所有挑战,故障总是会发生,因此会出现延迟。Lambdas和无服务器资源通常构建在重试机制上。这就是幂等性至关重要的地方。服务需要为给定的输入交付相同的结果,无论它们被重试或部分重试了多少次(这意味着即使只重试了流的一部分,结果仍然需要相同)。
你需要提前设计幂等性,以便重试和重放不会影响生产系统的状态。一个好的做法是确保在运行数据时为每个实例创建唯一的但不随机的确定性ID。这是正确执行此操作的良好指南。
内存泄漏
若要了解内存泄漏是如何发生的,首先需要了解运行代码的机制是如何工作的,因为它也有其局限性。对于Lambda函数,相同的Lambda运行程序会被一次又一次地重用,直到它死去。也许它可以完美运行1000次,但它可能会在第1001次运行时开始崩溃,并可能导致你的服务出现问题。
例如,使用相同解释器的Python代码会被反复使用。如果这段代码在每个运行中都添加全局内存对象,这些对象可能会通过不同的运行实例传递,这可能会导致内存泄漏,即超出实例内存限制。然后你的Lambda就会崩溃。
在使用共享资源和多租户架构时,这一点尤其重要。你需要确保不会留下未使用的资源、敏感数据或其他垃圾。在租户隔离方面,如果使用共享内存,则需要非常小心,确保数据不会在实例之间泄漏,因为数据可能会在租户之间泄漏。
同步与异步调用
无服务器中的同步调用可能会导致许多问题(比如前文中提到的“节流”)。在可能且不需要立即响应的情况下,异步调用模式是无服务器的首选模式。
无服务器通常被设计成异步和无状态的,而不是同步和有状态的,因此发挥技术的优势总是最好的。当你确实需要同步调用时,请确保有适当的保护措施(如使用API网关),并通过适当的日志记录获得可见性。
二、设计无服务器应用程序的复原能力和健壮性
对于那些希望快速运行、专注于交付和推出产品、不想在基础设施管理上耗费过多的人来说,无服务器是一个很好的选择。不过在选择运行无服务器时,你需要记住,这意味着使用许多不同的AWS资源,了解每种资源如何独立工作、如何协同工作以及它们的局限性和缺陷非常有必要。
要发挥无服务器的优势,需要建设适当的“护栏”,从而尽可能规避上述问题。
首先,与不可预测的动态云环境中的所有云原生应用程序一样,对于无服务器应用程序,通过监控、日志记录和追踪,确保对应用程序的工作方式具有适当的可见性尤为重要。
再者,谈到在无服务器上运行时,另一个常见且不容忽视的问题是成本。设计和构建应用程序的方式也会直接影响成本。你需要有适当的机制,以避免过度滥用资源,从计费警报和常规的具有成本意识的系统设计开始,这是无服务器的一个极其重要的实践。
另外,确保安全性和数据隐私也很重要,以免在使用共享资源和多租户时危及关键数据。有一些优秀的DevSecOps工具可以帮助你做到这一点。
当你了解了无服务器的工作原理后,你可以优化设计、架构和应用程序代码,进而实现显著的成本改进,同时获得更好的性能、安全性和容错能力。
三、写在最后
Lambda的推出开启了云计算的新时代,随后,微软、谷歌、IBM等大厂也先后推出了自己的Serverless产品。云产品的全面Serverless化逐渐成为时之所趋。
一旦Serverless进入规模化使用阶段,一方面,资源的使用由平台统一调度,按需使用,整个云计算资源的使用成本有望实现大幅降低;另一方面,编程方式会随着Serverless的发展产生很大不同。我们有理由相信,Serverless将成为IT基础设施变革中不可轻忽的拐点。
原文链接:https://thenewstack.io/serverless-doesnt-mean-devopsless-or-noops/