好好活就是有意义的事,有意义的事就是好好活
The Serverless Computing Survey: A Technical Primer for Design Architecture
The Serverless Computing Survey: A Technical Primer for Design Architecture

The Serverless Computing Survey: A Technical Primer for Design Architecture

The Serverless Computing Survey: A Technical Primer for Design Architecture

Please wait while flipbook is loading. For more related info, FAQs and issues please refer to DearFlip WordPress Flipbook Plugin Help documentation.

Abstract

云基础设施的发展激发了云原生计算的出现。作为最有前途的微服务部署架构,Serverless 计算最近越来越受到业界和学术界的关注。由于其固有的可扩展性和灵活性,无服务器计算对于不断增长的 Internet 服务变得越来越有吸引力和普遍。尽管云原生社区势头强劲,但现有的挑战和妥协仍在等待更先进的研究和解决方案来进一步探索无服务器计算模型的潜力。作为对这些知识的贡献,本文通过将架构解耦为四个堆栈层:虚拟化、封装、系统编排和系统协调,调查和阐述了无服务器上下文中的研究领域。我们强调了这些工作在每一层中的关键含义和局限性,并对未来无服务器计算领域的潜在挑战提出建议。

Introduction

Definition of Serverless Computing

传统的基础设施即服务 (IaaS) 部署模式需要长期运行的服务器来实现可持续的服务交付。但是,无论用户应用程序是否正在运行,这种独占分配都需要保留资源。因此,它导致当前数据中心的资源利用率平均只有 10% 左右,特别是对于具有昼夜模式的在线服务。这一矛盾吸引了平台管理的按需服务模式的发展,以实现更高的资源利用率和更低的云计算成本。为此提出了无服务器计算,亚马逊、谷歌、微软、IBM、阿里巴巴等大多数大型云厂商都已经提供了这种弹性计算服务。

在下文中,我们将首先回顾 Berkeley View [65] 中给出的定义,然后我们将给出更广泛的定义。我们认为,对基于 FaaS 的无服务器模型的狭隘看法可能会削弱其进步。到目前为止,无服务器计算还没有正式的定义。 Berkeley View [65] 中公认的定义如下:

  • 𝑆𝑒𝑟𝑣𝑒𝑟𝑙𝑒𝑠𝑠 𝐶𝑜𝑚𝑝𝑢𝑡𝑖𝑛𝑔=𝐹𝑎𝑎𝑆(𝐹𝑢𝑛𝑐𝑡𝑖𝑜𝑛-𝑎𝑠-𝑎𝑎)+𝐵𝑎𝑎𝑆(𝐵𝑎𝑐𝑘𝑒𝑛𝑑-𝑎𝑠-𝑎𝑎)。一个谬论是“无服务器”可以与“FaaS”互换,这是在最近的一次采访中揭示的 [78]。准确地说,它们都是无服务器计算必不可少的。 𝐹𝑎𝑎𝑆 模型实现了功能隔离和调用,而𝐵𝑎𝑎𝑆 提供了对在线服务的整体后端支持。
  • 在𝐹𝑎𝑎𝑆 模型(又名Lambda 范式)中,应用程序被分割成函数或函数级微服务[26、45、57、65、117、141]。函数标识符、语言运行时、一个实例的内存限制和函数代码 blob URI(统一资源标识符)共同定义了一个函数的存在 [94]
  • 𝐵𝑎𝑎𝑆 涵盖了广泛的服务,任何应用程序所依赖的服务都可以归入其中。例如,云存储(Amazon S3 和 DynamoDB)、传递的消息总线系统(谷歌云发布/订阅)、消息通知服务(Amazon SNS)和 DevOps 工具(Microsoft Azure DevOps)

为了描述无服务器计算模型,我们以图 1 中的异步调用为例。无服务器系统从用户那里接收触发的 API 查询,验证它们,并通过创建新的沙箱(也称为冷启动 [15,28,65])或重用运行的热启动(也称为热启动)来调用函数。隔离确保每个函数调用在单个容器或从访问控制控制器分配的虚拟机中运行。由于事件驱动和单事件处理的特性,可以触发无服务器系统以提供按需隔离的实例,并根据实际应用程序工作负载水平扩展它们。之后,每个执行工作者访问一个后端数据库来保存执行结果[23]。通过进一步配置触发器和桥接交互,用户可以自定义复杂应用程序的执行(例如,在 {𝐹𝑛𝐴、𝐹𝑛𝐵、𝐹𝑛𝐶} 管道中构建内部事件调用)。

