最新进展:Serverless 冷启动优化技术
Serverless 计算也称服务器无感知计算或函数计算,是近年来一种新兴的云计算编程模式。其致力于大幅简化云业务开发流程,使得应用开发者从繁杂的服务器运维工作中解放出来(例如自动伸缩、日志和监控等)。借助 Serverless 计算,开发者仅需上传业务代码并进行简单的资源配置便可实现服务的快速构建部署,云服务商则按照函数服务调用量和实际资源使用收费,从而帮助用户实现业务的快速交付 (fast built & Relia. Deliv.) 和低成本运行。
在当前阶段,业界公认的 Serverless 计算的准确定义应该为“FaaS+BaaS”,即 Function-as-a-Service 同 Backend-as-a-service 的组合。Serverless 计算改变了用户使用云的方式,为了实现细粒度的资源供给和高度弹性的扩缩容能力,Serverless 计算提供了无状态函数的编程抽象,即将用户的应用程序构建为多个无状态的函数集合,并通过中间存储、BaaS 等业务组件交互,继而构建完整的云应用。
然而,Serverless 计算的无状态函数编程在带来高度弹性和灵活性的同时,也导致了不可避免的冷启动问题。由于函数通常在执行完请求后被释放,当请求到达时,如果没有可用实例则需要从零开始启动新的实例处理请求(即冷启动)。当冷启动调用发生时,Serverless 平台需要执行实例调度、镜像分发、实例创建、资源配置、运行环境初始化以及代码加载等一系列操作,这一过程引发的时延通常可达请求实际执行时间的数倍。相对于冷启动调用,热调用(即请求到达时有可用实例)的准备时间可以控制在亚毫秒级。
在特定领域例如 AI 推理场景,冷启动调用导致的高时延问题则更为突出,例如,使用 TensorFlow 框架的启动以及读取和加载模型可能需要消耗数秒或数十秒。
因此,如何缓解 Serverless 函数的冷启动问题,改善函数性能是当前 Serverless 领域面临的主要挑战之一。
从研究思路上看,目前工业界和学术界主要从两个方面入手解决冷启动问题:
-
加快实例启动速度:当冷启动调用发生时,通过加速实例的初始化过程来减少启动时延。
-
降低冷启动发生率:通过函数预热、复用或实例共享等方法提高实例的利用效率,减少冷启动调用的发生。
在本篇文章中,我们首先从提高实例启动速度方面介绍下业界的前沿进展。
提高实例启动速度当冷启动发生时,Serverless 平台内部实例的初始化过程可以划分为准备和加载两个阶段。其中,准备阶段主要包括控制面决策调度 / 镜像获取、Runtime 运行时初始化、应用数据 / 代码传输几个部分。而加载阶段位于实例内部,包括用户应用框架和代码的初始化过程。在工业界和学术界公开的研究成果中,针对实例启动过程中的每个阶段都有大量的技术手段和优化方法。如下图所示,经过优化,实例冷启动的准备阶段和加载阶段时间可被极大地缩短。
下面列举了一些近年来发表在计算机系统领域知名会议的相关工作,主要可以分为五个方面:
-
调度优化 / 镜像快速分发 / 本地池化:例如利用文件级镜像缓存复用机制和并行化镜像构建技术,加快容器构建速度 FAST-BUILD [MSST'19];阿里云基于树结构的跨节点快速镜像分发 FaasNet [ATC'21];AWS 基于 Block 和分布式多级缓存的镜像分发策略 [Arxiv'23];Pod 池 + 特化实例跳过镜像传输 [华为云 FunctionGraph]。其中,快速镜像分发依赖于 VM 节点的上 / 下行网络带宽,Pod 池特化技术则是典型的以空间换时间的做法。
-
轻量级虚拟化 / 安全容器:例如针对传统容器 Docker 的精简优化工作 SOCK [ATC'21];更侧重安全性的轻量级虚拟化技术(Kata Containers, gVisor 等);基于安全容器的进一步的精简优化工作 (Catalyzer [ASPLOS'20], REAP[ASPLOS'21])。通过裁剪优化,安全容器的启动时延最快可以被压缩至亚毫秒级。
-
数据共享 / 跨节点传输优化:例如基于 RDMA 共享内存减少跨节点启动过程的数据拷贝 RemoteFork [OSDI'23];或者利用本地代码缓存跳过代码传输 [华为 FunctionGraph, 字节 ByteFaaS 等]。基于 RDMA 技术的跨节点数据传输时延可降低至微妙级。
-
用户代码精简 / 快速加载:例如针对 Java 语言的 JVM(Java Virtual Machine)运行时优化技术 [FunctionGraph];以及针对 Python 运行时库的裁剪优化工作 FaasLight [arxiv'23]。通过特定的优化,JVM 启动时间可由数秒降低至数十毫秒,而 Python 代码的启动加载时延可降低约 1/3。
-
其它非容器运行时技术:例如 WASM(即 WebAssembly)技术以及针对 WASM 的内存隔离方面的优化工作 Faasm [ATC'20]。相比容器化技术,直接以进程和线程方式组织运行函数,可在保证低开销函数运行的同时具备高度灵活性。
接下来,针对上述 5 个方面的优化工作进行详细介绍。
镜像压缩 / 快速分发 / 本地池化-
快速请求 / 实例调度。
在 Serverless 场景下,由于函数的体积更小、动态性更高,Serverless 平台在负载高峰时也会面临较大压力。因此主流的 Serverless 服务商通常采用“大小流区分的负载均衡 + 本地优先调度”的设计来实现请求的快速分发,降低调度时延。即在流量较小的时候,采用工作负载聚合的方式来分发请求,减少集群资源使用;在流量较大的时候,通过一致性 hash 或轮询等方法将请求快速映射到后端节点,从而降低排队时延。这种“自顶向下”的调度设计简单,易于实现,但是在超大规模的函数并发场景下仍可能面临顶层控制器的性能瓶颈问题,因此,根据实际场景架构适当地探索“自下而上”的调度框架设计将有助于缓解该问题。
此外,也有相关研究人员提出可将 Serverless 集群划分为多个小型的 worker 池,每个 worker 池由一个单独的 semi-global 子调度器管理,降低各个调度器的压力,从而改善调度时延[1] 。
-
镜像压缩与快速分发。
在 Serverless 平台中,用户的函数镜像通常被存储在 cluster-level 的镜像仓库,节点(通常指虚拟机 Virtual Machine, 简称 VM)创建实例时首先需要将镜像文件通过网络传输到对应的节点(1 个 100MB 的镜像文件从传输到容器创建完成需要耗费约 20 秒 [阿里云,Borg])。在这个过程中,影响镜像传输时延的因素主要为镜像体积和节点网络带宽。因此,Serverless 平台通常会采用镜像压缩技术缩小镜像体积,例如开源工具 fastfreeze[2] 。除此之外,为了解决节点网络带宽受限导致的拉取镜像时间过长的问题,阿里云的 FaasNet[29] 工作提出了一种基于树状网络的跨节点镜像分发策略,即通过根节点的 VM 将镜像下发给子节点(通常为 2),子节点获取到镜像后以同样方式扩展到更多的节点,从而充分利用节点的上 / 下行带宽实现短时间内快速扩容大量实例的目的。
此外,在节点中设立镜像缓存也是一种有效的方法,可以在一定程度上减少镜像传输操作,例如 AWS Lambda 采用了一种基于 Block 的镜像切分和缓存方法[30],相比于基于 Layer 的镜像构建方法,基于 Block 的镜像切分粒度更细,可以极大地提高镜像复用度,同时这些镜像 Block 被存储在由本地缓存,分布式缓存和 S3 组成的三级缓存系统中,从而实现快速镜像分发和实例创建速度。
-
Pod 池与实例特化。
类似于本地镜像缓存的概念,在集群中预留包含函数运行时基础镜像的实例(即具备用户代码运行环境的热容器)也是一种常用的“以时间换空间”的做法[3]。这种方法在集群中建立 Pod 池,预先启动一定数量的具有不同资源规格和语言运行时的实例(例如 Java, Nodejs, Python 等)。当冷启动调用发生时,Serverless 平台可以快速从 Pod 池中取出所需要的实例进行特化(挂载代码文件并加载执行),从而跳过镜像获取和运行时环境启动阶段,实现快速创建实例的目的。
生产环境下的数据测算显示,Node.js 实例特化时的启动时间仅需 15ms。然而,在 Pod 池中预留实例会占用大量集群资源,增加云供应商的服务成本。如何权衡用户函数性能和 Pod 池预留成本也是该类方法所面临的一个问题。
轻量级虚拟化 / 安全容器加速-
传统容器加速。
相比于传统的 VM 动辄数十秒至数分钟的创建时间,容器的启动速度和运行时开销更小,因此 Serverless 平台通常使用容器技术来隔离用户的函数实例,例如 Docker[4] 。然而在考虑函数的实际运行性能时,Docker 之类的传统容器设计包含了很多不必要的运行开销,因此并不适合直接作为函数沙盒环境。为此,SOCK 工作[5] 基于 Linux container 的设计分析了 Docker 文件系统和网络模块的性能瓶颈,通过裁剪不必要的启动项并对网络模块进行特定优化,大幅降低了 Docker 容器的内核扩展开销(超过 18 倍)。
-
兼顾安全性的轻量化容器或 microVM。
在非 Serverless 的云场景中,VM 的强安全隔离性使其在云租户的服务部署中扮演着重要角色。在 Serverless 场景中,租户函数间的安全隔离性也同样重要。为了弥补传统容器的安全性不足的问题,研究学者尝试将 VM 的高安全性同容器技术进行融合,例如 Intel 和 HyperHQ 团队主导的 Kata Containers 项目[6] ,Kata Containers 的本质是一个精简后的轻量级虚拟机,在其上面运行着用户的容器进程。为了减少暴露给容器进程的攻击面,Kata Containers 基于传统的虚拟化技术通过硬件虚拟出一个 microVM,而 microVM 里则运行了一个裁剪后的 Linux 内核来实现进程间的强隔离( 注:裁剪即屏蔽掉非必须的系统调用接口)。AWS Lambda 的 Firecracker[7] 也采用了类似 microVM 的技术路线来实现多租户隔离性和函数性能间的权衡。
除此之外,gVisor[8] 则是谷歌推出的轻量级安全容器项目。gVisor 采用了另一条技术路线,其核心原理是给容器进程配置一个类似“Guest Kernel”的极小的“独立内核”(即守护进程),通过拦截容器进程的系统调用来向宿主机 OS 发起有限的、可控的系统调用,从而提高系统安全性。由于这个独立内核运行在用户态,免去了大量地址空间转换和内核态切换的操作,因此具有较小的性能开销和更好的灵活性,同时又达到了将容器和宿主机 OS(Operation System)隔离的目的。
无论是 Kata Containers 类容器技术,还是 gVisor 安全容器技术,它们实现安全容器的方法在本质上是殊途同归的。这两种技术都采用了“系统分层”的设计思想,即向容器进程分配了一个独立的“操作系统内核”,从而避免了让租户的容器直接共享宿主机的内核。这样,容器进程的攻击面就从整个宿主机内核变成了一个极小的、独立的、以容器为单位的内核,从而有效解决了容器进程发生“逃逸”或者夺取整个宿主机控制权限的问题。
-
针对安全容器的进一步加速。
尽管 gVisor 之类的安全容器极大地弥补了传统容器的安全隔离性不足的问题,然而,安全性提高的同时也带来了额外的性能损失,例如拦截调用会增大启动和运行开销。为此,Catalyzer[9] 基于快照技术和状态重用技术针对 gVisor 安全容器的启动过程进行了进一步优化,大幅缩短了 gVisor 的启动时间。Catalyzer 的设计思想是“避免从零开始启动”,即通过检查点和快照恢复机制跳过启动过程关键路径上的初始化(零初始化),从而实现快速启动的目的。此外,Catalyzer 还提出了一个新的操作系统原语 sfork 技术,通过直接重用正在运行的沙箱实例的状态来进一步减少启动延迟。评估表明,Catalyzer 在最佳情况下可将 gVisor 的启动延迟降低至<1ms。
值得注意的是,尽管 Catalyzer 实现了“用户角度”的快速启动,但是其并不能保证内部所有的系统状态都为最新可用状态,为此,Catalyzer 采用了按需加载机制作为补救措施,即通过在后续运行过程中逐步恢复用户级内存状态和系统状态来最终恢复函数性能。该领域的另一项研究工作 REAP[10] 发现 Catalyzer 的设计机制带来的开销并不是可忽略的,运行过程中频繁的系统缺页在最坏的情况下会导致时延提高接近一倍。为此,REAP 提出了一种页面预加载机制,通过识别函数运行过程中所需的必要工作集并提前载入内存,从而显著改善了 Catalyzer 的缺页开销问题。
注:该部分涉及的一些术语可以参考 扩展知识部分进行了解。
数据共享 / 传输优化-
基于 RDMA 的跨节点分发。
在 Serverless 平台内部,借助网络进行跨节点数据、代码或者状态的传输也是一个较为耗时的操作,尤其是在大量实例并发创建的场景中,远程容器初始化的频繁需求进一步加剧了这种现象。为了解决该问题,MITOSIS[11] 工作在支持 RDMA 的操作系统中实现了一个新的操作系统原语,即 remote fork,remote fork 允许不同节点的操作系统之间通过 RDMA 技术进行内存共享映射,从而实现快速远程内存读取和跨节点容器间的数据传输。MITOSIS 可以大幅降低跨节点的实例初始化时间,从单个实例跨节点复制 10,000 个新实例的时间小于 1 秒。然而,MITOSIS 的实现涉及对操作系统内核代码的大量修改,同时还依赖于 RDMA 硬件的支持,这些都使得它在实际部署中会面临着挑战。
除此之外,新型网络设备例如 DPU 硬件等也提供了基于 RDMA 的高速跨节点互联的机制,即通过内存映射和共享来加快网络数据传输速度,这些硬件都可以被探索用于改善 Serverless 平台跨节点数据传输的效率。
代码加载延迟优化前面章节提到的加速技术都集中在系统层和框架层,在应用层,容器运行时环境的启动和函数代码的加载也在冷启动延迟中占据了相当的比例,尤其是对于机器学习等应用,运行库的加载和框架的启动时间可达数秒[12]。值得注意的是,即便调度时延和容器初始化时间再短,长的用户侧启动时延仍然会使得冷启动问题变得棘手。
为此,Serverless 平台通常会针对函数的运行时进行优化,例如华为的 FunctionGraph 内部针对 JVM 的优化技术可将简单 Java 应用的初始化时间降低至数十毫秒。在学术研究领域,也有针对 Python 函数运行时库的裁剪优化工作例如 FaasLight[13],FaasLight 的核心思想是“在函数启动过程中尽可能地只加载少量运行必需的代码”。为了实现这一目标,FaaSLight 构建了函数级调用图来识别和筛选与应用程序功能相关的代码,并对非强相关的代码(即可选代码)进行按需加载,避免必要代码识别不准确导致应用失败。实验结果显示 FaaSLight 可最高降低 78% 的 Python 代码加载延迟,平均延迟降低约 28%。
非容器化运行时技术-
WASM 运行时。
WSAM(即 WebAssembly)[14]技术也是近年来一种新兴的编程运行时,可以用在云场景中代替部分容器运行时来部署用户函数。WSAM 的运行原理类似于 JVM,可直接运行在宿主机 OS 上,其支持多种语言编码,用户函数代码在运行前需要编译成 WASM 运行时,继而实现跨平台运行。WASM 同样提供了高性能沙盒环境,并具备高灵活性和一定的安全性。
尽管 WASM 有诸多优势,但是也存在着诸如内存隔离性弱这样的问题,因此并不能完全替代现有的容器技术,而是在大多数情况下与 Docker 容器技术互相配合使用。据悉,基于 WASM 的函数计算平台目前在国内著名的云计算厂商内部都有布局,有的平台已经推出了初步的商用版本。
在研究领域,也有针对 WASM 的内存隔离性开展优化的工作,例如 Faasm[15]。Faasm 提出了一个新的隔离抽象“faaslets”,并基于 WebAssembly 的 software-default isolation (SFI) 机制实现了函数间的内存隔离。此外,在 faaslets 的设计中,来自不同租户的多个函数可共享相同的内存地址空间,这样就可以避免函数间通信时大量的数据交换所导致的性能开销。faaslets 还可以与 Linux cgroups 机制配合使用,继而实现例如 CPU, 网络资源等资源的隔离。这些优化措施可以使得 Faasm 获得接近 2 倍的性能加速同时降低内存使用 10 倍以上。
值得注意的是,上述的这些技术手段,无论是容器技术、VM 技术还是 WASM 技术,它们本质上都是以进程方式运行在服务器内部,因此都可以借助快照技术(例如 Linux CRIU[16])实现更快的系统状态保存和恢复,从而进一步加快初始化速度。
-
Unikernal 技术。
从前面列举的一些技术的特征可以看到,函数运行环境的启动速度和安全性之间总是存在一个折中,即为了改善安全性必须添加一些中间层来增强系统的控制能力,然而中间层的引入势必会降低系统启动速度。那么是否存在能够同时满足快速启动和高安全性的技术方案呢?答案就是 Unikernel[17]。Unikernel 顾名思义,是指定制化的操作系统内核。它的核心思想是将“用户程序和运行必需的库文件统一编译成为一个特殊的、单地址空间的内核镜像”。由于只有一个操作系统进程(这里不再有用户态和内核态的区分),同时编译时去掉了不必要的运行库,所以 Unikernel 运行速度可以非常快。如果将 Unikernel 加载到 VM 运行,也可以实现高安全性和隔离性。
但是 Unikernel 的缺点也十分明显,即灵活性差。由于 Unikernel 是与某种语言紧密相关的,所以一个 Unikernel 只能用一种语言编写,如果用户程序有所变动,则需要重新编译 Unikernel,之后加载并重启 VM。同时,Unikernel 的编码门槛也很高,这与 Serverless 计算的简化编程的设计初衷相悖,也是其难以被广泛应用的原因之一。
扩展知识介绍:
传统裸金属、VM 和容器技术的区别(在体系结构中所处的层级图、用户态和内核态概念)
在计算机的体系结构中,各种物理设备例如 CPU 处理器、磁盘、网卡等首先组成计算机的物理硬件,也成为“裸金属服务器”。裸金属服务器的运行需要操作系统的支持,比如我们熟知的 Linux 操作系统。借助操作系统就可以编写运行各种软件例如网页服务器、数据库等来提供外部服务。
在云计算场景中,通过虚拟机共享资源是早期云服务商的主要做法。借助虚拟化技术例如 Microsoft hyper-V、Citrix Xen 等,可以将裸金属服务器虚拟为多个单独的 VM,VM 间共享裸金属服务器(也称宿主机)的物理资源,但是在每个 VM 内对租户来说是独占资源的(例如 CPU,内存和磁盘)。实现这一目的的手段就是借助 Hypervisor(即虚拟机监视器)来管理划分各个 VM 使用的物理资源,实现高安全性和隔离性。Hypervisor 的内部比较复杂,涉及到系统调用、物理地址划分等操作,这里不再展开。
在 Hypervisor 划分出来的每个 VM 内部都可以运行一个独立的操作系统(也称 Guest OS),相比于 VM,宿主机的操作系统则称为 Host OS。Guest OS 对于租户来讲是一个类似本机的操作系统,包含运行程序所需要的各种系统调用库和可执行文件,具体的层级划分如左侧子图所示。
容器则是相比 VM 更为轻量级的虚拟化技术,例如 Linux Container(LXC)和基于 LXC 实现的 Docker 等技术(右侧子图所示)。容器的本质是一个用户态进程,因此它可以直接运行在 Host OS 上,我们称之为 Container Engine。Container Engine 可以创建出多个容器给租户使用,并通过 Linux cgroups 等机制实现 namespace 和租户资源(例如 CPU 和内存)的隔离。不同于 VM 的运作方式,容器内部并没有 Guest OS,而是复用底层的宿主机的操作系统,通过创建文件系统和加载用户程序运行所需要的库来实现运作。因此,相比 VM 来讲,容器的运行方式更加轻便灵活,但是安全性较差(例如某个租户的程序可能导致宿主机 OS 被攻击,继而使得其他租户的程序也无法运行)。为了解决这个问题,早期的云厂商做法通常是将容器部署在 VM 中,从而实现安全性和灵活性的折中取舍。
注:操作系统通常运行在内核态,权限最高,而租户程序则运行在用户态。用户态程序执行系统调用需要切换至内核态,执行完后再切换回用户态。
VM、容器和 Unikernel 对比 (灵活性,启动速度和隔离性)
前面我们提到,Serverless 平台中函数运行的技术路线有 VM,容器和 Unikernal 几种或是它们的组合。无论哪种方式,基本都在围绕技术方案的灵活性(Flexibility),启动速度(Startup Latency)和隔离性(Isolation Level)进行权衡。
下图总结并列出了这几种虚拟化方案的对比:
可以看到,VM 具有高隔离性,灵活性较好,但是启动速度最慢。
而传统容器以用户态进程运行,具有高度灵活性,较快的启动速度,但是隔离性较差。
安全容器是针对传统容器进行了裁剪和进一步控制,具有较高的隔离性,但是启动速度和灵活性有所降低。
WASM 技术类似 JVM 的设计理念,编译完成后即可运行,因此具有更快的启动速度和较高的灵活性,但是隔离性较差。
Unikernel 采用了定制化 OS 和单地址空间,因此可以兼顾快的启动速度和高隔离性,但是灵活性很差。
不难发现,这三个要素的关系非常类似于分布式系统的 CAP 原理,即一致性 (Consistency),可用性 (Availability) 和分区容忍性 (Partitiontolerance) 在分布式系统中最多只能同时实现两点,不可能三者兼顾。
下表展示了各虚拟化技术的启动延迟等指标的具体对比:
注:表格数据引用出处 The serverless computing survey[31]。
小结在实际场景中,不同的函数计算厂商往往有自己的虚拟化技术方案,往往根据自家产品的业务线,技术积累或者客户群体需求进行综合考虑。在出于商业意图或者个人需要搭建函数计算平台进行研究时,可以根据安全性需求制定自己的技术路线。例如个人或者高校团体研究可以归类为非安全性场景,基于目前的"VM+Kuberneters (k8s)+Docker+runtime 优化"技术栈就可以实现一个可用版本,其中 VM 可以提供资源强隔离性,基于多个 VM 节点组建 k8s 集群,函数计算框架例如 OpenWhisk 或 OpenFaaS 可以依托 k8s 进行部署。尽管同一个 VM 内的多租户共享会导致面临一定的安全隐患,但对于实验环境来说是足够的。
在注重租户间隔离性和强调安全的场景下,AWS Lambda 采用的“裸金属 +Hypervisor+microVM+ 容器”技术路线通过 microVM 实现强隔离性,并且 VM 内一般只允许部署同一个租户的函数来提高安全性。而谷歌采用的“裸金属 +Hypervisor+VM+gVisor”则是另一种技术方案,Hypervisor 和 VM 负责提供硬件虚拟化及资源强隔离性,安全性则由 gVisor 提供。其中,Firecracker 和 gVisor 均已开源。
讨论:VM 在每种技术方案都属于必需品的地位,但是这样势必会导致高开销的存在。那么能不能采用“裸金属 + 轻量级 Hypervisor+Host OS+ 安全容器”或者直接“裸金属 +Host OS+ 安全容器”的技术方案减少中间层的存在呢?其实这种方式并非不可以,比如剑桥大学就提出了 CHERI[18] 指令集扩展从而实现在硬件层面进行内存隔离,通过卸载掉虚拟化软件的部分职责,使得 Hypervisor“变薄”。尽管这项工作只基于模拟器进行了实现,但是也验证了未来更轻量化的 Serverless 计算底座的可行性。
降低冷启动发生率在文章的上半部分,我们主要介绍了如何加速函数实例初始化过程的一些技术方案,包括通过优化调度和镜像分发策略,采用更轻量级的虚拟化技术,或者借助 RDMA 硬件改善跨节点数据传输等方法,尽管这些方法已经可以将实例运行时环境的初始化的时间压缩至数十毫秒甚至是数毫秒,然而用户侧的延迟却仍然存在,例如程序状态的恢复,变量或者配置文件的重新初始化,相关库和框架的启动。具体来讲,在机器学习应用中,TensorFlow 框架的启动过程往往需要花费数秒,即使实例运行时环境的启动时间再短,应用整体的冷启动时延对用户而言依然是无法接受的(注:通常大于 200ms 的时延可被用户察觉)。
在这种情况下,可以从另一个角度入手解决冷启动问题,即降低冷启动调用的发生率。例如,通过缓存完整的函数实例,请求到达时可以快速恢复并处理请求,从而实现近乎零的初始化时延(例如 Docker unpause 操作时延小于 0.5ms)。
降低冷启动发生率的相关研究可以分为如下几个方面:
-
实例保活 / 实例预留:例如基于 Time-to-Live 的 keepalive 保活机制 [AWS Lambda, OpenWhisk];或者通过并发配置接口预留一定数量的实例 [AWS Labmda 等];这些方法原理简单,易于实现,但是在面对负载变化时缓存效率较低。
-
基于负载特征学习的动态缓存:例如基于请求到达间隔预测的动态缓存方案 Serverless in the Wild [ASPLOS'20];学习长短期负载变化特征的动态缓存方案 INFless [ASPLOS'22];基于优先级的可替换缓存策略 FaasCache [ATC'21];面向异构服务器集群的低成本缓存方案 IceBreaker [ASPLOS'22]。这些动态缓存方案根据负载特征学习决定实例缓存数量或时长,从而在降低冷启动调用率的同时改善缓存资源消耗。
-
优化请求分发提高命中率:例如兼顾节点负载和本地化执行的请求调度算法 CH-RLU [HPDC'22]。通过权衡节点负载压力和缓存实例的命中率来对请求的分发规则进行优化设计,避免节点负载过高导致性能下降,同时兼顾冷启动率。
-
改善并发 / 实例共享或复用:例如允许同一函数工作流的多个函数共享 Sandbox 环境 SAND [ATC'18];使用进程或线程编排多个函数到单个实例中运行 Faastlane [ATC'21];提高实例并发处理能力减少实例创建 Fifer [Middle'20]; 允许租户复用其它函数的空闲实例减少冷启动时间 Pagurus [ATC'22]。这些实例共享或者复用技术可以同缓存方案结合使用,降低冷启动带来的性能影响。
接下来,针对上述 4 个方面的研究工作进行详细介绍。
实例保活 / 实例预留-
实例并发设置和预留。
商用的 Serverless 平台例如 AWS Lambda[19]、华为云 FunctionGraph[20]都内置了 Time-to-live 实例保活机制即 keepalive 方法。其原理是将执行完请求的实例内存中保活一段时间再释放。如果保活期间有新的请求到达,则可以立即执行并重置剩余的保活时间。除此之外,云服务器通常会向用户提供实例并发设置的接口,用户在部署函数后可以设置预留一定数量的实例(需额外支付费用),从而降低由于突发负载导致的冷启动调用率。然而,这类静态的缓存方法易于实现,但是实例预留数量或保活时长难以根据负载变化进行实时调整,从而导致性能下降或者资源超分浪费。
基于负载特征学习的动态缓存
-
基于直方图统计的动态实例缓存。
微软的研究团队通过分析 Azure 的生产环境 trace,发现请求的到达间隔普遍分布在秒级、数分钟乃至数小时,基于 Time-to-live 的静态保活策略会导致大量的资源浪费。因此,作者提出了基于混合直方图的策略来统计函数请求的调用间隔,并根据这些信息动态的释放或提前拉取函数实例,从而在减少冷启动调用率的同时减少 Serverless 平台内部的缓存资源浪费[21] 。然而,这套设计方案只针对 0-1 的函数扩缩场景进行了评估,因为它只控制实例的缓存时长,而无法感知实例数量的变化,如何将这套机制运用在 1- 多的实例扩缩场景中还面临着一些挑战。
-
基于长短期直方图的动态实例缓存。
直方图策略通过生成函数请求到达间隔的分布来决定缓存实例的何时创建和缓存时长,然而,在初期历史统计数据不足或者负载发生短期突变的场景下,得到的直方图分布往往会不具有代表性,从而导致缓存策略的实际效果下降。为了解决该问题,INFless[22] 提出了一个长短期结合的混合直方图策略来改善预测精度,通过分别统计长期的直方图分布特征和短期的直方图分布特征,来共同决定缓存实例的创建时间点和保活时长,从而改善缓存效率(冷启动率 / 缓存资源成本)。
-
基于优先级的可替换缓存策略。
无论是 Time-to-live 的 keepalive 还是基于直方图的动态缓存方案,都是倾向于减少缓存资源的消耗,从而降低函数服务提供商的运营成本。然而,FaasCache [23] 的作者认为函数计算集群的内存资源与其与闲置,不如用来缓存更多的函数实例,从而最大程度地降低冷启动调用发生率。为此,FaasCache 借鉴了 CPU 缓存的替换算法,通过函数的最近访问时间,函数内存消耗以及冷启动时长为每个实例定义优先级。请求执行结束后的函数实例都会被长期缓存在节点中,仅当节点无可用资源时才驱逐较低优先级的实例来缓存新的函数。此外,FaasCache 还设计了一个反馈控制机制来调整缓存容量的大小,通过权衡冷启动率和缓存资源成本来实现较好的缓存效率。
面向异构集群的低成本缓存策略。
云服务供应商通常会提供多种具有不同 CPU 型号的服务器给租户使用,这些 VM 的处理能力和价格有所差异。IceBreaker[24] 针对异构函数计算集群设计了一个成本优先的缓存策略,其核心思想是“可以使用价格更为便宜的低端服务器缓存冷启动开销较低的函数,从而节省总体成本”。为了实现该目的,IceBreaker 基于傅里叶变化预测函数的负载到达率,并结合实例的使用率和节点加速前亲和性来决定将函数缓存在高端服务器,低端服务器或者不进行缓存,从而以损失部分函数性能的代价降低整体缓存消耗的资源成本。
优化请求分发提高缓存命中率此外,还有一些工作通过优化或重新设计 Serverless 平台的请求分发策略来改善函数实例的命中率,从而改善缓存效率。在 Serverless 平台内部,前端组件收到请求后,通常以 hash 或负载均衡的策略分发到后端节点进行处理。将同一函数的请求分发到相对固定的节点可以有效地提高节点内实例的使用率(即缓存命中率),这也称为缓存的本地性原理。但是,由于函数负载中通常存在大量的热点函数,当热点函数聚集在后端节点时,则可能导致节点资源使负载压力升高,从而引发性能下降。
因此,CH-RLU[25] 工作提出了一个负载感知的请求调度策略,作者基于一致性 Hash 的分发规则在调度过程中考虑后端节点的压力,通过将高负载的函数分发到不同的节点来避免局部热点, 从而缓解资源竞争导致的函数性能下降问题。可以看到,优化负载分发的研究工作可以同现有的缓存方案结合使用,通过协同设计可以进一步改善 Serverless 平台的缓存效率。
改善并发 / 实例共享或复用-
多函数共享 Sandbox。
SAND[26] 工作在函数工作流场景下提出了一种多函数共享实例 Sandbox 的方案,它允许同一个函数工作流内的不同函数共享同样的 Sandbox 环境,从而减少请求执行时创建的函数实例数量,这将有助于减少请求调用的冷启动发生率。然而,这在实际场景中也有很多局限性,例如租户的多个函数可能由不同的语言运行时编写,这些函数往往无法从实例共享中获益。此外,多个函数共享 Sandbox 会增加实例的体积,而工作流中的函数可能被多条路径所调用,在函数扩容时则会导致不必要的资源浪费。
-
进 / 线程混合的函数编排。
传统的函数实例以容器为单位,每个函数运行在一个单独的容器实例内部,容器间的数据传输需要借助网络或第三方存储实现,以 AWS S3 为例,通过 S3 进行函数间数据交换会导致较高时延。为了改善函数实例间的通信效率,Faastlane[27] 工作提出了一个新的函数编排组织方式,即将工作流中的不同函数以进程或线程的形式在容器实例中执行,同时采用 IPC 进程间通信来提高函数交互效率。对于包含敏感数据操作的函数工作流,Faastlane 使用英特尔内存保护密钥 (MPK) 提供轻量级线程级隔离域。在 Apache OpenWhisk 上的评测结果表明,Faastlane 可以将函数工作流的处理时间降低 15 倍,并将函数间的交互延迟减少 99.95%。
-
提高实例并发处理能力。
在 Serverless 平台中,函数实例通常被配置较少的资源容量,例如内存以 128MB 为单位递增,而 CPU 的配额同内存大小成比例。当请求到达后,平台通常以“一对一”的请求 - 实例映射方式处理请求。低的实例并发处理能力可能导致 Serverless 平台在面临突发负载时创建出大量的实例,不仅降低函数的服务性能,也会增加系统调度压力。为了解决该问题,Fifer [12] 工作提出了一种支持多并发处理的函数实例运行方案,通过为实例分配多个独立的 CPU 处理线程来提高实例的吞吐。同时,通过计算实例的排队延迟,并发处理数和未来请求到达率来提前预置对应数量的实例,从而减少冷启动调用的产生。
-
允许租户间实例抢占 / 复用。
通常 Serverless 平台中的租户函数运行在单独的实例中,不同函数间的实例有独立的资源配置和运行环境。由于不同租户的函数可能具有相同的运行时语言环境,而租户的函数实例也不一定在同一时间都处于忙碌状态,因此,Pagurus[28] 工作另辟蹊径,设计了一个类似“寄居蟹”的租户间实例复用机制,其核心思想是“当 A 租户函数的冷启动发生时,可以迅速抢占 B 租户的空闲实例的运行时环境,从而减少冷启动的时延”,通过实例抢占和复用,从而避免冷启动发生时从零启动的长时延问题。同时,可以看到该做法同 Pod 池特化技术有异曲同工之妙。
小结可以看到,改善实例的并发能力或是通过实例共享 / 复用都是为了提高已有实例的利用效率,而缓存的方案则是尽可能利用少的资源来预置更多的实例,从而降低冷启动调用的产生。上述这些方法从不同的角度缓解 Serverless 函数冷启动的问题,可以结合使用来改善缓存效率。
在主动缓存的方案中,由于突发流量或者负载的无规律性,基于负载预测来进行缓存还存在较大难度。在实际场景中,通过主动预测 + 优先级缓存调整来实现缓存方案将更有潜力。受限于各家函数计算平台内部的架构,函数共享实例或者抢占复用的实施成本较高,因此开发人员通常会选择更加易于实现的缓存方案例如预热池来改善服务质量。
总 结Serverless 的无状态设计赋予了函数计算高度弹性化的扩展能力,然而也带来了难以避免的冷启动问题。消除 Serverless 函数的冷启动开销还是从降低函数冷启动率和加速实例启动过程两个角度综合入手。
对于冷启动开销比较大的函数,在函数计算框架的设计机制中进行优化,尽量避免冷启动发生;当冷启动发生时,采用一系列启动加速技术来缩短整个过程进行补救。在 Serverless 平台的内部,冷启动的管理在实践中可以做进一步精细的划分,例如针对 VIP 大客户、针对有规律的负载,或是针对冷启动开销小的函数,通过分类做定制化、有目的的管理可以进一步改善系统效率。
在未来,基于 WASM+ 进程 fork 的技术可能会有助于彻底消除冷启动问题,但是考虑到实际可用性和安全性等问题,短期内的结果可能也是 WASM 和 Container-based 函数并存的折中方案,互相取长补短,因此在当前阶段研究冷启动问题还是有较大价值的。
参考文献
[1] Arjun Singhvi, Kevin Houck, Arjun Balasubramanian, Mohammed Danish Shaikh, Shivaram Venkataraman, Aditya Akella. Archipelago: A Scalable Low-Latency Serverless Platform. arXiv:1911.09849, 2019.
[2] Fastfreeze. https://github.com/twosigma/fastfreeze. 2023.
[3] 刘方明, 李林峰, 王磊. 华为 Serverless 核心技术与实践 [M]. 北京: 电子工业出版社, 2021.11.
[4] Docker. https://www.docker.com/. 2023.
[5] Edward Oakes, Leon Yang, Dennis Zhou, Kevin Houck, Tyler Harter, Andrea C. Arpaci-Dusseau, Remzi H. Arpaci-Dusseau: SOCK: Rapid Task Provisioning with Serverless-Optimized Containers. USENIX Annual Technical Conference 2018: 57-70.
[6] Kata Containers. https://katacontainers.io/. 2023.
[7] Alexandru Agache, Marc Brooker, Alexandra Iordache, Anthony Liguori, Rolf Neugebauer, Phil Piwonka, Diana-Maria Popa: Firecracker: Lightweight Virtualization for Serverless Applications. NSDI 2020: 419-434.
[8] Open-sourcing gVisor, a sandboxed contaienr runtime. https://github.com/google/gvisor. 2023.
[9] Dong Du, Tianyi Yu, Yubin Xia, Binyu Zang, Guanglu Yan, Chenggang Qin, Qixuan Wu, Haibo Chen: Catalyzer: Sub-millisecond Startup for Serverless Computing with Initialization-less Booting. ASPLOS 2020: 467-481.
[10] Dmitrii Ustiugov, Plamen Petrov, Marios Kogias, Edouard Bugnion, Boris Grot: Benchmarking, analysis, and optimization of serverless function snapshots. ASPLOS 2021: 559-572.
[11] Xingda Wei, Fangming Lu, Tianxia Wang, Jinyu Gu, Yuhan Yang, Rong Chen, Haibo Chen. No Provisioned Concurrency: Fast RDMA-codesigned Remote Fork for Serverless Computing. OSDI 2023.
[12] Jashwant Raj Gunasekaran, Prashanth Thinakaran, Nachiappan Chidambaram Nachiappan, Mahmut Taylan Kandemir, Chita R. Das. Fifer: Tackling Resource Underutilization in the Serverless Era. Middleware 2020: 280-295.
[13] Xuanzhe Liu, Jinfeng Wen, Zhenpeng Chen, Ding Li, Junkai Chen, Yi Liu, Haoyu Wang, Xin Jin. FaaSLight: General Application-Level Cold-Start Latency Optimization for Function-as-a-Service in Serverless Computing. arXiv:2207.08175. 2022.
[14] WebAssembly. https://webassembly.org. 2023.
[15] Simon Shillaker, Peter R. Pietzuch: Faasm: Lightweight Isolation for Efficient Stateful Serverless Computing. USENIX Annual Technical Conference 2020: 419-433.
[16] Linux CRIU, stands for checkpoint and resotre in userspace. https://github.com/checkpoint-restore/criu. 2023.
[17] Anil Madhavapeddy, Richard Mortier, Charalampos Rotsos, David J. Scott, Balraj Singh, Thomas Gazagnaire, Steven Smith, Steven Hand, Jon Crowcroft: Unikernels: library operating systems for the cloud. ASPLOS 2013: 461-472.
[18] Robert N. M. Watson, Jonathan Woodruff, Peter G. Neumann, Simon W. Moore, Jonathan Anderson, David Chisnall, Nirav H. Dave, Brooks Davis, Khilan Gudka, Ben Laurie, Steven J. Murdoch, Robert M. Norton, Michael Roe, Stacey D. Son, Munraj Vadera: CHERI: A Hybrid Capability-System Architecture for Scalable Software Compartmentalization. IEEE Symposium on Security and Privacy 2015: 20-37.
[19] AWS Lambda. https://aws.amazon.com/lambda/. 2023.
[20] 华为云 FunctionGraph. https://www.huaweicloud.com/product/functiongraph.html. 2023.
[21] Mohammad Shahrad, Rodrigo Fonseca, Iñigo Goiri, Gohar Chaudhry, Paul Batum, Jason Cooke, Eduardo Laureano, Colby Tresness, Mark Russinovich, Ricardo Bianchini: Serverless in the Wild: Characterizing and Optimizing the Serverless Workload at a Large Cloud Provider. USENIX Annual Technical Conference 2020: 205-218.
[22] Yanan Yang, Laiping Zhao, Yiming Li, Huanyu Zhang, Jie Li, Mingyang Zhao, Xingzhen Chen, Keqiu Li: INFless: a native serverless system for low-latency, high-throughput inference. ASPLOS 2022: 768-781.
[23] Alexander Fuerst, Prateek Sharma: FaasCache: keeping serverless computing alive with greedy-dual caching. ASPLOS 2021: 386-400.
[24] Rohan Basu Roy, Tirthak Patel, Devesh Tiwari: IceBreaker: warming serverless functions better with heterogeneity. ASPLOS 2022: 753-767.
[25]Alexander Fuerst, Prateek Sharma: Locality-aware Load-Balancing For Serverless Clusters. HPDC 2022: 227-239.
[26] Istemi Ekin Akkus, Ruichuan Chen, Ivica Rimac, Manuel Stein, Klaus Satzke, Andre Beck, Paarijaat Aditya, Volker Hilt: SAND: Towards High-Performance Serverless Computing. USENIX Annual Technical Conference 2018: 923-935.
[27] Swaroop Kotni, Ajay Nayak, Vinod Ganapathy, Arkaprava Basu: Faastlane: Accelerating Function-as-a-Service Workflows. USENIX Annual Technical Conference 2021: 805-820.
[28] Zijun Li, Quan Chen, Minyi Guo: Pagurus: Eliminating Cold Startup in Serverless Computing with Inter-Action Container Sharing. USENIX Annual Technical Conference 2022.
[29] Ao Wang, Shuai Chang, Huangshi Tian, Hongqi Wang, Haoran Yang, Huiba Li, Rui Du, Yue Cheng: FaaSNet: Scalable and Fast Provisioning of Custom Serverless Container Runtimes at Alibaba Cloud Function Compute. USENIX Annual Technical Conference 2021: 443-457.
[30] Marc Brooker, Mike Danilov, Chris Greenwood, Phil Piwonka: On-demand Container Loading in AWS Lambda. CoRR abs/2305.13162 (2023).
[31] Zijun Li, Linsong Guo, Jiagan Cheng, Quan Chen, Bingsheng He, Minyi Guo: The Serverless Computing Survey: A Technical Primer for Design Architecture. ACM Comput. Surv. 54(10s): 220:1-220:34 (2022).
点击底部 阅读原文访问 InfoQ 官网,获取更多精彩内容!
今日好文推荐 OpenAI 遭遇离职潮:员工对 ChatGPT 进展缓慢失望,痛批 CEO 不务正业
阿里改革,P8 成为历史;GPT-4 模型架构泄露;OpenAI 面临最严调查,Altman 惊慌连发 3 推|Q 资讯
甲骨文火上浇油、SUSE投入1000万美元,多方“围剿”红帽:“红帽负担不起?那我们来!”