问题
随着网络带宽(最高400Gbps)和IOPS(每秒一百万次)的增加,CPU的性能一直相对停滞不前,并成为主要瓶颈。
为了节省CPU资源,最近的系统(例如盘古[37]、Snap[34]、FaRM[14,15]、MICA[31]、RAMCloud[40]等)采用了内核旁路来消除内核开销并实现裸机硬件性能。将硬件设备映射到用户空间,并广泛使用运行到完成(RTC)模型来运行应用程序逻辑。与此同时,云应用程序(如微服务、无服务器等)通常被打包到共享集群中(即工作负载整合),使延迟关键应用程序(L-apps)未使用的CPU周期能够被尽力而为的应用程序(B-apps)所利用。
其他系统,如Shenango[39]、Caladan[17,35]和Arachne[42],使用用户空间核心调度器将应用程序托管在同一台机器上。具体来说,为每个应用程序授予一组专用的内核,在应用程序内的内核之间执行负载平衡,并在应用程序之间进行细粒度的内核重分配。虽然比Linux调度程序性能有巨大提升,但为平均服务时间为1-2秒的短任务(对于Memcached[9]和Redis[4]等数据中心应用程序来说是典型的)或密集托管应用程序提供服务时,仍然会浪费大量的CPU周期。
挑战
为了优化CPU性能,目标是让CPU核在用户空间中直接在进程之间切换,而不违反内核进程的原始语义。希望在共享内存地址空间内运行不同的进程,CPU核就可以通过跳转指令切换到另一个进程。但实现标准Linux进程抽象仍然具有挑战性。
-
Linux进程通过严格分离其地址空间来强制资源隔离,若共享地址空间,会导致恶意或有缺陷的进程可以任意访问和修改整个地址空间。因此,需要一种高效安全的方法来允许共享和隔离。
-
为了公平调度,抢占是必须的[17,28],以避免行首阻塞:在内核进程中运行的线程可以通过硬件定时器或处理器间中断(IPI)灵活抢占,以避免其长期占用内核。然而,没有现有机制可以在用户空间中抢占线程。
本文方法
本文提出了uProcess,一种用户空间进程抽象,使CPU内核能够在亚微秒的时间尺度上在应用程序之间调度。
-
通过在用户空间中构建特权模式来实现地址共享。不同uProcess的内存段(即文本、数据、堆栈等)由不同的内存保护密钥(MPK)保护,在uProcesss之间切换是陷入到这种特权模式,该陷入的功能类似于Linux内核的用户和内核空间之间的边界。【就是通过MPK实现了每个程序的独占空间和共享空间,独占空间存储文本、数据、栈等,只能有程序自己访问,共享空间用于执行,通过MPK获取权限来访问和执行】
-
为了实现抢占,使用硬件机制用户空间中断(Uintr),允许直接向用户级进程传递中断。因此,uProcess线程可以主动驻留,也可以被Uintr信号被动抢占,从而实现灵活的调度策略。
-
构建了Vessel,一个用户空间核心调度系统。传统上,应用程序内线程之间的负载平衡(例如,工作窃取)产生的开销比跨应用程序重新分配核心低得多,因此现有的调度为二级策略,只有在核心无法窃取当前应用程序中的任何工作后,才会重新分配核心。考虑到uProcesss的快速核心重新分配性能,Vessel通过维护CPU资源的全局视图将内核分配(抢占)给(从)应用程序,并执行一级调度策略。
实验结果表明,当多个应用程序托管时,Vessel表现出更好的整体性能和低延迟。
总结
针对进程间切换问题,频繁的用户态和内核态切换回消耗大量CPU周期。本文提出uProcess,一种用户空间进程抽象,实现了在亚微秒级的CPU核心调度和进程上下文切换。包括3个技术:(1)每个进程有独占空间和共享地址空间,通过内存保护密钥(MPK)实现内存的隔离和共享。(2)通过硬件机制用户空间中断(Uintr),实现抢占(3)基于uProcess构建用户空间核心调度系统,通过维护CPU资源的全局视图将内核分配(抢占)给(从)应用程序。