论文笔记:No Provisioned Concurrency: Fast RDMA-codesigned Remote Fork for Serverless Computing 中
接上篇 -> 地址:论文笔记 (上)
4 The MITOSIS Operating System Primitive
机会:内核空间RDMA
远程直接内存访问(RDMA)是一种在数据中心广泛部署的快速网络功能[112,47,43]。尽管通常在用户空间中使用,RDMA进一步使内核能够绕过远程CPU(即,单面RDMA read)读取/写入远程机器的物理内存[112],具有低延迟(例如,2µs)和高带宽(400 Gbps)。
方法:用RDMA模仿fork
MITOSIS通过使用RDMA模仿本地分叉实现了高效的远程分叉。首先,我们将父级的元数据(例如,页表)复制到一个精简的描述符(§5.1)中,以派生子级(❶). 注意,与C/R不同,我们不会将父级的内存页复制到描述符中。然后通过RDMA将描述符复制到子级,以恢复父级的元数据,类似于本地fork中的copy_process(❷). 在执行期间,我们配置孩子的远程内存访问以触发页面错误,内核将相应地读取远程页面。故障处理程序以按需模式自然触发,从而避免传递整个容器状态。同时,MITOSIS直接使用单侧RDMA READ读取远程物理内存(❸), 避免所有软件开销。
结构
我们的目标是一个去中心化架构,每台机器都可以从其他机器分叉,反之亦然。请注意,我们不需要专用资源(例如固定内存)来分叉容器,因此,非服务器应用程序可以与MITOSIS一起运行。我们通过向内核添加四个组件来实现MITOSIS(见图6):fork协调器 fork orchestrator 排练远程fork执行(§5.1和5.2)。网络守护程序 network daemon 管理一个可扩展的RDMA连接池(§5.3),用于内核之间的通信。我们扩展了OS的 虚拟内存子系统 virtual memory
subsystems,以利用RDMA的远程内存(§5.4)。最后,回退守护程序 fallback daemon provides 提供RPC处理程序,以恢复无法利用RDMA进行的罕见远程内存访问。
安全模型
我们保留容器的安全模型,即操作系统和硬件(RNIC)是可信的,而恶意容器(功能)可能存在。
4.1挑战和方法
高效且可扩展的RDMA连接设置
尽管RDMA速度很快(例如,2µs),但传统上仅在面向连接的传输(RC)中支持,因为连接建立速度要慢得多(例如,4毫秒[11],连接/秒吞吐量有限)。缓存到其他计算机的连接可以缓解此问题,但当支持RDMA的集群已扩展到10000多个节点时,这是不切实际的[43]。我们改进了DCT[1],这是一种未充分利用但得到广泛支持的高级RDMA功能,具有快速且可扩展的连接设置,以在内核之间进行通信(§5.3)。
高效的远程物理内存控制
MITOSIS将父级的物理内存暴露给子级,以获得最快的远程分叉。然而,这种方法在角落情况下引入了一致性问题。如果操作系统更改了父级的虚拟-物理映射[77、80、78、79](例如,交换[78]),则子级将读取不正确的页面。用户空间RDMA可以使用 内存寄存器 memory registration(MR)[92]进行访问控制。然而,MR具有非平凡的注册开销[49]。此外,内核空间RDMA对MR的支持有限,它仅支持RCQP上的MR(使用FRMR[89])。
我们提出了一种 无寄存器 内存控制 方法(§5.4),将RNIC的内存检查转换为连接许可检查。我们通过利用DCT的可扩展连接设置特性进一步提高了检查的效率。
父容器生命周期管理
为了正确,我们必须确保一个分叉的容器(父容器)在其所有后续容器(包括从子容器分叉的子容器)完成之前都是有效的。一种简单的方法是让每台机器跟踪其托管父代的继任者的生命周期。然而,这将带来巨大的管理负担:父代的继任者可能跨越多台机器,形成分布式叉树。同时,每台机器可能有多棵树。因此,每台机器都需要与树中的其他路径进行广泛的通信,以确保可以安全地回收父级。
为此,我们将生命周期管理加载到无服务器平台(§6.3)。观察到,无服务器协调器(通过fork调用函数的节点)自然地维护了分叉容器的运行时信息。因此,他们可以轻而易举地决定何时收回父节点。
5 Design and Implementation
为了简单起见,我们首先假设一跳 fork(即,没有级联),然后扩展到多跳叉(见§5.5)。
API
我们将fork分解为两个阶段(参见图7):用户可以首先调用fork_prepare来生成与远程fork相关的父级元数据(称为描述符)。描述符由本地唯一的handle_id和key(由准备好的调用生成并返回)以及父级机器的RDMA地址全局标识。给定标识符后,用户可以在另一台机器上通过fork_resume启动一个子机器(可以与父机器相同,即本地fork)。
与传统的单阶段fork系统调用相比,两阶段fork API(准备和恢复)-类似于缓存中的暂停和取消暂停-对于无服务器计算更为灵活。例如,在协调器处准备并记录父计算机的标识符之后,它可以稍后启动子计算机,而无需与父计算机通信。
父级数据结构的可见性
默认情况下,MITOSIS在fork-prepare之后向子级公开父级的所有数据结构,包括虚拟内存和文件描述符。MITOSIS可以引入API,让应用程序限制暴露范围,但目前,我们发现这是不必要的:父母必须信任孩子,因为他们来自同一个应用程序。
5.1 Fork prepare
fork_prepare 将生成捕获父状态的本地内存数据结构(容器描述符),其中包含(1)用于容器化的cgroup配置和命名空间标志,(2)用于恢复执行状态的CPU寄存器值,(3)用于恢复虚拟内存的页表和虚拟内存区域(VMA),以及(4)用于恢复I/O的打开文件信息。我们遵循本地fork(例如,Linux的copy_process())来捕获(1)–(3)和CRIU[7](4)。由于决定何时回收去脚本器很有挑战性,除非无服务器平台明确释放它们(即通过 fork_reclaim),否则我们始终保持已准备好的父级(及其描述符)有效。尽管描述符扮演着与C/R检查点文件类似的角色,但我们强调了一个关键区别:描述符只存储页表,而不存储内存页。因此,它的数量级更小(KB比MB),生成和传输速度更快。
5.2 Fork resume
fork_resume通过获取父描述符,然后从中恢复来恢复父的执行状态。现在我们将描述如何快速完成上述两个步骤。目前,我们假设子OS已经建立了能够向父OS发出RPC和单向RDMA的网络连接。下一节介绍连接设置
使用单侧RDMA快速获取描述符
获取描述符的一个简单实现是使用RPC。然而,RPC的内存复制开销不是微不足道的(见图18),因为中等大小容器的描述符可能会消耗几个KB。理想的获取是使用一个单侧RDMA READ,这需要(1)将父级的描述符存储到一个连续的内存区域中,以及(2)提前通知子级的OS内存的地址和大小
第一个要求可以通过将描述符序列化为井格式消息来实现。由于描述符的数据结构简单,数据序列化几乎没有成本(毫秒级)。对于第二个要求,一个简单的解决方案是在描述符标识符(例如handler_id)中编码内存信息,该标识符直接传递给恢复系统调用。然而,这种方法是不安全的,因为恶意用户可能会传递错误的ID,导致孩子读取并使用错误的描述符。我们采用了一个简单的解决方案来解决这个问题:MITOSIS将发送一个身份验证RPC,用描述符标识符查询描述符内存信息。如果身份验证通过,父级将发送回描述符存储的地址和有效负载,以便子级可以直接使用单边RDMA读取它。我们选择了一个简单的设计,因为额外的RPC(几个字节)的开销通常可以忽略不计:读取描述符(几个KB)将占据获取时间。
使用通用精简容器快速恢复
对于获取的描述符,子OS使用以下两个步骤将子OS恢复到父OS的执行状态:(1)容器化:设置cgroups和命名空间以匹配父OS的设置;(2) 切换:将调用方的CPU寄存器、页表和I/O描述符替换为父级的。该开关效率很高(以毫秒为单位完成):它只是初始化本地分叉,例如,取消映射调用方的当前内存映射,并通过将父级的页表复制到子级来将子级的虚拟内存映射到父级。另一方面,由于设置cgroups和命名空间的成本,容器化可能需要几十毫秒。
幸运的是,快速容器化得到了很好的研究[93,17,27,109]。例如,SOCK[93]引入了精益*(lean)*容器,这是一种特殊的容器,具有无服务器计算所需的最小配置。它还使用池来隐藏容器引导的成本,将其时间从几十毫秒减少到几毫秒。我们将SOCK的精益容器推广到分布式设置,以加速远程分叉的容器化。具体来说,在恢复远程父级之前,我们将使用SOCK创建一个满足父级隔离要求的空精益容器。然后,空容器调用MITOSIS以恢复执行。由于容器已正确配置了SOCK,我们可以跳过昂贵的集容器化。
5.3 Network daemon 网络守护程序
网络守护程序旨在降低在远程分叉的关键路径上创建RDMA连接(通常称为RCQP)的成本。同时,它还避免缓存连接到所有服务器的RCQP以节省内存
解决方案:改装高级RDMA传输(DCT)
目标背后的基本要求是我们需要QP无连接。RDMA确实提供了无连接传输不可靠数据报 unreliable datagram (UD),但它只支持消息传递,因此我们可以将其用于RPC。
我们发现动态连接传输 dynamic connected transport(DCT)[1]——一种研究较少但得到广泛支持的RDMA特性很适合远程分叉。DCT保留了RC的功能,并进一步提供了一种无连接的错觉:单个DCQP可以与不同的节点通信。目标节点只需要创建DC目标,该目标由节点的RDMA地址和12B DC密钥7标识。在知道密钥后,子节点可以在没有连接的情况下向相应的目标发送单边RDMA请求。硬件将通过数据处理附带连接,速度极快(在1µs内[11,67]),如图8所示
基于DCT,网络守护程序管理一个小的内核空间DCQP池,用于处理来自子级的RDMA请求。通常,每个CPU一个DCQP足以利用RDMA[11]。然而,单独使用DCT是不够的,因为孩子需要提前知道DCT密钥才能与家长沟通。因此,我们还实现了一个内核空间FaSST RPC[67]来引导DCT。FaSST是一种基于UD的RPC,支持无连接。使用RPC,我们在RPC请求中携带与父级关联的DCT密钥,以查询父级的描述符。为了节省CPU资源,我们只部署两个内核线程来处理RPC,这对于我们的工作负载来说已经足够了(见图13(b))
关于DCT开销的讨论
由于额外的重新连接消息,DCT存在已知的性能问题。与RC相比,对于小型(32B)单侧RDMA READ,其性能下降高达55.3%[67]。然而,重新连接对大型(例如,超过1KB)传输没有影响,因为传输数据占据了时间[11]。由于MITOSIS的工作负载模式主要由大型传输(例如,以4KB粒度读取远程页面)控制,我们根据经验发现,该问题没有影响。
5.4 RDMA-Aware virtual memory management
为了提高恢复效率,我们在恢复阶段直接将子级映射页面的页面表条目(PTE)设置为父级的物理地址(PA)。然而,原始操作系统不知道PTE中的远程PA。因此,我们在PTE中指定了一个远程位用于区分。特别地,OS将在恢复阶段的切换过程中将远程位设置为1并清除PTE的当前位。
之后,孩子的远程页面访问将在切换后被困在内核中。因此,MITOSIS可以在RDMA感知页面错误处理程序中处理它们。请注意,我们没有更改表条目数据结构:我们使用一个被忽略的PTE位(即[58:52][60]中的一个)作为远程位。
RDMA感知页面错误处理程序
表2总结了我们如何处理与远程分叉相关的不同错误。如果错误页面没有映射到父级,例如,堆栈增长,我们会像处理正常页面错误一样在本地处理它。否则,我们检查故障虚拟地址(VA)是否具有映射的远程PA。如果是,我们使用单侧RDMA将远程页面读取到本地页面。大多数子页面都可以通过RDMA恢复,因为无服务器功能通常会触及上一次运行的子集[117,37]。如果缺少映射,我们将回退到RPC。
回退守护程序
每个节点都托管一个回退守护进程,该守护进程产生内核线程来处理子节点的分页请求,其中包含父节点标识符和请求的虚拟地址。回退逻辑很简单:在检查
如果请求有效,守护程序线程将代表父级加载页面。如果加载成功,我们将把结果发送回孩子。
基于连接的内存访问控制和隔离
直接暴露父级的物理内存可以提高远程分叉速度。然而,我们需要拒绝对不再属于父级的映射页面的访问,并适当隔离对不同容器的访问。由于我们以CPU旁路的方式通过单侧RDMA暴露内存,因此我们只能利用RNIC进行控制。
MITOSIS提出了一种基于连接的存储器访问控制方法。具体而言,我们将不同的RDMA连接分配给父虚拟内存区域(VMA)的不同部分,例如,每个VMA一个连接。如果映射的物理页不再属于父页,我们将销毁与该页的VMA相关的连接。因此,RNIC将拒绝孩子访问该页面。这些连接都在内核中进行管理,以防止恶意用户访问错误的远程容器内存。
为了实现基于连接的访问控制,每个连接必须在创建和存储方面高效。幸运的是,DCQP很好地满足了这些要求。在子端,每个连接(DC密钥)仅消耗12B——不同的DC连接可以共享相同的DCQP。同时,父方DC目标消耗144B。注意,创建DCQP和目标也有开销。然而,它们在逻辑上独立于父母的记忆。因此,我们使用池来摊销它们的创建时间(几毫秒)。
图9显示了正在运行的基于DCT的访问控制。在准备分叉时,MITOSIS将从目标池中选择的一个DC目标分配给每个父VMA。池在启动时初始化,并定期在后台填充。这些目标的DC密钥附带在父级描述符中,以便子级可以在恢复期间将其记录在VMA中。在读取父级页面时,子级将使用与该页面的VMA相对应的密钥来发出RDMA请求。使用此方案,如果用户想要拒绝对此页面的访问,则可以销毁相应的DC目标。
基于连接的控制具有误报 false positives :在破坏VMA分配的目标后,所有对它的远程访问都被拒绝。以更细粒度的方式分配DC目标(例如,每个VMA分配多个目标)可以以增加内存使用为代价来缓解问题。我们发现这是不必要的,因为父母的VA–PA变化很少。例如,如果操作系统有足够的内存,则不会发生交换
安全分析
与普通容器相比,MITOSIS还通过RDMA将其物理内存暴露给远程机器。然而,由于远程容器必须利用其内核来读取暴露的内存,因此恶意容器无法读取其他状态,只要其内核没有受到损害。除此之外,RDMA的固有安全问题[108,97,121]也可能危及有丝分裂症。虽然此类安全威胁不在我们的工作范围内,但可以集成正交解决方案[108,97,121,112]来提高MITOSIS的安全性。
优化:预取和缓存
即使使用RDMA,读取远程页面仍然比本地内存访问慢得多[35](3µs vs.100 ns)。因此,我们应用了两种标准优化:在出现页面错误时,预取会预取相邻的远程页面。根据经验,我们发现预取大小为1足以以对运行时内存的较小成本提高远程分叉的性能(见图15)。因此,默认情况下,MITOSIS只预取一个相邻页面。缓存在内核中缓存已完成的子页面表(和已读取的页面)。随后,派生同一父级的子级可以以写时复制的方式重用页表,以避免再次读取被触摸的页。这本质上是本地远程分叉的组合。为了避免额外的内存开销,我们只在短时间(通常几秒)内保持缓存页表以应对负载峰值(例如,请参见图1)。
5.5支持多跳远程分叉
MITOSIS支持多跳分叉:孩子可以在第三台机器上再次分叉。它类似于一跳分叉,只是我们需要以细粒度的方式进一步跟踪远程页面的所有权。如图10所示,data[1]和data[0]后面的页面位于两台不同的机器上。一个简单的方法是维护一个地图来跟踪每个虚拟页面的所有者。然而,这将消耗非平凡的存储开销。为了减少内存使用,MITOSIS在PTE中对所有者进行编码:我们在PTE的忽略位中指定4位来编码支持最多15跳远程分叉(最多15个祖先)的远程页面机器
未完待更………………