在更广泛的场景中,我们认为无服务器计算模型应该具有以下特征:

  • Auto-scaling. 自动可扩展性不应只限于 FaaS 模型(例如,容器黑匣子作为 OpenWhisk [134] 中的调度单元)。 识别无服务器系统不可或缺的因素是在适应工作负载动态时执行水平和垂直扩展。 允许应用程序将实例数量缩放到零还引入了一个令人担忧的挑战 – 冷启动。 当一个函数经历冷启动时,实例需要从头开始,初始化软件环境,并加载应用程序特定的代码。 这些步骤会显着拖累服务响应,导致违反 QoS(服务质量)。
  • Flexible scheduling. 由于应用程序不再绑定到特定的服务器,无服务器控制器根据集群中的资源使用情况动态调度应用程序,同时确保负载平衡和性能保证。 此外,无服务器平台还考虑了多区域协作[154]。 对于更健壮和可用的无服务器系统,灵活的调度允许工作负载查询分布在更广泛的区域 [119]。 它避免了在节点不可用或崩溃的情况下严重的性能下降或对服务连续性的破坏。
  • Event-driven. 无服务器应用程序由事件触发,例如 REST ful HTTP 查询的到达、消息队列的更新或存储服务的新数据。 通过使用触发器和规则将事件绑定到函数,控制器和函数可以使用封装在上下文属性中的元数据。 它使事件和系统之间的关系变得可检测,从而实现对不同事件的不同协作响应。 云原生计算基金会 (CNCF) 无服务器小组还发布了 CloudEvents 规范,用于共同描述事件元数据以提供互操作性。
  • Transparent development. 一方面,管理底层主机资源将不再是应用维护者的烦恼。 这是因为他们不知道执行环境。 同时,云供应商应确保可用的物理节点、隔离的沙箱、软件运行时和计算能力,同时使它们对维护人员透明。 另一方面,无服务器计算还应该集成 DevOps 工具,以帮助更有效地部署和迭代。
  • Pay-as-you-go. 无服务器计费模型将计算能力的成本从资本支出转变为运营支出。 这种模式消除了用户根据峰值负载购买专属服务器的需求。 即用即付模型通过共享网络、磁盘、CPU、内存等资源,只指示应用实际使用的资源[1,2,26],无论实例是运行还是空闲。

我们将结合上述五个特征的弹性计算模型作为无服务器计算定义的关键。 随着无服务器的出现,应用程序维护人员会发现根据应用程序的实际处理事件而不是预先分配的资源来计费资源定价更具吸引力[2]。 如今,无服务器计算通常应用于批处理作业的后端场景,包括数据分析(例如,PyWren [64] 中的分布式计算模型)、机器学习任务(例如,深度学习)[78, 111] 和事件驱动的 Web 应用程序。

Survey Method by the Layered Serverless Architecture

无服务器计算中的一些调查讨论了无服务器泛化的特征 [15, 52, 65, 112, 116, 144]。然而,他们只从高层次的角度提出文献评论,而忽略了提供足够的架构含义。因此,研究人员和无服务器供应商可能会发现很难掌握和理解真正的无服务器架构中的每个问题。在缺乏系统知识的情况下,挑战和提出的解决方案将缺乏对各种 serverless 系统的高可移植性和兼容性。为此,本次调查旨在提出分层设计,并从不同角度总结研究领域。它可以帮助研究人员和从业者进一步了解无服务器计算的本质。如图 2 所示,我们用自下而上的逻辑分析其设计架构,并将 serverless 计算架构解耦为四个堆栈层:Virtualization, Encapsulate, System Orchestration, and System Coordination.

Virtualization layer. 虚拟化层使用性能和功能安全的sandbox来隔离Fucntion。 沙箱充当应用程序服务代码、运行时环境、依赖项和系统库的运行时。 为了防止在多应用或多租户的场景下访问资源,云厂商通常采用容器/虚拟机来实现隔离。 目前,流行的沙盒技术有 Docker [41]、gVisor [49]、Kata [67]、Firecracker [3] 和 Unikernel [86]。 第 2 节介绍了这些解决方案以隔离功能并分析它们的优缺点。

Encapsule layer. Encapsule 层中的各种中间件可以实现自定义Function的触发和执行,它们还提供数据metrics收集以进行通信和监控。我们将所有这些额外的中间件称为 sidecar。 它分离了服务的业务逻辑,并实现了功能和底层平台之间的松散耦合。 同时,为了加快实例启动和初始化,预热池通常用于封装层( Encapsule layer ) [44、97、104、105]。此外Serverless 系统还可能通过分析负载模型进行预测, 从而实现一对一的预热实例; 或者为所有的Function构建一个模板, 然后根据运行的特征动态的安装requirements (REQs), 这是一种一对多的方法.第 3 节介绍和比较了这些概念。

System Orchestration layer. System Orchestration 层允许用户配置触发器和绑定规则,通过随着负载变化动态调整来确保用户应用程序的高可用性和稳定性。 通过云编排器,在线和离线调度相结合,可以避免资源争用,回收闲置资源,缓解co-located functions的性能下降。 上述实现通常也集成到容器编排服务中(例如,Google Kubernetes 和 Docker Swarm)。 在无服务器系统中,资源监视器、控制器和负载均衡器被整合以解决调度挑战 [4, 32, 50, 57, 66, 70, 88, 139]。 它们使无服务器系统能够实现三个不同级别的调度优化:资源级、实例级和应用程序级。 第 4 节从这三个角度详细分析了调度方法。

System Coordination layer. 系统协调层由一系列后端即服务 (BaaS) 组件组成,这些组件使用统一的 API 和 SDK 将后端服务集成到Function中。 很明显,它不同于使用云外本地物理服务的传统中间件。 这些 BaaS 服务提供存储、队列服务 [94、99]、触发器绑定 [75、77]、API 网关、数据缓存 [6、7]、DevOps 工具 [24、25、63、122] 和其他自定义组件 为了更好地满足系统编排层的灵活性要求。 第 5 节讨论了无服务器系统中的这些基本 BaaS 组件。

