本文由星云 Clustar 编译并授权 InfoQ 发布,原文链接:https://mp.weixin.qq.com/s/jHSaBHJdikJCZZiMjM4m5Q
摘要
为实现资源的高效利用和轻量隔离,很多流行的大型云应用都在逐渐使用容器化。同时,很多数据密集型应用(例如,数据分析和深度学习框架)正在或希望采用 RDMA 来提高网络性能。行业趋势表明,这两种场景不可避免地会发生冲突。在本文中,我们介绍了 FreeFlow,一个为容器云设计的基于软件的 RDMA 虚拟化框架。FreeFlow 纯粹使用基于软件的方法,利用商用 RDMA NICs 实现了虚拟 RDMA 网络。与现有的 RDMA 虚拟化解决方案不同,FreeFlow 完全满足来自云环境的需求,例如多租户的隔离、容器迁移的可移植性 、以及控制和数据平面策略的可控制性。FreeFlow 对应用程序也是透明的,且使用很小的 CPU 开销提供了接近裸机 RDMA 的网络性能。在我们对 TensorFlow 和 Spark 的评估中,FreeFlow 提供了几乎与裸机 RDMA 相同的应用性能。
1. 介绍
大型云应用开发者一直在追求高性能、低运维成本和高资源利用率,导致容器化和远程直接内存访问(RDMA)网络技术被越来越多的采用。
容器[7,11,6]提供的轻量级隔离和可移植性,降低了部署和管理云应用的复杂性(从而降低了成本)。因此,现在容器成为管理和部署大型云应用的实际方式。
因为与基于标准 TCP/IP 的网络相比,RDMA 网络能够提供更高的吞吐量、更低的延迟和更少的 CPU 占用,所以许多数据密集型应用(例如,深度学习和数据分析框架)都会采用 RDMA [24,5,18,17]。
但不幸的是,这两种技术趋势在云环境中是相互矛盾的。容器化的核心价值是为应用提供高效灵活的管理。为此容器云需要容器在网络中具有以下三个属性:
隔离:每个容器都应该有其专用的网络命名空间(包括端口空间、路由表、接口等),以消除与同一主机上其他容器的冲突。
可移植性:容器应该使用虚拟网络与其他容器通信,并且与它的虚拟 IP 保持关联,而不管它被调度到哪个主机上或迁移到哪个主机上。
可控性:编排器可以容易地执行控制平面策略(例如,准入控制、路由)和数据平面策略(例如,QoS、计费)。此属性在(多租户)云环境中尤其需要。
对于在云环境中,自由放置、迁移容器、以及控制每个容器可使用的资源,这些属性都是必需的。为此,在基于 TCP/IP 的操作中,网络可以通过软件(虚拟)交换机来实现完全虚拟化[15]。
但是,很难对基于 RDMA 的网络进行完全虚拟化。 RDMA 通过将网络处理卸载到硬件 NIC 中,绕过内核软件栈,实现了高网络性能。 在共享的云环境中难以修改硬件中的控制平面状态(例如,路由),同时由于流量直接通过 PCIe 总线在 RAM 和 NIC 之间传输,也难以控制数据路径。
因此,采用这两种技术的几个数据密集型应用(例如,TensorFlow [24],CNTK [5],Spark [18],Hadoop [17])仅在专用裸机群集中运行时才使用 RDMA; 当在共享的云环境中运行时,不得不完全摒弃 RDMA 提供的性能优势。 当然,使用专用集群来运行应用对于提供商或客户来说都是不划算的。
本文的目的很简单:我们希望基于云环境中的容器化应用能够像在专用裸机集群中那样高效地使用 RDMA,同时也能实现容器云中的隔离、可移植性和可控性的要求。
目前还没有成熟的容器 RDMA 虚拟化解决方案。表 1 总结了可能通过扩展来支持容器的一些重要选项,尽管它们未能达到关键要求,也可能需要以很大的性能成本为代价进行实现。
表 1: 可用于容器的 RDMA 网络解决方案。
例如,基于硬件的 I/O 虚拟化技术,如 SR-IOV[21],具有根本的移植性限制[39,28],因为它们需要重新配置硬件网卡和交换机来支持容器的迁移。控制路径虚拟化解决方案,例如 HyV[39],只操作控制平面命令来实现隔离和可移植性,它们不具有数据流的可见性或可控制性。因此,它们不能灵活地支持云提供商所需的数据平面策略。软件仿真 RDMA,如 SoftRoCE[36],通过在 UDP 网络栈上运行 RDMA 并使用现有的虚拟 IP 网络解决方案,可以轻松实现隔离、可移植性和可控性,但其性能将受到 UDP 的限制。
本文提出了一种基于软件的容器云虚拟 RDMA 网络框架 FreeFlow,该框架实现了隔离、可移植性和可控性,并提供了接近裸机 RDMA 的性能。FreeFlow 的核心是运行在每个服务器上的软件虚拟交换机,来实现在商业 RDMA 网卡上虚拟化 RDMA。FreeFlow 不需要专门的硬件或基于硬件的 I/O 虚拟化。软件虚拟交换机具有对容器间通信的控制路径(如地址、路由)和数据路径(如数据流量)的完全访问权。这种设计理念类似于容器云中用于 TCP / IP 网络的现有软件虚拟交换机,例如 Open vSwitch(OvS)[15],尽管由于 RDMA 的特性,FreeFlow 的实际设计与 OvS 截然不同。
FreeFlow 的设计解决了两个关键挑战。首先,我们希望 FreeFlow 对应用程序完全透明。这很有挑战性,因为 RDMA 需要网卡来操作内存缓冲区和文件描述符,而容器内的应用程序由于网络虚拟化而不能直接与网卡交互。我们解决这一问题的关键点是,容器本质上是进程,它们可以使用 FreeFlow 轻松共享内存和文件描述符等资源。如果 FreeFlow 和容器共享相同的内存(§4.3)和文件描述符(§4.4),则底层物理 RDMA NIC 上的任何操作都将自动在容器内生效。另一个问题是,鉴于应用程序不会协作地创建可共享的资源,因此共享对应用程序透明的资源并不简单。 我们设计了将资源从不可共享转换为可共享的方法,对应用程序代码无需修改或只需很少的修改。
其次,FreeFlow 必须提供与裸机 RDMA 相当的吞吐量和延迟。我们将吞吐量和延迟中的性能瓶颈分别定义为内存复制和进程间通信。我们利用一个零拷贝设计吞吐量(§4.3), 一个共享内存进程间通道与 CPU 旋转延迟(§5.2)。同时还优化了 FreeFlow 来限制 CPU 开销。
我们使用标准的微基准测试工具和真实的数据密集型应用程序、Spark 和 TensorFlow 来评估 FreeFlow 的性能,不需要对它们进行任何修改或只需很小的修改。FreeFlow 的性能可与裸机 RDMA 相媲美,无需太多的 CPU 开销。同时,与使用传统 TCP/IP 虚拟网络相比,FreeFlow 显著提高了实际应用程序的性能,吞吐量提高了 14.6 倍,延迟降低了 98%。FreeFlow 吸引了多个 RDMA 解决方案提供商的兴趣,并已开放源代码https://github.com/Microsoft/Freeflow。
2. 背景
本章简要介绍了容器和 RDMA 网络,以及引出对容器的基于软件的 RDMA 虚拟化的需求。
容器和容器网络
容器正在成为打包和部署数据中心应用程序的实际选择 [30, 27, 25]。容器使用如 chroot 等机制 [4],将应用程序的可执行文件和依赖捆绑在独立的命名空间中,从而提供轻量级隔离和可移植的解决方案。
大
多数容器应用使用微服务架构,并由多个容器组成。例如,Spark [2]中的每个 mapper 和 reducer 节点都是一个单独的容器,TensorFlow[22]中的每个 ps 节点或 worker 节点也是一个单独的容器。容器通过网络解决方案交换数据。网络解决方案的设计会影响隔离度和可移植性。
例如,在主机模式网络中,容器使用其主机的 IP 和端口空间,并像主机操作系统中的常规进程一样进行通信。此模式有较差隔离性(例如,端口冲突)和可移植性(例如,迁移到其他主机后,必须更改 IP 地址和端口)。
因此,许多应用程序使用虚拟模式网络。在此模式下,容器的网络命名空间完全隔离,容器通过由主机上的软件虚拟交换机组成的虚拟(覆盖)网络进行通信。因为可以在软件虚拟交换机中控制到虚拟 IP 的路由,所以容器的虚拟 IP 是高度可移植的。由于所有数据流量必须通过虚拟交换机,因此它们可以访问流量,从而为容器网络提供完全可控性。这种隔离和可移植性使编排器在容器部署和迁移方面具有完全的灵活性,并且这种可控性使云提供商能够在控制和数据层面上实施其策略。
实际上,像 Kubernetes [11]这样的编排器要求使用虚拟网络模式[12]。许多软件解决方案可用于为容器提供虚拟网络结构,例如 Weave [23]和 Docker Overlay [7]。
RDMA 网络
许多现代应用程序(例如深度学习和数据分析框架)已采用 RDMA 网络 [18,17,25,5]来获得比传统 TCP / IP 堆栈更高的吞吐量和更低的延迟。RDMA 通过将大部分网络功能卸载到 NIC 中实现性能的提升,有效地绕过操作系统内核。
表 2:在单台计算机和具有 TCP、RDMA 网络的多台计算机上通过 TensorFlow 运行 RNN 的速度。速度标准化为单机的情况。
表 2 显示了使用 RDMA 进行通信的深度学习应用的性能改进 - 训练 Recurrent Neural Network(RNN)语音识别模型。该应用程序首先在具有 8 个 GPU 的单台机器上进行基准测试。当应用程序在具有 16 个 GPU 的两台计算机上运行时,传统的 TCP/IP 网络成为瓶颈,性能的提升下降。但是使用了 RDMA,额外 GPU 可以显著提高性能。
上述现象的原因是,RNN 训练任务包含数千个步骤。在每个步骤中,所有 GPU 都必须对训练模型参数进行 shuffle(即随机重排列),总流量大约在 100MB 到 10GB。花在通信上的时间实际上是浪费 GPU 的时间,因为 GPU 在 shuffle 期间处于空闲状态。TCP 在这些频繁和突发的工作负载中表现不佳,而 RDMA 可以在每次 shuffle 开始时瞬间爬升到全带宽。
对于基于软件的 RDMA 虚拟化的需求:
我们已经注意到了虚拟模式网络对容器应用程序的好处,即增强的隔离性、可移植性和可控性。同时,RDMA 还可以为许多具有微服务架构的应用程序提供显著的性能提升。
那么问题是,我们如何将 RDMA 网络与需要虚拟模式网络的容器应用程序结合使用,尤其是在云环境中。
图 1:基于硬件(SR-IOV)和基于软件的虚拟网络解决方案之间的比较。
正如我们之前看到的,RDMA 网络依赖于将大多数网络功能卸载到 NIC。“虚拟化”RDMA 网络的一种可能方法是使用基于硬件的解决方案,例如 SR-IOV[21],但是这会限制虚拟模式网络提供的可移植性。如图 1(a)所示,使用 SR-IOV,NIC 运行一个简单的第 2 层交换机,仅仅执行 VLAN 转发。因此,必须在底层物理网络中直接路由从虚拟网络生成并发往虚拟网络的所有分组。同时,将容器 C1 迁移到主机 Host2 需要重新配置物理交换机,以将 C1 的数据包路由到 Host2,而不是 Host1。此外,在生产中,物理交换机需要维护大量的路由表来管理虚拟网络中所有容器的路由,这在大规模云环境中是不可行的。
因此,我们认为,为容器虚拟化 RDMA 网络的正确方法是使用软件交换机,正如它用于虚拟化传统 TCP/IP 网络一样。如图 1(b)所示,物理网络只负责提供针对不同主机的数据包,而虚拟网络路由完全在每个主机内部的软件交换机中实现,这些交换机与物理网络无关。软件交换机可以控制所有寻址和路由,因此在控制层面上提供良好的隔离和可移植性。它还可以在数据层面上实现网络功能,例如 QoS 和计量。
3. 概述
FreeFlow 的目标是在每个容器内部提供虚拟接口,应用程序可以通过虚拟接口上的虚拟网络以未修改的方式使用 RDMA。理想情况下,虚拟网络的性能应接近裸机 RDMA,并且控制和数据路径上的策略都可以灵活地配置为纯软件。在本节中,我们将介绍系统架构以及 FreeFlow 设计中的主要挑战。
总体设计
在原生 RDMA 中,如图 2(a)所示,应用程序利用 RDMA API 直接向硬件 NIC 发送命令,以实现控制和数据路径功能。FreeFlow 接收应用程序和物理网卡之间的通信,并在软件 FreeFlow 路由器内执行控制平面和数据平面策略,该路由器作为主机上的另一个容器运行。特别的是,为了控制数据路径,FreeFlo wrouter 只允许物理 NIC 直接从自己的内存中读取和写入(图 2(b)中的虚拟内存),并负责将数据复制到应用程序的内存中。请注意,内部容器中的内存容器和 FreeFlow router 中的影子内存可以是零拷贝的同一块物理内存(§4.3 )。
表 2:设计概览: FreeFlow router 直接访问 NIC,作为一个 RDMA 中继为 container 服务。蓝线和红线分别是控制和数据的路径。
Verbs:RDMA 的“窄腰”
有多种方法可以拦截应用程序和物理网卡之间的通信,但我们必须选择有效的方法。 目前有许多支持 RDMA 的商业技术,包括 Infiniband [9]、RoCE [8]和 iWarp [19]。应用程序还可以使用几种不同的高级 API 来访问 RDMA 功能,例如 MPI 和 rsocket [20]。如图 3 所示,这些 API 事实上的“窄腰”是 IB Verbs API(Verbs)。因此,我们有意识地选择在 FreeFlow 中支持 Verbs,这样我们就可以自然地支持所有更高级别的 API。
表 3:IB 动词是基于 RDMA 的网络卸载解决方案,实际上的“窄腰”。
Verbs 使用“队列对”(QP)的概念进行数据传输。对于每个连接,两个端点中的每一个都有一个 sendqueue(SQ)和一个接收队列(RQ),它们一起称为 QP。发送队列保存有关需要发送的内存缓冲区的信息,而接收队列保存有关接收传入数据的缓冲区的信息。
每个端点还具有单独的完成队列(CQ),NIC 使用该队列来通知端点发送或接收请求的完成。Verbs 库和相关驱动程序允许读取、写入和监视三个队列的应用程序。数据的实际传输,包括打包和错误恢复,由 NIC 处理。为了透明的支持 Verbs ,FreeFlow 创建虚拟 NIC 中的虚拟 QP 和 CQ,以及将它们的操作与物理 NI 中的实际 QP 和 CQ 的操作联系起来。
FreeFlow 架构
FreeFlow 的体系结构如图 4 所示。我们修改或引入的容器网络堆栈的三个组件以灰色显示:(i)FreeFlow network library(FFL),(ii)FreeFlow software 路由器(FFR),以及(iii)FreeFlow network orchestrator(FFO)。
FFL 位于容器内部,是使 FreeFlow 对应用程序透明的关键。从应用程序的角度来看,它与标准的 RDMA Verbs 库无法区分[16]。构建 Verbs API 的所有应用程序和中间件都可以在没有(或可忽略的)修改的情况下运行,FF 与 FFR 协作。
FFR 在每个主机上运行单个实例,并与同一主机上的所有容器一起提供虚拟网络。在数据平面中,FFR 与同一主机上的容器共享内存缓冲区,并隔离不同容器的共享内存缓冲区。FFR 通过 NIC 在共享内存中发送和接收数据,依靠 FFL 在应用程序的专用数据缓冲区和共享内存缓冲区之间同步数据。FFR 通过控制容器和 FFR 之间的共享存储器通道来实现数据平面资源策略,例如 QoS。它还可以与 FFO 一起处理诸如 IP 地址分配之类的簿记任务。
FFO 根据用户定义的配置和集群的实时监控,为其集群中的所有容器做出控制平面决策。它还维护集中式存储器映射,我们将在下文中讨论。
表 4:FreeFlow 架构
挑战
在设计 FreeFlow 时,我们需要解决两个关键挑战。首先,FreeFlow 应该提供一个 RDMA 接口,它透明地支持所有类型的现有 RDMA 操作。存在各种类型的 RDMA 操作,包括用于数据传输的单侧和双侧操作,用于工作完成通知的轮询和基于事件的机制,以及用于连接建立的 TCP/IP 和 RDMA-CM。我们观察到,由于 RDMA 操作的复杂性,透明地支持它们并不简单。其次,FreeFlow 应该提供接近裸机的 RDMA 性能,同时最小化 CPU 和内存开销。由于 FFR 通过 FFL 接受来自应用程序的 Verbs 调用,所以我们需要仔细设计 FFR 和 FFL 之间的通信通道。我们将分别针对§4 和§5 中的每个挑战提出我们的方法。
4. RDMA 操作的支持
Verbs 支持多种操作和机制。使用 WRITE/READ 单方操作,读取(写入)方可以读取(写入)远端服务器特定内存地址的数据,而不需要事先通知对方。使用 SEND/RECV 双方操作,发送方必须在接收方准备好接收数据之后才能发送数据。此外,程序也可以使用基于拉取或者基于事件的机制来处理任务完成通知。不同的程序根据自己的需要选择不同的操作方式,我们发现在常用的应用程序中,这几种操作都被使用到。[32、18、17、22]
FreeFlow 完全透明地支持这些不同的 RDMA 操作。主要的挑战是支持单方操作和基于事件的完成通知,因为,RDMA 网卡会悄无声息的修改 FFR 使用的内存或者文件描述符。FFR 如果不持续的频繁检查内存或者文件描述符的话是不会马上发现变更的,所以,及时的将物理网卡上的操作转换到容器中的虚拟网卡上是非常困难的。但是,容器终归是进程,FFL 和 FFR 可以共享内存和文件描述符,借助这个特点我们解决了这个问题,让物理网卡所做的操作可以自动的传入容器中。将应用程序的内存在 FFL 和 FFR 之间共享也不是很容易,因为,容器内的应用程序不会在 IPC 共享内存区申请内存,所以,我们需要将容器中的内存转换成共享内存。
建立连接
两个 RDMA 通信端首先需要建立连接。它们在各自的网卡上创建 QP,并为 QP 申请一个内存缓存,然后与远端的 QP 进行配对。当连接建立后,应用程序会要求 NIC 将本地缓存中的内容发送到远端,或者将收到的内容放到本地缓存中。
表 5:RDMA 发送操作的工作流程
图 5 中的 1~7 步展示了使用 Verbs 创建连接的基本流程。左边一列显示了应用程序使用 Verbs 的顺序。右边阴影中的两列展示了 FreeFlow 如何捕获应用程中的 Verbs 调用,以及如何在发送端 FFR 和接受端之间建立连接。
第一步:应用程序查找支持 Verbs 的网卡。FFL 截获这个调用并返回容器的虚拟网卡。(即通知应用程序容器的虚拟网卡支持 Verbs 操作。)
第二步:应用程序在虚拟网卡上建立 QP 和 CQ,同时 FFR 在物理网卡上创建对应的队列(QP’和 CQ’)。当 FFR 创建好这些队列后,由 FFL 将 QP-ID 等队列的元信息返回给应用程序。
第三步:应用程序注册一块内存(mem)到 QP。FFR 在自己的共享内存内部处理交互区(IPC)分配一块同样大小的内存(s-mem),并将其注册到 QP’上。FFR 返回它创建的 s-mem 的 ID,这个 ID 是主机上 IPC 内存区的唯一标示。FFL 可以用这个 ID 将 s-mem 映射到自己的虚拟内存区中。
第四步:应用程序查询本地 QP 的地址(在 RDMA 中叫 GID)。这个地址信息会同时共享给本地和远程的 QP。最后,FFR 返回 QP’的真实 GID。
第五步:应用程序与远端交换 GID 和 QP-ID。应用程序可以通过任何方式交换这些信息,例如 TCP/IP,或 RDMA-CM。
第六步:应用程序通过接收者的 GID 将本地的 QP 和远端容器的 QP 配对。FFL 将此 GID 转发给 FFR。FFR 再用这个 GID 配对 QP’。
第七步:应用程序将本地 QP 的状态改为 Ready,准备发送接收数据,同时 FFR 修改 QP’的状态。
第七步之后,从应用程序的角度来看,它已经可以发送或接收数据了 – 它已经创建好了 QP 和 CQ,在 QP 上注册了 mem,与远端的 QP 建立了连接,并完成了与远端 QP 的配对。
从 FreeFlow 的角度来看,它创建了与 QP 关联的 QP、与 CQ 关联的 CQ’,注册了与 mem 关联的 s-mem,并且与远端 FFR 中的 QP’进行了配对。它也准备好接收并处理应用程序中的 Verbs 调用了。
由于 FFR、FFL 之间额外的交互,Freeflow 可能会增加连接建立的延迟。但是它对总体延迟影响不大,因为建立连接是一次性行为;大部分的 RDMA 应用会重用之前建立好的连接。
双方操作
在执行数据传输之前,发送者和接受者都需要进行两步操作。第一步是用 QP 发送接收数据,第二步是用 CQ 来处理完成通知。图 5 中的 8、9 步展示了这个过程。
第八步:应用程序执行 SEND 调用,并传入了指向 mem 的指针。FFL 首先复制 mem 中的数据到 s-mem,然后 FFR 调用 SEND 指令,将 s-mem 中的数据发送到远端的 FFR。我们使用§4.3 讨论到的零复制机制来实现数据复制,而不是简单的将数据从 mem 复制到 s-mem。请注意,此时在远端会触发一个对应的 RECV 调用。
第九步:应用程序会通过检测 CQ 或者等待通知来获知 send 是否完成。同时 FFR 会检测与 CQ’并将结果发送给 FFL。
对于同一个 QP 中的后续 SEND 操作,应用程序只需要重复第八、九步。RECV 操作的工作流程除了第九步以外基本相同,FFL 会在 QP’接受完数据后将数据从 s-mem 复制到 mem,就像 SEND 操作的第八步一样。
对于应用程序来说,FFL 和 FFR 是完全透明的。应用程序就像是在自己的虚拟网卡上执行一个普通 Verbs 操作。图 5 展示的流程也是开发中使用 Verbs 的标准方法。这里描述的 FreeFlow 的行为说明它可以完全支持 SEND 和 RECV 操作。
单方操作
表 6:让 Freeflow 可以高效的支持单方操作的内存零复制设计
在单方操作中,客户端不止需要服务端的 GID,同时还需要远端内存缓存的地址,以及访问内存所需的密钥。这些信息会在图 5 的第五步时进行交换,然后在第八步执行读写操作时使用。
与双方操作相比,单方操作的透明支持更加有挑战性。在 FreeFlow 中支持单方操作需要面临两个问题。
首先,目标存储器地址 mem 位于远程容器的虚拟存储器中。但是,本地 FFR 不知道另一方的相应 s-mem。例如,在图 6(a)中,当发送方试图将 mem-1 中的数据写入远程存储器 mem-2 时,它在阶段 3)就失败了,因为接收器上的 FFR 无法访问目标存储器地址 mem-2 。
为了解决这个问题,FreeFlow 在 FFO 中为所有 FFR 构建了一个中心键值存储,以保存应用程序虚拟内存空间中 mem 指针与 FFR 虚拟内存空间中相应 s-mem 指针之间的映射。当应用程序将内存注册到其虚拟 NIC 时,更新此表会增加图 5 中步骤 3 的延迟。但是,数据平面性能不会受到影响,因为 FFR 可以在本地缓存映射。
其次,即使我们知道远程端的内存映射,WRITE 和 READ 也可以远程修改或复制数据而不通知远程端的 CPU,因此,FFR 不知道何时复制到应用程序的存储器或从应用程序的存储器复制。例如,在图 6(b)中,发送方找到 s-mem-2 的正确地址并将数据发送给它。但是,在 s-mem-2 中有数据后,没有通知接收器的 FFR 知道何时将 s-mem-2 复制到 mem-2。解决此问题的一种方法是不断同步 s-mem-2 和 mem-2。 当然,这会消耗大量的 CPU 和内存总线带宽。
为了解决这个问题,我们在 FreeFlow 中设计了一个基于零拷贝的机制来有效地支持单方操作。高级想法是使 mem 和 s-mem 具有相同的物理内存,因此 FFR 不需要进行任何复制,数据将自然地呈现给应用程序。图 6(c)说明了这种设计。通过删除内存副本,我们还可以提高 FreeFlow 的性能。
这里的关键是使应用程序直接分配和使用共享内存与 FFR 进行数据传输。为此,FreeFlow 提供了两个选项:
选项 1 - 创建新的 API 来分配共享内存:我们创建两个新的 Verbs 函数,ibv _malloc 和 ibv_free,让应用程序将内存创建和删除委托给 FreeFlow。这允许 FFL 直接在共享内存区域中分配这些缓冲区(与 FFR 共享),从而避免复制。这个选项的缺点是需要修改应用程序代码,尽管修改应该只是数据缓冲区创建的几行。
选项 2 - 将应用程序的虚拟内存地址重新映射到共享内存:当应用程序将虚拟内存地址 va 作为数据缓冲区注册到私有内存块时(例如,图 5 中的步骤 3),FFL 释放物理内存记忆片后面的 va,并从 FFR 到 va 分配一个共享的物理内存片。在 Linux 中,此操作仅在 va 是内存页面开头的地址时有效。为了强制应用程序始终在页面的开头分配内存,FFL 拦截 C 语言中的 malloc 之类的调用,并使其始终返回页面对齐的内存地址。虽然此选项可以在不修改应用程序代码的情况下实现零内存复制,但它会强制应用程序中的所有内存分配进行页面对齐,这会导致主机上的内存效率降低。
在实践中,我们建议使用第一个选项,因为它更清洁,更高效。但是,由于许多 RDMA 应用程序已经使它们的数据缓冲区页面对齐以获得更好的性能(例如,RDMA-Spark [18]),我们可以直接使用第二个选项而不拦截 malloc,因此副作用有限。请注意,不管开发人员选择使用选项 1 修改应用程序,还是应用程序本来就支持页面对齐缓冲区,FreeFlow 都不会在实际内存使用中产生任何开销。
基于事件的操作
从 CQs(完成队列)中获取信息有两种方式。一种是让应用定时检查队列中是否有结束的操作。另一种是基于事件的,由应用创建一个事件管道,然后将 CQ 加入管道。当有操作完成时可以通过管道中的文件描述符触发相应的事件。
在 FreeFlow 中,由于原始文件描述符是由物理网卡创建的,FFR 需要将文件描述符传递给 FFL,否则后者无法感知与文件操作符相关的事件。但是 FFL、FFR 本质上共享同一个内核的两个进程,借助此特点也可以实现进程间文件描述符的传递,由此我们实现了将事件管道从 FFR 传递给了 FFL。
5. FFL 和 FFR 之间的通信通道
由于 FreeFlow 通过 FreeFlow 网络库(FFL)截取每个 Verbs 调用,解释并通过 FreeFlow 软件路由器(FFR)将它们转发到物理网卡,因此,在 FFL 和 FFR 之间建立有效通道以提供高 RDMA 性能,同时最小化系统资源消耗至关重要。在本章中,我们提出了两种这样的通信信道设计,它们允许用 RDMA 性能来换取资源消耗量,反之亦然,这取决于应用的要求。
Verbs 通过文件描述符转发
图 7:Verbs API 和库的结构。FFR 截取 Verbs 库和网卡驱动之间的调用。
在 FFL 和 FFR 之间传递 Verbs 调用的直接方法是使用 RPC:FFL 将 API 名称和参数传递给 FFR,FFR 适当修改参数后执行 API 并将 API 调用的结果返回给 FFL。然而,由于 Verbs 调用复杂的输入数据结构,这种简单的 RPC 方法在 FreeFlow 中并不能很好地工作。如图 7(a)所示,Verbs 中的典型函数调用(例如,ibv_post_send)含有输入数据(qp,wr)和输出数据(bad_wr),它们是指向复杂数据结构的指针。由于 FFL 和 FFR 是两个不同的进程,所以,FFL 中的指针在 FFR 中无效。
也许有人提倡“深度复制”,它会记下复杂的输入/输出数据结构,并在 FFL 和 FFR 之间的所有指针下传输数据对象。然而,这种方法有两个严重的缺点。首先,Verbs 中的数据结构层级非常深(如多层的指针和嵌套),这样的深度复制会损害性能。其次,对于用户自定义的数据结构,其深度复制方法不能由 FreeFlow 预定义。
为了解决这个问题,我们利用了当前 Verbs 库的结构。如图 7(b)所示,Verbs 库由三层组成。顶层是最复杂的层,如上所述那样难以处理。但是,当涉及与网卡文件描述符进行通信的中间层时,Verbs 库必须准备一个足够简单(无指针)的数据结构,使网卡硬件可以处理。
因此,我们转发对网卡文件描述符的请求,而不是转发 Verbs 的原始函数调用。我们用一个一端连接 FFR 的 Unix 套接字文件描述符替换容器中的网卡文件描述符,如图 7(c)所示。通过这样做,FFR 可以获取应用程序发送的命令和提供的参数。FFR 会将在容器中对虚拟队列的操作映射到在物理网卡中对实际队列的相应操作。然后,它将来自物理网卡的回复转换为虚拟网卡对虚拟队列的回复,并通过 Unix 套接字将新的回复返回给 FFL。FFL 中的网卡驱动程序通信层将正常处理该回复,但不会知道 Unix 套接字文件描述符背后的操作。
虽然这种基于 Unix 套接字的方法能消耗很少的 CPU,但由于通过套接字进行通信的固有延迟,它可能会产生额外的延迟。我们的测量结果表明,在商品服务器中,Unix 套接字(以及信号量共享内存)的往返时间很容易超过 5μs。因此,图 7(c)中的 Unix 套接字通信通道可能成为延迟敏感应用程序的性能瓶颈。而这些应用程序则需要超低的延迟(比如小于 5μs)。
对于需要低延迟通信的应用,我们将在下一节中介绍 Fastpath 的设计,它通过用 CPU 资源来换取通信延迟的优化。
FFL 与 FFR 之间的 Fastpath
图 8:FFR 与 FFL 间的 Fastpath 通道
为了加速 FFR 和 FFL 之间的通信,我们设计了一个与它们之间基于 Unix 套接字的通道并行的 Fastpath。如图 8 所示,FFL 和 FFR 共同拥有一块专用的共享内存。使用 Fastpath,FFR 在 CPU 内核上自旋并持续检查是否有来自 FFL 的新请求被写入共享内存块。一旦检测到请求,FFR 将立即执行它,同时 FFL 开始在 CPU 内核上自旋以检查是否完成响应。在读取到响应后,FFL 将停止它的 CPU 自旋。
正如我们将在第 8.1.2 节中看到的,Fastpath 可以显著减少延迟。但代价就是用于读取请求和响应的自旋所花费的 CPU 开销。为了限制 Fastpath 带来的 CPU 开销,我们做出两个设计决定:
(1)对于同一主机上具有 FFL 的所有 Fastpath 通道,FFR 仅在一个 CPU 内核上自旋。
(2)Fastpath 仅用于数据通路上的非阻塞功能,使得 FFL 上等待响应的 CPU 旋转时间会很短(几微秒)。
总的来说,Fastpath 平均每个主机仅消耗一个 CPU 内核,以显著缩短消息传递的延迟(第 8.1.2 节)。 另外,如果 FFO 知道主机上没有对延迟敏感的应用程序(根据运行的容器镜像),它可以禁用 Fastpath 和 CPU 自旋。
6. 实现
我们通过修改 libibverbs (v1.2.1)、 libmlx4 (v1.2.1) 和 librdmacm(v1.1.0)来实现 FreeFlow 网络库(FFL)[注 4]。添加了大约 4000 行 C 代码来实现 FreeFlow 的逻辑。我们大约通过 2000 行 C ++代码实现了 FreeFlow 软件路由器(FFR)。对于 FreeFlow 网络协调器(FFO),我们使用 ZooKeeper 来存储用户定义的信息。比如,IP 分配、访问控制、资源共享策略和单侧操作的内存映射信息。由于篇幅限制,我们接下来只展示三个代表性的实现细节。
控制和数据层面策略
由于 FreeFlow 可以控制容器请求的控制和数据层面操作,因此它可以支持常见的控制和数据层面策略,包括带宽执行策略、流优先级划分策略和资源使用执行策略。
作为控制层面策略的一个例子,在我们的原型中,FreeFlow 对每个容器可以创建的 QP(queue pair)数量进行限额,因为大量的 QP 是 RDMA 网卡性能下降的主要原因[32]。此控制层面策略可防止容器创建太多 QP 影响同一主机上的其他容器。
我们在 FFR 中实现了一个简单的令牌桶数据结构。当应用程序创建新 QP 时,我们检查存储在 FFO 中的策略,并将有预设速率限制的令牌桶关联到 QP。在每个应用程序发送请求时,路由器会检查 QP 是否有足够的令牌去发送请求消息。如果有,则立即将发送请求转发给物理网卡。否则,FFR 将通知 FFL 并将其延迟,直到有足够的令牌。请注意,它只是实施 QoS 策略的一个示例。FreeFlow 提供了灵活的 API,用于在 FFR 中实现复杂的 QoS 算法,而由于篇幅限制,我们省略了细节部分。
Fastpath 内存管理
在 Fastpath 实现中,我们使用汇编代码显式强制地将 FFL 和 FFR 写入的请求和响应的缓存行立即刷新到主存储器中。这是必要的,否则 CPU 会将新写入的行保留一段时间,以等待更多写入行,从而减慢 Fastpath 上的信息交换速度。
支持并行
由于应用程序可以创建多个 QP,并使用多个线程来并行传输数据,因此 FFL 和 FFR 之间的每个 Unix 域套接字都需要锁定。为了提高性能,我们在 FFL 和 FFR 之间创建了多个 Unix 域套接字。为避免排头阻塞,我们将更多套接字专用于数据层面操作和事件通知,并仅使用一小部分套接字用于创建、设置和删除操作。在 FFR 上,我们为每个传入的 Unix 域套接字连接使用专用线程。我们还为每个容器创建专用数据结构,并为每个已注册的内存缓冲区创建专用共享内存区域,以保持数据路径无锁。
注 4:libibverbs 和 librdmacm 是允许用户空间进程分别使用 InfiniBand / RDMA Verbs 和 RDMA 通信管理器接口的库。libmlx4 是 libibverbs 的用户空间驱动程序,允许用户空间进程使用 Mellanox 硬件。
7. 讨论
在本节中,我们将讨论当前 FreeFlow 设计中的一些主要问题和潜在扩展。
CPU 开销:与基于软件的 TCP / IP 虚拟网络解决方案类似,FreeFlow 会产生 CPU 开销。特别是,FreeFlow 使用 CPU 内核在 FFL 和 FFR 之间轮询控制消息,以支持低延迟 IPC 通道(第 5.2 节)。我们承认,这个是在当前商品硬件之上进行网络虚拟化的成本。解决这个问题的一种可能方法是利用支持卸载 CPU 任务的硬件,例如 FPGA、ARM 协处理器或 RDMA 网卡[1]。我们如何消除 Fastpath 中的 CPU 开销,将作为我们未来的工作。
安全性:一个问题是由于 FFR 与容器共享其内存,因此一个容器是否可以通过扫描 IPC 空间来读取同一主机上其他容器的通信。这不是 FreeFlow 的问题,因为 FFR 为每个单独的 QP 创建了专用的共享内存缓冲区。只有属于容器的共享内存缓冲区才会映射到容器的虚拟内存空间。另一个问题是存储键的安全性,如果可以通过窃听看到密钥,则后续通信可能会受到影响。这个问题与原始 RDMA 工作中的单边操作有关,并且 FreeFlow 不会使其变得更糟糕。
使用外部传统对等体:FreeFlow 中的容器可以自然地与外部 RDMA 对等体通信,因为每个 FFR 都能独立工作。FFR 不会区分远程对等体是另一个 FFR,还是外部 RDMA 对等体。
容器迁移:FreeFlow 自然支持离线迁移。如果在另一台主机上捕获、关闭、移动和重新启动容器,则其 IP 地址不会更改,以便其对等方重新建立 RDMA 连接,就像它刚刚重新启动一样。如今,离线迁移通常用于容器集群中,以进行资源打包或故障转移。FreeFlow 不支持实时迁移,因为现在 RDMA 的移动性还很差[39]。
VM 主机:我们的原型(和评估)是基于在裸机主机上运行的容器。但是,如果 VM 使用 SR-IOV 访问物理 NIC,则 FreeFlow 可以直接用于部署在 VM 中的容器。
拥塞控制:RDMA 网卡已经拥有拥塞控制机制,并且 FreeFlow 依赖于它们。
8. 评估
我们评估了 FreeFlow 的性能和开销。我们将从微基准和 FreeFlow 上的实际应用程序的性能开始进行评估。
微基准测试
设置:我们在两个测试台上运行微基准测试。一个测试平台运行在 InfiniBand,这是一种传统的 RDMA 专用结构。这些服务器配备两个 Intel Xeon E5-2620 2.10GHz 8 核 CPU、64GB RAM 和 56Gbps Mellanox FDR CX3 NIC。操作系统是 Ubuntu 14.04,内核版本为 3.13.0-129-generic。
另一个测试平台运行 RoCE(RDMA over Converged Ethernet)。顾名思义,RoCE 只需要传统的以太网交换机(在我们的例子中,Arista 7050QX 作为 ToR 交换机)。此测试平台群集中的服务器具有 Intel Xeon E5-2609 2.40GHz 4 核 CPU、64GB RAM、40Gbps Mellanox CX3 NIC 和 Ubuntu 14.04 以及内核版本 4.4.0-31-generic。
我们使用 Docker(v1.13.0)[7]运行容器,并使用 Weave(v1.8.0)[23]设置基本的 TCP / IP 虚拟网络,并启用 Open vSwitch 内核模块。除非另有说明,否则我们运行 Fastpath(§5.2)启用 FreeFlow。
我们主要将 FreeFlow 与裸机 RDMA 进行比较,后者是“最佳”性能的替代品。我们将展示 FreeFlow 为容器启用虚拟 RDMA 网络,而性能损失最小。在 8.1.4 中,我们还将演示在 FreeFlow 上将 TCP 套接字调用转换为 RDMA 的性能,这样传统的 TCP 应用程序也可以从 FreeFlow 中受益。我们还将 FreeFlow 与裸机 TCP 和 Weave 进行了比较,后者支持容器的虚拟 TCP / IP 虚拟网络。
吞吐量和延迟
我们专注于两个基本性能指标,即吞吐量和延迟。我们使用 Mellanox perftest [13]提供的基准测试工具:ib_send_lat 和 ib_send_bw 测量延迟和通过双边操作(SEND),ib_write_lat 和 ib_write_bw 进行单向操作(WRITE)。这些工具可以在 FreeFlow 上运行而无需任何修改,如 4.3 中所述。一般而言,FreeFlow 不区分主机间设置(在不同主机上运行的发送方和接收方)和主机内设置。这里我们只显示主机间性能值。
图 9:不同主机上一对容器之间的 RDMA SEND 吞吐量。FreeFlow 使容器虚拟网络的性能损失最小化。
图 11:扩展容器对数量时的聚合吞吐量。
吞吐量:我们测量两个测试平台上的单线程 RDMA SEND / WRITE 吞吐量,并在图 9 中显示 RDMA SEND 结果。每次运行都传输 1GB 数据,不同大小的消息范围从 2KB 到 1MB。 FreeFlow RDMA WRITE 结果实际上略好于 SEND,为简洁起见省略。我们看到,当消息大小等于或大于 8KB 时,FreeFlow 将获得全吞吐量作为裸机 RDMA(InfiniBand 为 46.9Gbps,RoCE 为 34.5Gbps)。此外,当我们将并发容器对(流量)的数量增加到 512 时,所有流量的聚合吞吐量仍然接近最优(图 11)。我们还通过计算 Jain 的公平性指数[31](平均 0.97)来验证带宽在不同流量之间的公平分配。
通常,需要大量带宽的应用程序倾向于使用比几 KB 更大的消息大小。例如,在我们使用 RDMA 的一个内部存储群集中,典型的消息大小为 1MB 或更多。在这种情况下,FreeFlow 将没有吞吐量损失(关于 CPU 开销,请参见 8.1.2)。
即使消息很小,如 2KB,FreeFlow 仍然可以达到全部吞吐量的一半以上。我们验证了在这种情况下,吞吐量受单个 FFR Fastpath 线程(第 5.2 节)的限制。通过为 FFR 分配一个 CPU 核心,并在两个核心之间平衡 RDMA 请求负载,可以轻松消除此瓶颈。虽然我们将此选项保持打开状态,但开发人员通常不希望使用小消息来满足整个带宽。相反,对于小消息,开发人员通常关心延迟。
延迟:我们分别测量发送 64B、256B、1KB 和 4KB 消息的延迟。与吞吐量基准测试一样,两个容器在通过相同 ToR 交换机连接的不同主机上运行。对于每个消息大小,我们测量延迟 1000 次。我们绘制了中位数、第 10 和第 99 百分位潜伏期值。
图 10:不同主机上的一对容器之间的 RDMA 延迟。 SEND 是典型的双面操作,而 WRITE 是单面操作。
图 10 显示了 perftest 工具报告的单向延迟。我们可以看到,单面 WRITE 操作的延迟低于双面 SEND 操作,FreeFlow 和裸机 RDMA 之间的间隙也较小。但是,即使进行双面操作,FreeFlow 也会导致额外延迟小于 1.5μs。额外的延迟主要是由于 FFL 和 FFR 之间的 IPC。单面操作将仅触发 IPC 一次,而双面操作将触发两次和一次内存复制。这就解释了双面操作的较大延迟差距。
为了将这些延迟值放入透视图中,网络中的一跳(即硬件交换机)具有 0.55μs 的延迟[3]。因此,FreeFlow 延迟开销与网络中额外的交换跳跃相当。相比之下,主机 TCP 堆栈延迟至少为 10μs(8.1.4),然后 TCP / IP 虚拟网络容量更大(超过 40μs)。这意味着 FreeFlow 在为容器启用虚拟网络的同时保留了 RDMA 的延迟优势。
CPU 开销和权衡
FreeFlow 以低 CPU 开销实现了良好的性能。FreeFlow 有两种模式:Fastpath 和非 Fastpath(或 LowCPU,§5.1)。默认情况下,启用 Fastpath 并在延迟方面提供最佳性能。在此模式下,FFR 在一个 CPU 核心上旋转,并尽快为动词请求提供服务。一个 CPU 核心能够为一个主机上的所有容器提供服务,这要归功于 FFR 只处理消息级事件,而不是像 Open vSwitch 那样处理数据包级别。在具有许多 CPU 内核的商用服务器上,这是可以接受的。
图 12:使用 1MB 消息测量吞吐量时 ib 发送 bw 和 FFR 的 CPU 使用率。100%CPU 意味着一个充分利用的 CPU 核心。
表 3:两种 FreeFlow 模式的 2 字节消息延迟。
此外,用户可以选择 LowCPU 模式,它使用 Unix 套接字作为信号机制而不是核心旋转。这会影响延迟性能(从 2.4μs 增加到 17.0μs),如表 3 所示。在图 12 中,我们在测量主机间吞吐量时记录了每进程的 CPU 利用率。图中所有三种情况的吞吐量是相同的(全带宽)。它显示了 LowCPU 模式的 CPU 优势,特别是在 FFR 上。在 LowCPU 模式下,FFR CPU 开销随实际负载而变化。
我们建议根据工作负载要求选择模式。延迟敏感或非重 CPU(例如,GPU-heavy)应用程序应使用快速路径模式运行,而其余应用程序可以使用 LowCPU 模式运行。但是,即使使用 Fastpath,FFR 最多也只消耗一个 CPU 内核,而 FFL 的额外开销低于全带宽吞吐量的 30%。
速率限制器和性能隔离
图 13:FreeFlow 可以准确控制容器中通信流量
我们演示了§6 中提到的速率限制器的性能。在图 13 中,我们在 InfiniBand 测试平台上的不同主机上的两个容器之间启动单个流。我们限制流量并将不同的带宽上限从 1Gbps 设置为 40Gbps。我们看到受控带宽(y 轴)接近我们设定的带宽上限(x 轴)。FreeFlow 只需 6%的 CPU 开销即可实现这一目标。
FreeFlow 可以使用速率限制器隔离不同容器的性能(即吞吐量)。为了证明这一点,我们在容器对之间运行了 10 个并发流,并对每个流应用了不同的速率限制(从 1 到 10Gbps)。我们确认每个流量的吞吐量都是准确的上限。
RDMA 上的 TCP 套接字
启用虚拟 RDMA 还可以提高基于套接字的应用程序的性能。下面我们展示 FreeFlow 在 rsocket(现有的 socketto-Verbs 转换层)的帮助下,提供比传统 TCP / IP 虚拟网络更好的性能。
我们在 InfiniBand 和 RoCE 集群上进行实验。通过在运行时动态链接 rsocket,应用程序套接字调用被透明地转换为 RDMA Verbs 调用。我们运行 iperf [10]来测量 TCP 吞吐量,NPtcp [14]用于 TCP 延迟,而不对这些工具进行任何修改。我们与在虚拟和主机模式网络上运行的相同工具进行比较。
图 14:不同主机上一对容器之间的 TCP 吞吐量和延迟。我们将本机 TCP 与 FreeFlow + rsocket(socket-to-Verbs 转换)进行比较。
如图 14 所示,FreeFlow 总是优于 Weave。特别是对于小消息延迟,FreeFlow 始终低于主机 TCP / IP,高达 98%。对于吞吐量,由于套接字到动词转换的开销,FreeFlow 有时比主机 TCP 差,并且无法像原始 RDMA 那样实现全吞吐量。但是,它仍然比使用大消息的 Weave 大 6.8 到 13.4 倍。
这是 FreeFlow 具有良好性能的两个原因。首先,RDMA 堆栈和 FreeFlow 架构只能在用户空间中工作,并避免在内核 TCP 堆栈中进行上下文切换。这个优势并不是唯一的;定制用户空间网络堆栈也可以实现这一目标。FreeFlow 优于 Weave 的第二个原因是根本。现有的 TCP / IP 虚拟网络解决方案执行从虚拟网络到主机网络的逐包地址转换。但是,FreeFlow 执行从虚拟连接到物理连接的基于消息的转换。因此,FreeFlow 总是优于 Weave,尽管 rsocket 引入了一些 socket-to-Verbs 转换开销。
真实世界的应用程序
在本节中,我们将展示 TensorFlow 和 Spark 的性能,这是一个在容器中运行的代表性机器学习和数据分析框架。我们将 FreeFlow 的应用程序性能与 Host-RDMA、HostTCP 和 Weave 进行比较。
由于 TensorFlow 需要我们的 RoCE 集群没有的 GPU,我们在 InfiniBand 集群上运行所有实验。基于微基准测试,我们认为如果配备 GPU,RoCE 集群将具有类似的趋势。
Tensorflow
我们在 InfiniBand 集群中的三台服务器上运行支持 RDMA 的 TensorFlow(v1.3.0)。我们修改了 TensorFlow 的一行源代码,用我们的自定义内存分配器(第 4.3 节)替换原始的内存分配函数。每台服务器都有 8 个 NVIDIA GTX 1080 Ti GPU。其中一个服务器是主节点,也是参数服务器,而其他两个服务器是工作服务器。我们针对深度学习运行两种主要类型的训练工作量,即基于卷积神经网络(CNN)的图像识别和基于递归神经网络(RNN)的语音识别。
图 15:FreeFlow 上的 TensorFlow 性能
对于图像识别,我们运行三个特定模型,ResNet-50 [29]、Inception-v3 [42]和 AlexNet [33]。我们使用合成的 Image Netdata 作为训练数据。图 15(a)显示了具有 10 百分位数和 99 百分位数值的每秒中值训练速度。根据所有三种不同模型的结果,我们得出结论,首先,网络性能确实是分布式培训的瓶颈。将主机 RDMA 与主机 TCP 进行比较,主机 RDMA 在训练速度方面的性能提高了 1.8 到 3.0 倍。容器覆盖层上 FreeFlow 和 Weave 之间的差距更大。例如,FreeFlow 在 AlexNet 上的运行速度提高了 14.6 倍。其次,FreeFlow 性能非常接近主机 RDMA。差异小于 4.9%,FreeFlow 有时甚至更快。我们推测这是由于测量噪声造成的。
对于语音识别,我们运行一个私有语音 RNN 模型,该模型由双向编码器和完全连接的解码器层组成,隐藏层维度为 1024,词汇量大小为 100k。数据集大小为 4GB,包括 1860 万个样本。在每个训练步骤中,GPU 从一小块“学习”并相互通信以进行同步。图 15(b)显示了每个训练步骤所花费时间的 CDF,包括 GPU 时间和网络时间。同样,FreeFlow 非常接近主机 RDMA。中位数训练时间比 Weave 快 8.7 倍。
Spark
我们在两台服务器上运行 Spark(v2.1.0)。其中一个服务器运行一个主容器,用于调度从属容器上的作业。两个服务器都运行从属容器。Spark [18]的 RDMA 扩展是由闭源实现的。我们从他们的官方网站下载了二进制文件,并没有进行任何修改。
图 16:FreeFlow 上的 Spark 性能。
我们演示了 Spark 发行版附带的基本基准测试 - GroupBy 和 SortBy。每个基准测试运行 262,144 个键值对,值为 2 KB。我们将 Spark 映射器和 Reducer 的数量设置为 8,并且每个都是单个线程。图 16 显示了结果。我们总结了与运行 TensorFlow 相似的观察结果。网络的性能确实会显著影响应用程序的端到端性能。使用 FreeFlow 运行时,性能非常接近在主机 RDMA 上运行,优于主机 TCP,并且比使用 Weave 运行容器的性能高出 1.8 倍。
9. 相关工作
容器中的 RDMA 虚拟化:Mellanox 正在努力扩展 Linux 内核中的网络 namespace 和 cgroup,以适应 RDMA 的网络隔离[34,35]。使用 MACVLAN 将物理接口拆分为多个虚拟接口,为每个容器插入一个或多个接口,并依靠 VLAN 路由将流量传递到正确的虚拟接口。 显然,它在云环境中会有可移植性问题,因为移动 IP 意味着更新硬件中的 VLAN 路由。此外,它不提供灵活的可控性,因为它允许容器直接访问物理 NIC。
另一种方法是使用可编程硬件来处理容器的 RDMA 虚拟化,例如智能 NIC [26]或 FPGA [38]。与基于硬件的解决方案相比,FreeFlow 的优势在于使用商用硬件降低了成本,并且可以更灵活地定制网络功能。
VM 的 RDMA 虚拟化:HyV [39]是最接近 FreeFlow 的解决方案。它还拦截应用程序和 NIC 驱动程序之间的通信,并提供地址转换、QP/CQ 映射和内存映射。HyV 和 FreeFlow 的主要区别在于 HyV 不控制数据路径以在私有集群中提供裸机性能,而 FreeFlow 适用于云环境。这给 FreeFlow 带来了更多挑战,例如使性能仍然接近裸机质量,同时保持数据路径中应用程序的透明性。VMM 旁路 I/O [37]具有与 HyV 类似的设计和问题。VMware 一直致力于对称为 vRDMA 的 RDMA 设备进行半虚拟化[40]。vRDMA 专为 VMware 的虚拟机管理程序和虚拟机而设计,因此,它本身并不适用于容器。
10. 结论
在本文中,我们介绍了 FreeFlow,这是一种虚拟 RDMA 网络解决方案,可提供容器云所需的隔离性、可移植性和可控性。FreeFlow 对应用程序是透明的,并且可接受的开销实现接近裸机的 RDMA 性能。使用实际应用程序和微基准测试进行的评估表明,FreeFlow 可以支持与裸机 RDMA 相媲美的性能,并且比现有的 TCP / IP 虚拟网络解决方案更好。我们开源了 FreeFlow 的原型。
参考文献请查看原文链接,原文地址:
https://www.usenix.org/conference/nsdi19/presentation/kim
来源:NSDI 19
作者:Daehyeok Kim and Tianlong Yu, Carnegie Mellon University; Hongqiang Harry Liu, Alibaba; Yibo Zhu, Microsoft and Bytedance; Jitu Padhye and Shachar Raindel, Microsoft; Chuanxiong Guo, Bytedance; Vyas Sekar and Srinivasan Seshan, Carnegie Mellon University
参与编译:张春海、冉玫美、王泽旺、孙夏、张磊
出品:Clustar
评论