核心思想是协同利用VM级别的snapshot和runtime级别的JIT compilation。
Fireworks利用JIT的无服务器功能代码来减少函数的启动时间和执行时间,并通过共享JIT的代码来提高内存效率。此外,Fireworks还可以通过使用虚拟机作为沙盒来执行无服务器函数,从而提供高度的隔离性。
Background and Motivation
Characteristics of a Serverless Workload
- Short function execution time
- High consolidation in a server
- Memory efficiency
Optimizing Serverless Platforms 对比的平台
- Firecracker
- OpenWhisk
- gVisor
- Cloudflare Workers
- Catalyzer
Design
Design Overview
一共两个阶段
- installation phase
- 发信号给Firecracker,创建一个microVM
- 将源代码添加注释
- 调用函数,函数自己完成JIT。在entry point前创造一个snapshot
- invocation phase
- 当函数被调用后,setup a network for the microVM
- restart VM snapshot
- 读参数并正常执行
三个优点
高隔离度。Fireworks在一个单独的虚拟机(即Firecracker中的microVM)中运行每个虚拟服务器的功能,与使用容器或运行时作为沙盒的方法相比,提供了一个高隔离度。
高性能。Fireworks通过即时启动和JIT化的功能执行实现了高性能。 从本质上讲,Fireworks使用的是一个微虚拟机快照,它是在函数被加载和JIT化之后创建的。 由于JIT编译的代码比解释器更快,而且我们不需要在运行时支付JIT编译的成本,所以无服务器函数的执行时间大大减少。
内存效率。无服务器函数的多个实例可以以写时复制(CoW)的方式共享虚拟机级的内存快照。 Fireworks对快照使用私有映射(即MAP_PRIVATE),因此,如果没有变化,它就共享客体物理页;否则,它就依靠写时拷贝。 因此,快照共享microVM、操作系统、库、运行时,甚至JIT化代码的状态。只有在无服务器函数执行期间更新的特定参数执行状态不会被共享。
Automatic Source Code Annotation
Figure 3说的比较清楚了。
Python Numba对带有@jit(cache=True)的函数全部进行JIT编译。
Creating a post-JIT VM snapshot
Fireworks使用Firecracker API。然后Firecracker创建整个microVM的内存快照,并将快照存储在一个文件中。
Invoking a serverless function
当用户向无服务器函数发送请求时,Fireworks将请求的信息放入参数传递者队列,并向Firecracker管理程序请求恢复MicroVM。
一个microVM会以相应的快照图像重新启动。因此,调用无服务器函数只不过是把快照作为一个文件加载到内存中而已。
Fireworks在JIT化后的虚拟机快照镜像创建后立即恢复执行。
在恢复快照之前,Fireworks会配置网络并准备好参数传递,这样恢复后的微虚拟机就可以访问网络并获取所请求的函数的参数。
Enabling Network Connectivity
假设基于同一快照的多个microVM被启动。在这种情况下,microVM将有网络资源冲突--即每个从同一快照恢复的microVM将有相同的IP地址和MAC地址。
为了解决这个网络连接问题,Fireworks使用网络命名空间和网络地址转换(NAT)
Taking Serverless Function Arguments
Fireworks利用Kafka队列--一个软件消息总线--来向无服务器函数传递参数。