每个堆栈层在无服务器架构中都起着至关重要的作用。 因此,基于上述层次结构,我们将本次调查的贡献总结如下:

(1) 介绍 serverless 的定义并总结其特点。
(2) 详细阐述基于四层层次的架构设计,并审查每一层的重要和代表性工作。
(3) 分析当前的 serverless 性能及其局限性。
(4) 探索无服务器计算的挑战、局限和机遇。

调查的其余部分安排如下:第 2-5 节介绍了四个堆栈层,并详细阐述了无服务器计算的当前研究领域。 第 6 节分析了降低性能的几个因素,并比较了当前的生产无服务器系统。 最后,第 7-8 节给出了无服务器计算的挑战、局限性和机遇。 我们在第 9 节结束本文。

2 VIRTUALIZATION LAYER

每当在无服务器计算中调用用户函数时,它将在虚拟化沙箱中加载和执行。 一个函数既可以重用一个暖沙箱,也可以创建一个新沙箱,但通常不能与不同的用户函数共同运行。 在这个前提下,虚拟化中的大部分关注点是隔离性、灵活性和低启动延迟。 隔离保证了每个应用进程都在划定的资源空间中运行,并且运行的进程可以避免受到其他进程的干扰。 测试和调试能力以及对系统扩展的额外支持证明了灵活性。 低启动延迟要求沙盒创建和初始化的快速响应。 目前虚拟化层上的沙盒机制分为四大类:传统VM(虚拟机)、容器、安全容器和Unikernel。 表 1 在几个方面比较了这些主流方法。

表中“启动延迟”表示冷启动的响应延迟。 “隔离级别”表示功能运行不受他人干扰的能力。 “OSkernel”显示GuestOS 中的内核是否共享。 “热插拔”允许函数实例以最少的资源(CPU、内存、virtio 块)启动,并在运行时添加额外的资源。 “支持 OCI”是指它是否提供开放容器倡议 (OCI),这是一种用于表达容器格式和运行时的开放治理结构。此外,本调查所有表格中的“√”表示使用了该技术或策略,反之亦然。

传统的基于 VM 的隔离采用 VMM(虚拟机管理器,例如 hypervisor),为 GuestOS 提供虚拟化能力。它还可以通过提供的接口(或使用 Qemu/KVM)调解对所有共享资源的访问。借助快照,当在每个 VM 实例中的应用程序上执行补丁时,VM 在快速故障保护方面表现出高度的灵活性。尽管 VM 提供了强大的隔离机制和灵活性,但它缺乏用户应用程序启动延迟较低(通常 >1000 毫秒)的优势。这种权衡是无服务器计算的基础,其中函数很小,而 VMM 和来Guest内核的相对开销很高。

Container customization: provide high flexibility and performance.

无服务器计算中另一个常见的功能隔离机制是使用容器。 容器引擎利用 Linux 内核来隔离资源,并在 HostOS [19, 92] 中将容器创建为不同的进程。 每个容器共享具有只读属性的 HostOS 内核,该属性通常包括二进制文件和库。 高度的灵活性也通过UnionFS(联合文件系统)附加到容器上,它可以通过只读和读写层来组合分层的容器映像。 本质上,容器通过命名空间实现隔离,使共享相同系统内核的进程和Linux Cgroups来设置资源限制。 由于不需要硬件隔离, 基于容器的沙箱在启动延迟上要比基于hypervisor的粗粒度的VM低.

代表性的容器引擎是 Docker [41]。 Docker 将软件打包到一个适应环境要求的标准化 RunC 容器中,包括库、系统工具、代码和运行时。 Docker 容器以其轻量级的特性被广泛应用于各种无服务器系统。一些工作进一步优化了容器运行时,以更好地适应无服务器系统中的应用程序需求。 SOCK [101] 提出了一种用于无服务器 RunC 容器的集成解决方案,其中 Docker 容器中的冗余机制在这个精益容器中被丢弃。通过仅构建根文件系统、创建通信通道和施加隔离边界,SOCK 容器使无服务器系统在启动延迟和吞吐量方面更高效地运行。 SOCK 容器的启动延迟降低到 10ms-50ms,而 docker 容器通常需要 50ms-500ms。附加工具(例如,调试器、编辑器、coreutils、shell)丰富了容器的功能,同时增加了镜像大小,与精简容器中的压缩冗余不同, CNTR [130] 将容器镜像分为“胖”和“瘦”部分。用户可以独立部署“slim”镜像,并通过动态附加“fat”镜像来使用其他工具对其进行扩展。对 CNTR 的评估表明,该机制在数据中心广泛应用时,可以显着提高整体性能并有效减小镜像大小。

Secure Container: compromise security with high flexibility and performance.

