作者 | Mike Danilov
译者 | 明知山
策划 | Tina
AWS Lambda 是一种无服务器计算服务,将代码作为高可用、可伸缩、安全、容错的服务来运行。Lambda 抽象了底层计算环境,允许开发团队专注于应用程序开发,加快产品发布速度并降低总体成本。
亚马逊云科技高级主任工程师 Mike Danilov 在 2023 年旧金山 QCon 大会 上介绍了 AWS Lambda 及其内部工作原理。本文对本次演讲内容进行了总结,从介绍 Lambda 开始,概述了该服务的关键概念及其基础,有助于深入了解整个系统。
随后,我们将深入探讨调用路由层,这个层被认为是连接所有微服务并确保整个系统无缝运行的关键组件。之后,我们将转向计算基础设施——即代码执行发生的空间。这代表了更广泛的无服务器框架中的无服务器环境。与此同时,我们将加入一个关于冷启动的故事,这是在云基础设施中运行代码时的一个常见主题。
AWS Lambda 概览
Lambda 让用户能够按需执行代码,作为一个无服务器计算系统,无需拥有、配置或管理服务器。Lambda 可以使用各种集成语言, 让用户专注于代码,简化了流程。
Lambda 已经运行了好几年,因其对变更需求的快速响应,满足了数百万用户的需求,产生了数万亿次的调用。用户只需要做一些简单的配置,比如指定首选的内存大小和资源分配比例,包括计算能力和 CPU。
Lambda 支持两种调用模型,首先是同步调用。在这种模式下,发送的请求被路由到执行环境,然后执行代码,并在相同时间轴上提供同步响应。另外一个是异步调用 ,涉及为请求分配队列,然后通过轮询系统在不同的时间轴上处理请求。本文将讨论同步和异步调用的等效性,并主要集中在当前上下文的同步调用上。
其设计原则对于理解 Lambda 来说至关重要。第一个原则是可用性,即确保对每个用户请求都做出可靠的响应。在按需系统中,效率至关重要,系统需要快速配置和释放资源以防止浪费。根据需求进行快速的伸缩,可有效地缩减规模以最小化浪费,这就是规模原则。安全性是 AWS 的首要任务,确保用户有一个安全可靠的执行环境来运行他们的代码。最后,Lambda 也强调性能,在执行应用程序业务逻辑的基础上提供最小的开销,从而实现一个隐形且高效的计算系统。
请求路由
请求路由是 Lambda 的重要组成部分——是连接各种微服务的关键层,提供诸如可用性、伸缩性和访问执行环境等基本属性。我们将通过说明构建过程来更好地理解这个层。
在这个场景中,Alice 希望在云端部署她的代码。初始的步骤是引入配置服务,用于存储她的代码和相关配置。随后,引入了一个前端,负责处理请求,执行验证和授权,并将配置信息存储在数据库中。下一个组件是 worker,作为代码的执行环境或沙盒。尽管表面上看起来很简单,但在按需计算方面扔存在一些挑战,比如 worker 或执行环境的可用性在调用期间可能是不确定的。为了解决这个问题,引入了一个叫作 “placement” 的新系统,用于按需创建执行环境或沙盒。
前端需要与 placement 通信,在将请求转发到执行环境之前请求一个沙盒,完成函数的设置。然而,由于在每次调用请求之前都需要进行按需初始化,因此仍然存在挑战。按需初始化涉及多个步骤,包括创建执行环境、下载客户代码、启动运行时和初始化函数。这个过程可能需要几秒钟,可能会对整体客户体验产生负面影响。
延迟分布图表说明了一段时间内调用持续时间的频率。绿色延迟表示代码执行成功,反映了业务逻辑的效率及其 CPU 利用率。为了最大限度地减少开销并提升客户体验,引入了一个新系统—— worker 管理器。它可在两种模式下运行,在前端请求时提供预先存在的沙盒,实现平稳的“热调用”,或者在没有沙盒的情况下,通过 placement 启动一个较慢的路径来创建新的沙盒。热调用具有最小的开销和最快的速度,但在这方面人们仍在努力地消除冷启动,需要做出进一步的改进。
上面给出了生产环境中 Lambda 同步调用路由的描述。系统集成了额外的可用性区域和前置负载均衡器。负责跟踪沙盒的 worker 管理器由于依赖内存而面临挑战,因为在主机发生故障时可能导致数据丢失。一年前引入了一种叫作分配服务的替代方案来解决这个问题。它在功能方面与 worker 管理器类似,包含了一个可靠的分布式存储,即日志记录,可确保区域一致性。
分配服务利用了分区,每个分区都有一个首领和两个跟随者,利用首领与跟随者架构来增强故障转移。这种转变显著增强了系统的可用性,使其对单主机故障和可用性区域事件具有容错性。从内存存储转到了分布式存储,再加上引入了首领与跟随者模型,不仅提升了效率还降低了延迟。本小节探讨了冷启动和热启动以及一致状态在增强可用性方面的关键作用。
计算布局 (Fabric)
计算布局(特别是 Lambda 基础设施中的 worker 集群)负责执行代码。集群由 EC2 实例组成,也就是 worker,在其中创建执行环境。容量管理器根据需求调整最佳的集群大小,并监控 worker 的健康状况,及时替换不健康的实例。数据科学协作机制通过利用实时信号和预测模型帮助容量管理器做出明智的决策。
考虑到数据隔离性问题,在同一 worker 上运行多个用户的代码存在着一些挑战。采用快速虚拟化技术 Firecracker 有助于克服这一障碍。Firecracker 将每个执行环境封装在微型虚拟机(microVM)中,确保了强大的数据隔离,允许不同的帐户安全地共存于同一 worker 上。这种从 EC2 到 Firecracker 的转变显著提升了资源利用率,防止过载并提供了稳定的性能。
Firecracker 带来了强大的隔离性、最小的系统开销,改进了对 worker 集群热度的控制。采用 Firecracker 显著降低了新建执行环境的成本,如延迟分布图所示。使用 VM 快照加速了初始化过程,降低了创建新执行环境的开销。
以上概述了创建 VM 快照系统的过程,强调了在 worker 之间分发快照,确保快速恢复 VM,并保持强大的安全性。系统引入了一种叫作“copy-on-read”的间接层,解决与共享内存相关的潜在安全威胁。还讨论了将相同的 VM 恢复到一致性状态的挑战,以及与各种社区(如 Java 和 Linux)的持续合作,作为提高系统安全性和效率的持续努力的一部分。
快照分发
快照分发是 EC2 的一个关键问题,特别是考虑到快照的大小可以达到 30 GB。传统的下载方法可能耗时,至少需要 10 秒钟才能完成。为了优化这一过程,采用了与视频流类似的机制,即随着初始部分的播放,内容会在后台逐步加载。类似地,快照被分割成较小的块,通常为 512 KB,可以先下载用于恢复 VM 所需的最小块集合。这种方法具有双重优点,可以分摊下载时间,并且在调用期间只获取必要的数据块。
这种按需加载块的机制涉及 VM 内存与快照文件之间的映射。进程在访问内存时要么从内存页面中检索数据,要么(如果不可用)退回到快照文件。这个过程的效率在很大程度上依赖于缓存命中率,包括本地、分布式和源缓存。一种策略是通过识别和共享熟悉的块来最大化缓存命中率。例如,操作系统和运行时块可以进行除重,并跨多个函数共享,从而提升效率并减少对区域的调用。
为了进一步优化块管理,建议使用分层增量快照。这些快照使用不同的密钥加密,分为操作系统、运行时和函数块。操作系统和运行时块可以共享,即使在来源未知的情况下,也可以利用收敛加密来减少公共位的重复。收敛加密确保相同的明文内容会生成相等的加密块。这种方法增强了缓存局部性,增加了对本地分布式缓存的命中,降低了延迟开销。
在生产环境中,间接层被稀疏的文件系统取代,简化了请求过程,并在文件系统级别按需提供数据块。这种复杂的方法有助于构建更高效、响应更快的系统。
我们解决了冷启动问题吗?
在成功实现了快照分发和 VM 恢复后,系统应该能够良好地运行。然而,在某些冷调用中,尽管它们接近目标位置,仍然存在一些延迟。为了更好地理解这个问题,请重温页面缓存和内存映射的相关知识。操作系统有一项优化措施涉及预读取,即对常规文件进行顺序读取,当访问单个页面时读取多个页面。对于映射内存来说,这种方法被证明是低效的,会导致为看似随机的页面请求下载整个快照文件。
延迟分布图体现了这种低效率。为了解决这个问题,对 100 个 VM 之间的内存访问进行了分析,并发现了相同的访问模式。这种模式记录在页面访问日志中,并附加到每个快照中。因此,在快照恢复期间,系统拥有所需页面及其顺序的相关信息,大大提升了效率。这种创新解决方案成功地缓解了与冷启动相关的问题。值得注意的是,用户可以通过在他们的 Java 函数上启用 Lambda SnapStart 来体验这项改进。
总    结
在本文中,我们深入探讨了 Lambda 架构中增强系统可用性和可伸缩性的调用路由层。在基础设施方面,Firecracker 显著提升了效率,保持了强大的安全性。系统的性能得到了显著改善,并成功解决了冷启动难题。这些努力最终形成了一个基本概念:在云端无需服务器执行代码,而这正是 Lambda 作为用户体验压缩算法的本质。
最后,更多详细内容可以在这里可以找到。
查看英文原文
https://www.infoq.com/articles/aws-lambda-under-the-hood/
声明:本文为 InfoQ 翻译整理,未经许可禁止转载。
今日好文推荐
继续阅读
阅读原文