同时,由于容器的隔离级别相对较低,虚拟化层的安全问题也随之而来。任何基于流程的解决方案都必须包括放松安全模型,因为它不能满足相互不信任的功能。在共享内核架构的情况下,它需要容器来防止代码漏洞。 Meltdown [84]、Zombieload [114]、Spectre [72] 等侧信道攻击提示了针对漏洞的缓解方法,特别是对于无服务器环境中的多租户。在这种情况下,容器隔离应该关注防止特权升级、信息和通信泄露侧通道 [3]。解决这个问题的最先进的解决方案是利用 Secure Container。例如,微软提出了他们的 Hyper-V Container for Windows [58]。 Hyper-V 提供增强的安全性和更广泛的兼容性。每个实例都在高度优化的 MicroVM 内运行,并且不与同一主机上的其他实例共享其内核。但是,它仍然是一个重量级的虚拟化,可以引入超过 1000 毫秒的启动延迟。在 Google gVisor [49] 中,其中的内核充当非特权进程来限制在用户空间中调用的系统调用。但是,在沙箱中拦截和处理系统调用期间引入的开销很高。因此,它不适合具有繁重系统调用的应用程序。为了以可承受的开销隔离不同的租户,FireCracker [3] 通过为云原生应用程序定制 VMM 来创建 MicroVM。每个 Firecracker 沙箱都在用户空间中运行,并受 Seccomp、Cgroup 和 Namespace 策略的限制。 Kata [67] 使用内置 MicroVM 的容器引擎,采用代理通过管理程序与位于主机上的 kata-proxy 进行通信,从而以轻量级的方式实现安全环境。 FireCracker 和 Kata 容器都可以显着降低启动延迟和内存消耗,并且它们都只需要 50ms-500ms 即可启动沙盒。借助安全容器,它可以提供与 HostOS 和其他租户的完整和强大的隔离,但代价是压缩的 MicroVM 的灵活性有限。同时,由于额外的应用程序初始化,例如 JVM 或 Python 解释器设置,它仍然会导致实例的启动延迟较长。

Specialized Unikernel: enhance flexibility with high security and performance.

另一种新兴的虚拟化技术称为 Unikernel [86],它利用 libraryOS,包括一系列必要的依赖库来构建专门的单地址空间机器映像。由于 Unikernel 作为内置的 GuestOS 运行,编译时不变性排除了运行时管理,这大大降低了 Unikernel 的适用性和灵活性。但是,不包含𝑙𝑠、𝑐𝑑、𝑡𝑎𝑟等不必要的程序或工具,因此 Unikernel 的图像大小更小(例如,从 Xen 编译的 mirage-skeleton [95] 为 2MB),启动延迟要小得多(例如,10ms 内启动),安全性比容器更重要。在此基础上,LightVM [90] 取代了耗时的 XenStore 并实现了拆分工具堆栈,将定期运行的功能与必须执行的功能分开,从而提高效率并减少 VM 启动延迟。从软件生态系统的角度来看,为了解决传统应用程序难以移植到 Unikernel 模型 [86, 113] 的挑战,Olivier 提出了 HermitTux [102],这是一个与 Linux 二进制文件兼容的 Unikernel 模型。 HermitTux 使 Unikernel 模型与 Linux 应用程序二进制接口兼容,同时保留了 Unikernel 的优点。然而,Unikernel 一旦构建就无法适应开发人员,这使得它对应用程序天生不灵活,更不用说糟糕的 DevOps 环境了。此外,在异构集群中,底层硬件的异构性迫使 Unikernel 随着驱动程序的变化而更新,这使其成为无服务器理念的对立面。

Tradeoffs among Security, performance, and flexibility.

最后,我们在图 3 中制作了这四种技术的指标图,以展示安全性、性能和灵活性之间的权衡。 总而言之,基于hypervisor的VM表现出更好的隔离性和灵活性,而容器可以使实例启动更快,更灵活地定制运行时环境。 Secure Container 提供高安全性和相对较低的启动延迟,同时兼顾灵活性。 Unikernel 在性能和安全性方面展示了巨大的潜力,但它失去了灵活性。

When offering adaptable images in the production environment by either virtualization mechanism, it is also critical to avoid that built ones are signed and originated from an unsafe pedigree, with the solutions [69, 128] by keeping continuous vulnerability assessment and remediation program.

3 ENCAPSULE LAYER

在Servverless中, 当Function的请求无法被暖实例捕获或者发生突发的负载时, 就会导致冷启动, 对于前者, 往往是第一次调用函数, 或者调用的间隔小于实例的生存周期. 典型的特征是实例必须要从头开始. 对于突发负载, 实例需要在用户工作负载激增期间执行水平扩展. 实例将随着负载的变化自动缩放, 一确保足够的资源分配. 除了在虚拟化层用不到一秒的时间准备一个沙箱, 还需要初始化软件的环境, 例如, Python库等, 而用户代码本身的执行时间和前者相比都会相形见绌. 虽然我们可以提供更轻量级的沙盒机制来减少虚拟化层的冷启动延迟,但当迁移到现有的无服务器架构时,最先进的沙盒机制可能无法完美兼容容器或虚拟机。为了应对性能和兼容性之间的权衡,一个有效的解决方案是在封装层中预热实例。这种方法被称为预热启动,已被广泛研究。表 2 列出了有关实例预热的代表性工作。

在给出详细的分析和比较之前,我们首先描述每一列的分类。 “模板”反映冷启动实例是否来自模板。 “静态镜像”显示用于预热的虚拟机/容器镜像是否在每次冷启动时禁用动态更新。 “Pool”表示是否有函数冷启动的预热池。 “Exclusive”和“Fixed-size”表示预热的实例及其预热池是否是独占的和固定大小的。 “Predict/Heuristic”指出是使用预测算法还是基于启发式的方法来预热实例。 “REQs”反映了运行时库和包是否在预热实例中动态加载和更新。 “C/R”反映是否支持checkpoint和restore加速启动。 “Sidecar based”代表相关技术是否可以实现或集成到sidecar中。 “Imp”表示它的实施位置。

有两种常见的预热启动方法:one-for-one预热启动和one-for-all预热启动。在一对一预热启动中,每个函数实例都从一个固定大小的池中预热,或者通过基于历史工作负载轨迹的动态预测进行预热。而在one-for-all预热启动中,所有函数的实例都是从缓存的沙箱中预热的,这些沙箱是根据一个通用的配置文件预先生成的。当发生冷启动时,该函数只需要通过导入特定于函数的代码 blob URI 和设置来专门化这些预先初始化的沙箱。为了更高的可扩展性和更低的实例初始化延迟,C/R(检查点/恢复)还与无服务器系统中的预热实例相结合。 C/R 是一种可以冻结正在运行的实例,将检查点制作成文件列表,然后在冻结点恢复实例的运行状态的技术。无服务器实现中的一个常见模式是在空闲时暂停实例以节省资源,然后在调用时将其恢复以重用 [55, 94]。

通过大小固定的池进行one-to-one的预热:有效但对资源不友好。

一对一策略会为每个函数预热实例,这意味着确定预热时间至关重要。 否则,缓慢或快速的预热周期要么会导致减少冷启动的效率降低,要么会导致不必要的预热实例浪费大量资源。 目前的解决方案是为每个功能建立一个固定大小的专有预热池,以最大限度地提高服务稳定性。 例如,Azure Functions [105] 通过设置一个固定大小的预热池来预热每个函数的实例。 一旦始终就绪的实例被占用,预热的实例将处于活动状态并继续缓冲直到达到限制。 开源的 Fission [44] 也像 Azure Function 一样预热。 它引入了一个名为𝑝𝑜𝑜𝑙𝑚𝑔𝑟的组件,该组件管理具有固定池大小的通用实例池,并将函数代码注入空闲实例以减少冷启动延迟。

通过预测性预热进行一对一暖启动:使资源友好的方法。

一对一策略预热每个大小固定的预热池中的独占实例,并在调用到达时加载代码。在这种模式下,这是一种安全策略,不会引入其他安全问题。但是,它会在后台产生大量的空闲实例,使 serverless 系统资源不友好。这种缺陷激发了研究人员提出更灵活的预热策略,例如使用基于预测和启发式的方法。徐等人。 [146] 通过利用 LSTM(长短期记忆)网络设计一种 AWU(自适应热身)(AWU)策略,以根据历史轨迹发现依赖关系。它预测每个函数的调用时间以预热实例,并在 AWU 失败时根据 ACPS(Adaptive Container Pool Scaling)策略初始化预热的容器。沙赫拉德等人。 [118] 为一对一的预热启动提出了一种实用的资源管理策略。通过表征 FaaS 工作负载,它们根据时间序列预测动态改变回收和供应实例的实例生命周期。 CRIU(用户空间中的检查点/恢复)[39] 是 Linux 上实现检查点/恢复功能的软件工具。 Replayable Execution [140] 在 CRIU 的基础上进行了改进,使用“mmap”将检查点文件映射到内存,并利用 OS 中的 Copy-on-Write 在多个容器之间共享冷数据。通过利用intensive-deflated执行特性,它减少了容器的冷启动时间和内存使用量。

有缓存感知的one-for-all预热:尝试在保证隐私的情况下使预热通用化和资源友好。

one-for-all 预热启动与 Template 方法共享类似的机制,在收到套接字通知后,它已被孵化并已预先导入大部分 bins/libs。当一个新的调用到达并需要一个新的实例时,它只需要从模板初始化或专门化。在上述过程中,Catalyzer [42] 通过加速缩减的关键路径上的恢复来优化 C/R 中的恢复过程。同时,它提出了一个s-fork,以利​​用已经预先加载了特定功能的模板沙箱进行状态恢复。为了使冷启动更少的初始化以及更平坦的启动延迟,Mohan 等 [97] 通过使用惰性暂停容器绑定预先分配虚拟网络接口,提出了一个自我进化的暂停容器池。随着性能的提高,漏洞也会出现。 one-for-all prewarm 策略中的安全问题通常被称为封装层中的隐私问题。换句话说,必须使私有包/库 (REQ) 不可访问。例如,著名的开源 Apache OpenWhisk [103] 通过允许用户可以在 ZIP 或 virtualenv 中分配私有包来动态专门化预热容器 [104] 来解决它。 Zygote 机制是 Android 中用于应用程序实例化的基于缓存的设计。 SOCK [101] 利用广义的 Zygote 机制,在创建预热容器时考虑工作负载的内部特征。具体来说,它设计了一个包感知缓存模型,以动态调整具有最高成本效益比的缓存包。因为它在系统级别使用运行时采样执行指标分配,所以恶意活动无法揭示特定功能的敏感包/库。

One-to-one and one-for-all prewarm: the challenging points.

对于one-to-one的预热启动和one-for-all的预热启动,两者都有利于优化无服务器架构封装层中的冷启动。 他们各自的缺陷也很明显。 one-to-one预热启动通过交换内存资源来显着减少初始化延迟。 根据研究 [118],它面临的挑战是,在确保内存资源合理分配的同时,通常很难测量或预测预热时间。 一方面,当历史数据足以建立准确的模型时,基于预测和启发式的方法特别有效,但在跟踪稀缺时会退化。 另一方面,当大量应用程序和功能链共存时,预测和迭代操作会引入高 CPU 开销。

采用one-for-all预热启动中的模板机制,缓解函数从零开始冷启动的高成本。 此外,与一对一的预热启动相比,维护全局预热池引入的额外内存资源消耗更少。 然而,它仍然面临着一些挑战,包括巨大的模板镜像大小 [8, 51] 和各种预导入库的冲突。 它还可能潜在地揭示具有类似镜像的应用程序被广泛部署的附近。 对于不同场景下的冷启动,“对症下药”非常重要。 例如,在第一次调用函数时,或者在跟踪分析期间预测不佳时,通过 one-for-all prewarm 启动生成模板效率更高。 一对一预热启动对于具有一般规则或昼夜模式的功能表现更好,反之亦然。

4 ORCHESTRATION LAYER

系统编排层的主要挑战是对不同服务的友好和弹性支持。尽管当前的无服务器编排器的实现方式不同,但它们在系统中遇到的挑战却大同小异。由于数百个函数在无服务器节点上共存,这给调度具有不可分割依赖关系的海量函数带来了挑战。与传统的解决方案 [26, 35, 59, 76, 126] 类似,无服务器模型也关注预测按需计算资源的能力以及服务的有效调度策略。如图 4 所示,研究人员通常建议将负载均衡器和资源监控组件引入控制器,以解决供应和调度挑战。负载均衡器旨在协调资源使用以避免任何单个资源过载。同时,资源监控器不断监视每个节点的资源利用率,并将更新的信息传递给负载均衡器。借助资源监视器和负载均衡器,无服务器控制器可以在资源级、实例级和应用级三个方面执行更好的调度策略。我们在表 3 中总结了层次结构。

对于表3, 具体来说:

  • “focused hierarchy”表示除了资源自动配置的基本策略外,还设计了一种优化方法(又称资源调整),可分为“R”(资源级)、“I”(实例级) ,或“A”(应用程序级)。
  • “Resource adjusting”显示调度是否提供资源供应的调整。 “
  • SLO”反映是否考虑 SLO 约束。
  • “Intf”表示是否讨论了资源争用或干扰。
  • “Usage feedback”反映了是否考虑物理节点中资源使用的反馈。
  • “Dynamic strategy”表示是否为动态和运行时调度策略。
  • “Trace driven”表示做出选择是否取决于跟踪或收集的数据指标。
  • “Predict/Heuristic”反映是使用基于预测还是基于启发式的方法。
  • “Implement”指出它是在哪里实现的(“P”表示它是一个原型)。
  • “Insight”总结了其独特的洞察力和关键动机。

5 ESSENTIAL BAAS COMPONENTS IN COORDINATION LAYER

6 PERFORMANCE AND COMPARISON

本节首先总结了无服务器计算中不同 VM/容器、语言运行时和资源限制的性能。 然后,我们分析当前的生产无服务器系统以显示偏好。

6.1 Performance Analysis

使用不同虚拟化技术构建的实例中的运行时可以表现出不同的冷启动性能。 此外,语言运行时是另一个严重影响冷启动延迟的因素。 例如,Catalyzer [42] 中的评估显示了不同 VM/容器和语言运行时的冷启动延迟。 如图 7 所示,HyperContainer 在各种语言运行时引入了最高的冷启动延迟。 基于进程的 Docker 运行时的性能肯定比其他运行时要好得多。 一般来说,解释型语言(例如 Python)在冷启动时会产生更高的初始成本,并且使启动时间比编译型语言(例如 C)慢 10 倍 [4, 101]。

然而,根据 Jackson [62] 的性能测试,测量不同语言运行时的启动和执行延迟,编译和解释语言运行时的性能也取决于平台。 例如,.NET C# 在 AWS Lambda 上的冷启动延迟高于 Node.js,而在 Azure Functions 上则相反。 这是因为 Azure Functions 将基于其核心技术 .NET 为微软提供更好的 C# 支持,并通过在 windows 容器上运行而不是基于 Linux 容器的开源 .NET CLR (Common Language Runtime) 来实现。

作为上述影响 serverless 冷启动性能的因素的补充,Shahrad 等人。 [117] 探讨了可能影响函数冷启动和执行时间的其他因素,例如 MKPI(每千指令的错误预测)、LLC(最后一级缓存)大小和内存带宽。首先,他们发现函数中的分支 MKPI 明显较低时,通常会出现较长的执行时间。我们很容易理解,执行时间短的函数大部分时间都花在语言运行时启动上,因此分支预测器在训练时会输出更多的未命中。其次,LLC 大小不是影响冷启动延迟和执行时间的重要因素。由于不敏感,较大的 LLC 大小无法为无服务器功能执行带来更好的性能。只有当 LLC 的大小非常小(例如小于 2M)时,才会成为函数执行和冷启动的瓶颈。云供应商通常在无服务器系统中设置默认的 LLC 大小和预配置文件,以避免严重的性能下降。 BabelFish [121] 还发现,惰性页表管理会导致容器化环境中的 TLB 压力过大。为了避免在页表管理过程中产生多余的内核作业,他们尝试在 TLB 和页表中的容器之间共享翻译。

6.2 Production Comparison

随着更多尝试使云原生应用程序的快速发展,Wang 等人。 [141] 通过调用具有逐步内存限制的测量函数来收集各种系统级指标来评估三个商业无服务器平台的性能。 李等人。 [77] 还详细比较了 Amazon Lambda、Google Functions、Microsoft Azure Functions 和 IBM OpenWhisk。 它们展示了吞吐量、网络带宽、I/O 容量和计算性能方面的差异。 基于这些实验,我们总结了表 4 中的指标。

从这张表中,我们可以一窥它们各自的优缺点。 例如,AWS Lambda 显示并发函数调用的容量和吞吐量更高,但在触发吞吐量方面表现不佳。 Microsoft Azure Functions 在顺序调用查询时能够实现快速的读写速度,并且表现出相对较高的函数冷启动延迟。 毫无疑问,所有云厂商都意识到了Serverless架构的挑战,都在积极优化函数调用性能和相关的BaaS瓶颈。

7 OTHER KEY LIMITATIONS AND CHALLENGES

当前工作在每一层的局限性和挑战已经在相应的章节中讨论过。 本节将分别强调封装、编排和协调层中的其他关键限制和挑战,作为正交补充。 我们推荐读者在其他调查 [13, 18] 中对虚拟化层进行更详细和集中的讨论。

7.1 Stateless within Encapsule Layer

从这张表中,我们可以一窥它们各自的优缺点。 例如,AWS Lambda 显示并发函数调用的容量和吞吐量更高,但在触发吞吐量方面表现不佳。 Microsoft Azure Functions 在顺序调用查询时能够实现快速的读写速度,并且表现出相对较高的函数冷启动延迟。 毫无疑问,所有云厂商都意识到了Serverless架构的挑战,都在积极优化函数调用性能和相关的BaaS瓶颈。

7.2 Memory Fragmentation within Orchestration Layer

在多个租户共存的无服务器架构中,并发调用要么在多个容器中处理并在每个容器中经历不希望的冷启动,要么在单个容器中并发执行(例如,OpenFaaS 和 OpenLambda)。在前者中,为了性能隔离,一个容器一次只能执行一个调用。在这种情况下,大量 Sidecar 的内存占用会阻止无服务器容器实现高密度部署和提高资源利用率 [3]。这一挑战的关键是通过 VMM 和来宾内核中的重复数据删除来精简和压缩容器运行时,例如在主机上的不同实例之间共享页面缓存。在后者中,内存碎片成为重中之重。图 10 描绘了可能出现内存碎片的两种常见情况。分配碎片通常是由于 microVM 的不正确提供造成的。函数执行器不能充分利用分配的内存。调度碎片是不可避免的,通常是由实例级负载平衡策略引起的,当自动扩展工作负载变化时。自从无服务器出现以来,在进一步实现一种有效的方法来指导如何搜索高密度容器部署解决方案方面仍然存在挑战。

7.3 API and Benchmark Lock-in within Coordination Layer

当人们谈论无服务器供应商锁定时,他们关心的是功能的可移植性。然而,这个问题的真正意义在于来自其他服务的 API,而不是函数本身。尽管 Apex [10] 和 Sparta [123] 等一些努力允许用户以本机不支持的语言将功能部署到无服务器平台,但来自不同平台的 BaaS 服务及其 API 定义仍然不同。 API 锁定的挑战源于用户功能与其他 BaaS 组件之间的紧密耦合,这会增加不同 FaaS 平台之间的代码迁移难度。

过度简化的基准测试是 API 锁定的另一个问题。易于构建的微基准被过分强调并用于当前工作的 75% [110]。除了科学工作流[64,89,119],我们呼吁建立和开源跨平台的真实世界应用程序基准。然而,在将大型服务分解为不同功能,然后构建细粒度节点互连时,应用架构的复杂性使得功能的分级难以指导和确定。

8 OPPORTUNITIES IN SERVERLESS COMPUTING

最后,我们讨论了无服务器计算面临的一些未来机遇,并对解决方案进行了一些初步的、建设性的探索。

8.1 Application-Level Optimization

应用程序级优化需要在应用程序内的不同功能之间进行协调,而不是专注于每个通用功能。 数据依赖和调用者-被调用者关系等复杂的互连可能隐藏在函数之间。 未来的工作可以通过两种方式实现应用级优化:工作流支持和工作流调度。 工作流支持是指对功能间互联互通的一般支持。 我们认为以下支持是必要的:

  • 更好的存储。 在某些情况下,函数需要相互交换大型临时文件。 如果我们注册中间存储,存储和函数之间的传输将占用大部分 I/O 资源并显着减慢响应速度。 这种后果在无服务器工作流场景中更加严重。 因此,更好的存储要求应用程序内功能之间的元数据交换具有更高的优先级。
  • 更高的并行能力。 在视频处理的示例中,可以以 MapReduce 方式同时调用多个重新编码实例以加快转码速度。 显然,并行性在优化端到端延迟方面具有巨大潜力。 然而,由于对物理节点资源利用管理的考虑,更高的并行度很难实现。 如果无服务器系统可以提供卓越的并行性和可持续的资源开销,它可以进一步增强用户的能力。 例如,无服务器系统允许在保证 QoS 的情况下在一个实例内同时调用多个查询,或者优化来宾内核、容器运行时和 cgroup,以在高并发和高密度场景下实现更轻的虚拟化。

工作流调度推动了一种考虑功能互连的调度策略。 我们认为当前工作中缺少以下考虑:

  • 调用者-被调用者关系。 调用者-被调用者关系在复杂的应用程序中很常见。 通常,被调用者将在调用者完成后被调用,如图 11(a) 所示。 它为研究人员提供了一个探索的机会:系统可以通过数据流架构预热函数实例并使用部分数据提前执行它们。 如图 11(b) 所示,由于数据依赖而不是函数状态依赖,函数 B、C 可以在函数 A 未完成时更早开始执行。 在提供具有数据流规范模式的优化接口并直接应用于功能的情况下,云供应商可以使应用程序通过数据管道实现更高的并行度和更低的响应延迟。
  • 数据局部性。我们已经提到元数据交换可能会在应用程序中的功能之间不断发生。 如果两个具有数据依赖的函数调度在同一个物理节点上,通过中间件可以显着减少数据传输。 但是,目前的 serverless 系统是一种数据传送架构,将数据发送到代码节点进行解析,而不是发送代码到数据节点。 因此,一方面,无服务器系统不能保证存储的数据和调度的工作人员正好在同一个物理节点上。 另一方面,出于安全和隐私的考虑,还应避免频繁的代码传输。 改善数据局部性可以有效地将应用程序设计从数据传输架构转变为代码传输架构[54]。

Robust Performance of Cold Startup Alleviation

当前的工作通常使用预测方法来减少冷启动,而它们都需要函数的历史跟踪或系统级指标。通过预测在不久的将来,系统将扩大容器池或预热模板容器。尽管如此,每个功能都收集足够的数据并建立准确的预测模型是不切实际的。就像 Shahrad [118] 在 Azure 跟踪中显示的那样,大约 40% 和 30% 的注册函数和应用程序每天被调用不到 10 次。这一事实也使得为此类服务定期收集系统级信息变得更具挑战性。例如,基于 LRU 的模板可以最大化热点函数启动的缓存命中,而非热函数的冷启动无法从系统级别的缓存更新中受益。目前对这种差异的妥协是使用保留的容器池来执行功能,尽管会浪费大量资源。

探索对性能具有很强的鲁棒性的热身策略至关重要,特别是对于偶尔触发或对延迟敏感的功能。它要求无服务器控制器和负载均衡器更通用,以减轻冷启动或减少性能下降。他们可以根据函数内部的信息,如服务类别、使用的环境库、上下文图等信息做出决策,进行冷启动预测和缓解。例如,Serverless 系统可以为同类别的函数构建共享镜像和模板容器,或者将函数打包成类似的环境配置,并实现更细粒度的内部隔离机制。

8.3 Accelerators in Serverless

GPU 和 FPGA 等加速器广泛用于数据库 [36, 53] 和图形处理 [37, 156] 等许多应用中。它们可以显着加快特定任务的处理速度,例如图像处理和机器学习应用程序。为了满足对加速器的需求,云供应商以 IaaS(例如 AWS EC2 P4 和 F1 实例)和 SaaS(例如 AWS SageMaker)的方式提供加速器。然而,这种加速器的不灵活性阻碍了无服务器计算的实例化。这种情况导致了两个障碍:(1)它使加速器在云中的使用变得不那么方便和灵活; (2) 限制了 serverless 可以支持的应用范围。我们认为无服务器中的多路复用加速器是解决这些障碍的关键。例如,一些作品 [98, 150] 将 GPU 集成到无服务器系统中,而 BlastFunction [14] 使 FPGA 在无服务器中可用。然而,目前的作品仍然不足。我们认为未来的研究可以集中在以下几点:

  • Accelerator-aware scheduling. 加速器也可以被视为无服务器系统中的资源,除了它们比其他加速器具有更多不可替代的特性。延迟感知调度和按需扩展在加速器上的成本更高,这会刺激无服务器控制器对加速器进行区别对待。在这种情况下,在一个加速器上调度多个任务时,调度策略应该更加保守。
  • Accelerator virtualization. 虚拟化是应用在无服务器系统中的一项基本技术。用于实现运行时环境管理、资源隔离和高安全性。但是,就 CPU 虚拟化而言,没有探索无服务器加速器方案。它使加速器很难集成到无服务器系统中。因此,为了更好地支持 serverless 中的加速器,应该进一步探索加速器虚拟化。
  • Automatic batching. 加速器通常有很强的 I/O 带宽限制。批量查询是克服这些限制并充分利用加速器计算能力的常用操作。但是,批处理操作会将冗余引入端到端延迟。因此,在未来的研究中应该研究一种平衡利用率和延迟的无服务器批处理策略。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注