本文转载自: 网络交换FPGA微信公众号
随着摩尔定律中的物理尺寸逐渐逼近极限,但实际应用中人们逐渐通过软件的硬件定制化加速来继续延续着摩尔定律的加速使命,这里面最典型的场景就是计算机网络。如软件的TCP/IP协议栈时延较大,于是就有了硬件化的TOE(TCP Offload Engine),把三次握手建立连接和四次挥手断开连接用硬件的方式来实现了。有了硬件实现的高效的TCP session建立/断开的机制,人们又在此基础上做了网络的存储协议硬件化实现,于是就有了大家平常生活中常用的网盘。上篇文章中Nick McKeown教授团队已经把带有传输层的低延迟NIC线对线RPC响应时间降低到69ns,并且开发了一种带有寄存器文件的直接消息接口的新型CPU-nanoPU,本文继续推荐Nick教授团队在相同的开源工程nanoPU的基础上做的进一步工作,将传输层进行硬件化的定制加速,可以在不到10ns的时间内处理传输层中的数据包,并且可以每2.6ns发出一个新数据包。同时,该硬件化的传输层nano Transport还支持自定义的通信协议,支持P4编程语言,这就意味着,在保障性能的同时,还兼顾了灵活性。
以下内容翻译自论文《NanoTransport: A Low-Latency, Programmable Transport Layer for NICs》。
摘要:传输协议可以在NIC(网卡)硬件中实现,以增加吞吐量、减少延迟并释放CPU周期。如果已知理想的传输协议,那么最佳的实现方法很简单:直接将它烧入到固定功能的硬件中。但是传输协议仍在发展,每年都有提出新的创新算法。最近的一项研究提出了Tonic,这是一种Verilog可编程硬件传输层。我们在这项工作的基础上提出了一种称为纳米传输层的新型可编程硬件传输层架构,该架构针对主导大型现代分布式数据中心应用中极低延迟的基于消息的 RPC(远程过程调用)进行了优化。Nano Transport使用P4语言进行编程,可以轻松修改硬件中的现有(或创建全新的)传输协议。我们识别常见事件和基本操作,允许流水化、模块化、可编程的流水线,包括分组、重组、超时和数据包生成,所有这些都由程序设计员来表达。
我们通过对其进行编程以运行可靠的基于消息的传输协议NDP和HOMA以及混合变体来对评估我们的nanoTransport原型。我们的FPGA原型使用Chisel语言实现并在Firesim仿真平台上运行,展示了P4可编程流水线,设计旨在以200Gb/s的速度在ASIC中运行,每个数据包的端到端处理时间不到10ns(包括消息重组)。
CCS CONCEPTS
• Networks→Programming interfaces; Transport protocols;
• Hardware→Networking hardware.
ACM Reference Format:
https://doi.org/10.1145/3482898.3483365
1. 介绍
现代分布式应用程序在大型服务器组[8,34,62]之间发送大量远程过程调用(RPC)。这促使产生了减少RPC处理时间的新提议,例如通过重新设计网卡(NIC)以减少终端主机上的处理时间(商业产品[14,16,47,48,51,53,66]和研究建议[4,19,25,28,34,36,39,41,43,44,62]),以及新的低延迟传输协议用于减少网络堵塞引起的延迟[3,13,20, 23,24,42,50]。因此,我们将先前的工作进行分类,以减少两个主要位置的延迟:
(1)终端-主机。例如eRPC[34],它是一种结合了许多软件技术的软件设计,可以将中位RPC响应时间减少到1-2us,而NeBuLa[62]是一种硬件设计,它通过绕过PCIe直接将NIC与CPU集成并将到达的RPC请求直接放入L1缓存,从而使RPC响应时间减少到100ns以下。
(2)网络。例如NDP[23],它通过在拥堵的交换机中修剪数据包的数据来缓解广播拥堵,只向接收器发送包头并允许它决定何时重新发送数据包。
显然,如果我们想最小化总体RPC响应时间,我们需要最小化终端主机和网络中的延迟。
在本文中,我们主要研究传输层。我们最感兴趣的是低延迟传输协议的两个方面:一是算法简单,在终端-主机网卡中处理时间最短;二是低延迟,即算法最大程度地减少数据包在网络中传输时的拥塞延迟。
我们的方法是通过将传输层放在硬件中来最小化终端-主机延迟,并通过使硬件可编程来使其他层能够最大限度地减少拥塞延迟。
传输层处理:多年来,在减少软件中传输层处理时间方面做了大量工作。例如,谷歌用于主机网络的微内核方法,Snap[45]报告的端到端尾部延迟为100us。Homa的Linux内核[52]可以实现在大约5us内将来自NIC的传入消息传递到用户线程。eRPC[34]通过针对常见情况进行仔细优化,报告了使用Timely[49]拥塞控制协议的小型32字节RPC的线对线延迟为850ns。
目前报道的带有传输层的低延迟NIC整个系统的最快组合是nanoPU[28],它具有中位线对线RPC响应时间为69ns,使用到CPU寄存器文件的直接消息接口,一个硬件线程调度器以及固定的基于NDP的传输层(处理时间为7ns)。
我们很容易认为我们已经完成了:将处理路径再减少几纳秒会有很多好处吗?nanoPU完全在硬件中处理数据包,直到RPC在线程中请求开始处理为止。似乎没有什么空间可以进一步减少延迟。
然而,网络中延迟可能仍有改进的空间。传输层拥塞控制算法的设计会对网络延迟产生重大影响。事实上,研究人员不断提出新的协议来降低RPC消息的网络延迟[1-3,7,13,20,23,24,50],云服务提供商也报告了新算法的设计和部署[38,42,49,68]。至于哪种算法最好,目前还没有定论,而且可能不存在单一的最佳算法;相反,它可能取决于特定的数据中心拓扑和特定的分布式应用[57]。例如,在§5.2中,我们展示了NDP和Homa各自优于对方的场景。
传输协议的一个不同之处在于对吞吐量和延迟(中位和尾部)给予的相对重要性。众所周知,即使RPC请求平均地快速返回结果,尾部延迟通常也决定了应用程序的性能,特别是当它向不同的服务器发起多个RPC请求并且必须等待所有服务器返回才能取得进展。随着级联RPC数量的增加,长尾延迟的可能性增加,从而定义了整个系统的端对端性能[17]。
正确的取舍最好由云服务提供商来决定。但是,如果将传输协议烧入到固定的功能硬件中,则修改它是一件昂贵且耗时的任务。这一现象促使Tonic[4]的作者提出一种可编程硬件设计形式的传输协议,该方案“利用传输逻辑中的常见模式来创建可重用的高速硬件模块。”他们的设计假定传输层将在FPGA上实现,并且程序员将使用Verilog[29]硬件描述语言来实现新的算法。由于Verilog需要一个陡峭的学习曲线,因此作者提供了一个NS3模型来帮助用户设计新的协议层。基本模型是,一旦建立了传输连接,内核就会将连接状态和数据包处理卸载到NIC。Tonic原型使用环形缓冲区和位图来跟踪连接状态,并通过128字节数据包实现100Gb/s的速度,并且能够在大约100ns的时间内处理一个数据包。
虽然一些网卡可以在FPGA中实现的,但专用集成电路(ASIC)因其高性能、低功耗和低成本而成为发展趋势。我们着手设计一个受Tonic启发的可编程传输层,在FPGA上进行了原型设计,但针对在ASIC上的实现进行了优化。我们把我们的设计称为nanoTransport,它在几个方面扩展了Tonic。第一,nanoTransport被设计为在ASIC中运行,并使用P4语言进行编程[11],与FPGA相比,它可以实现约10倍的数据包处理速度。P4流水线技术已经在现代商业NIC中被使用[47,53,66],并且一个行业组织正在为P4可编程智能网卡[18]创建一个标准的便捷式架构。第二,广泛的传输协议共享一组共同的触发事件(例如 :数据包到达、超时、重复确认),并且nanoTransport利用了P4更简单且被广泛接受的抽象。它使接口能够以可编程的方式触发事件,灵感来自事件驱动的P4数据包处理框架[26]。第三,nanoTransport实现了传输协议的发送方和接收方客户端,而Tonic仅用于卸载发送方协议。最后,我们的设计是精简的,它可以在不到10ns的时间内处理传输层中的数据包,每2.6ns发出一个新数据包。
NanoTransport专注于减少与传输相关的处理延时。在传输处理之后将消息传递到应用程序线程的延迟涉及内核选择和线程调度等机制,这些机制都超出了nanoTransport的范围。因此,为了验证一个完整的可编程系统,我们在开源的nanoPU设计框架上构建了nanoTransport原型。1这允许其他人试验我们的设计,尝试新的传输协议并改进我们的工作。但是,我们的可编程传输层并没有绑定到nanoPU;它可以在任何NIC中用作独立的、P4可编程的流水线,将传输层卸载到硬件—例如,现代NIC中的RDMA处理流水线。
总而言之,nanoTransport的主要贡献有:
① 我们确定了传输协议中一组通用事件的接口,这些接口可以用作可编程解决方案的原语。
② 我们观察到传输协议处理可以用P4编程语言有效地表达。
③ 我们在硬件上构建并评估了第一个P4可编程传输层,它可以添加到nanoPU系统中,或者独立于RDMA网卡流水线。
④ 我们提供了一个基于开源FPGA的nanoTransport原型,即使对于小数据包也能以200Gb/s的速度运行,同时保持每条消息不到100字节的状态。
⑤ 在我们的设计中,一个数据包可以在11ns(中位延迟和尾部延时)内被确定性处理,包括入口和出口路径。这比常见的基于软件的实现方案低三个数量级,比Tonic低一个数量级。
⑥ 我们在NS3[54]中提供了nanoTransport的行为模型,以帮助设计人员在编程硬件之前大规模评估新的传输协议和算法。
本文的其余部分在§2中描述了nanoTransport的构建模块,在§3中描述了设计细节,在§4中描述了原型FPGA实现,在§5中描述了原型评估。我们在§6中讨论了可编程硬件传输层的用例、可行性和局限性。
2. 传输层剖析
尽管存在差异,但大多数传输协议都有大量相同的特性。在本节中,我们将探索并列举一些常见的共同特性,这些特性将在后面作为nanoTransport设计的基础。
>2.1 协议分类
一般来说,传输协议有两种类型:WAN(广域网)协议,例如TCP NewReno[21],CUBIC[22]和BBR[12];和DC(数据中心)协议,例如RoCE [46],DCQCN [68] 和Timely [49]。
WAN协议专为长期、可靠的双向字节流而设计的,主要性能指标是吞吐量和公平性。连接是通过在两端安装每个连接状态的握手建立的,并在连接期间保持连接。由于WAN RTT通常为1~100ms,所以终端主机的微秒级改进不会增加太多价值,而我们的重点是低延迟。因此,我们在设计中不会考虑这种类型的协议。
另一方面,数据中心协议主要用于在服务器之间交换小消息[5,55]。RTT只有几微秒,延迟敏感的应用程序可以从终端主机处理时间的进一步微秒级减少中受益[23,24,50]。因此,nanoTransport专注于延迟敏感、可靠、基于消息的传输协议,主要用于数据中心。
具体来说,nanoTransport旨在允许用户设计低延迟、可靠的单向消息服务。
小消息通信的一个(有益的)结果是不需要持久的连接状态。这减少了NIC跟踪当前活动消息所需的内存量,从而使速度更快、功率更低的单芯片ASIC解决方案成为可能。
>2.2 构建模块
我们的可编程硬件传输层有两个服务接口:下面一个,它与以太网MAC交换以太网帧。上面一个,它与CPU内核或者RDMA引擎交换完整的、重组的、可靠的消息。无论协议细节如何,nanoTransport上可靠的基于消息的传输协议必须满足:
① 将传出消息拆分为一个或多个数据包。数据包被存储以供再次重发,直到成功传送到接收器。
② 将传入的数据包重新组装成消息。无序到达的数据包在重组过程中会被重新正确排序。
③ 监测计时器以触发数据包重传或在重复失败时取消消息。
④ 监测每个正在进行的消息的状态,例如,可以允许拥塞控制逻辑决定下一个发送哪个分组以及何时发送。
⑤ 生成控制数据包以通知消息状态或拥塞,例如,ACK,NACK和GRANT。
我们工作的一个关键观察是,只有最后两个功能(监测每条消息的状态和生成控制包)需要可编程性来支持不同拥塞控制算法。其他功能是固定的,对于我们遇到的所有可靠的面向消息的传输协议都是通用的。
Tonic做了类似的观察[4],并选择使用位图来跟踪消息状态,并确定下一个要发送或者重发的数据包。NanoTransport将这些位图保存在重组和分组模块中,紧挨着相关的数据包数据。不同的协议在发送和接收数据或控制数据包时修改位图的方式、检测数据包丢失的方式以及处理丢失数据包的方式不同。nanoTransport程序设计者通过P4 externs[64]和扩展P4元数据字段来确定如何触发和处理事件(例如数据包到达、数据包丢失检测、数据包确认)。§3中对我们的设计进行了更详细地描述。
3. 架构设计
图1展示了nanoTransport体系架构。该流水线位于外部以太网数据包接口(MAC)和CPU内核(或RDMA引擎)之间,外部以太网数据包接口用于交换以太网帧,CPU内核用于交换完全组装好的、随时可用的消息。流水线是独立的,代表CPU处理传输层的所有方面。配置和初始化流水线都需要CPU,但为了最大限度地减少延迟,CPU不参与处理单个数据包。
该设计采用深度流水线,以便并行处理多个数据包(最大限度地提高吞吐量),但不会太深(以保持较低延迟)。每条输入、输出流水线都包含固定和可编程模块的混合。除了当触发某些明确定义的事件外(在§3.4.1和§3.4.2中描述),这两条流水线也独立运行。
我们从处理到达和离开数据包的高级步骤开始,然后深入到每个阶段:到达 NIC1的数据包首先由可编程输入流水线处理,其中协议特定的逻辑将确定如何处理数据包。然后GetRxMsgInfo外部变量被称为2,此外部变量使用流标识符,例如5元组或唯一消息ID来获取(或分配)重组模块中的每个消息状态。每个消息的状态对所有协议都是通用的,并在§3.3.1中进行了描述。根据协议,输入流水线还可以选择触发CtrlPktEvent3,这会导致数据包生成器生成控制数据包(确认、授权或NACK等,取决于协议)以响应输入数据包4。原始数据包被传递到重组模块5,该模块存储并检查消息是否完整。重组模块维护并更新输入数据的消息计时器6.如果计时器超时(指示消息接收失败),则消息的所有状态都将被垃圾收集。收到所有消息的数据包后,它们将按正确的顺序重新组合并作为完整消息转发到CPU(或RDMA引擎)7。
在输出方向,当消息从应用程序线程8发送时,它存储在分组模块中,该模块将消息划分为MTU大小的子段并初始化每个消息的状态变量。每条消息的重发计时器设置为9;如果它超时,则可能会重新传输某些消息的数据包。当分组模块发送一个数据包时,它会被仲裁器10排入队列,仲裁器会安排它与来自数据包生成器的输出数据包一起离开。最后,数据包通过可编程输出流水线11,在数据包被发送到网络之前,会在其中添加特定于协议的报头。
接下来,我们详细描述每个块,并提供用于事件处理的API签名。
>3.1 可编程组件
该流水线包含以下可编程模块:P4可编程PISA流水线和数据包生成器模块。PISA流水线:PISA(协议独立交换机架构)[10]流水线提供了一个简单的匹配动作抽象,允许通过执行 P4 程序 [11] 来快速、灵活地处理数据包。我们的设计为输入和输出提供了单独的PISA流水线。每条流水线都包含一个标准的P4库(core.p4),以及几个支持nanoTransport特定事件处理逻辑的自定义外部变量。用户对流水线进行编程,以解析和发出特定于协议的报头,并触发固定功能块中的预定义事件处理逻辑。
典型的输入流水线流从到达解析器的数据包开始,然后是匹配表。匹配表被编程以匹配特定于协议的事件,这是执行大多数特定于协议的功能的地方。例如,可以对输入表进行编程以匹配数据包(例如ACK)作为响应。如果输入数据包是控制数据包(例如,来自远程端的ACK分组),则输入流水线会对其进行处理,然后将其丢弃。
在输入端处理之后,数据包到达重组模块,并携带清单1中所示的元数据。元数据包括远程发送者的IP地址和端口号;以及发件人选择的唯一消息ID(tx_msg_id)。这三个字段用于将消息映射到本地唯一的ID(rx_msg_id)。pkt_offset字段表示该数据包在它所属消息中的偏移量。
清单 1:从输入流水线传递到重组模块的元数据以及数据包有效载荷。
输出流水线的主要工作是为输出数据包创建正确的的数据报头。仲裁器将原始数据包有效荷载传递给输出流水线,后者使用附带的元数据构建正确的数据包报头。输出端元数据如清单2所示。credit值表示当前被授权为此消息发送的最高数据包偏移量。rank是输出数据包的排队优先级。例如,在Homa中,credit值表示接收方授予了哪些数据包,而rank值决定了该数据应该使用哪个网络内优先级队列。消息中的第一个数据包设置了is_new_msg标志来初始化消息处理逻辑。is_rtx标志用来标识重传的数据包以防协议需要以不同的方式处理这些数据包。
清单2:与数据包负载一起传递到输出流水线的元数据。
除了报头处理,在 PISA 流水线中传输协议保持协议特定的状态。例如,NDP 在输入流水线中保持状态以识别在 PULL 控制数据包中请求哪个数据包。虽然 P4 不能用于实现有状态逻辑是一个常见的误解,但读-改-写 (RMW)“寄存器”操作经常向程序员公开,用于匹配操作流水线中的有状态数据平面应用程序。§3.2 中描述了 nanoTransport 的PISA 流水线中的状态原语,§5.2中讨论了它们使用的可行性。
数据包生成器。用户对数据包生成器进行编程以发送特定于协议的控制数据包,例如 NDP [23] 中的 NACK 数据包、Homa 中的 GRANT 数据包和 HPCC [42] 中的 INT 确认。该模块由来自输入流水线的 CtrlPktEvent外部变量进行调用触发,它本质上是一个镜像数据包,其中包含清单 2 中所示的元数据。输入流水线设置的元数据确定要生成的控制数据包。
不同的传输协议以不同的时间和速率以及不同的格式生成控制数据包。例如,NDP 调整其传出的 PULL 控制数据包,用于告诉发送方何时重新发送修剪后的数据包。PULL 数据包必须在特定时间发送。HPCC在反向输出的数据包中搭载了一个模板,以携带路径上交换机添加的INT报告。幸运的是,操作范围相当小。
>3.2 状态原语
本节描述了状态原语,程序员可以在输入端和输出端PISA流水线中使用这些原语来开发特定于协议的功能。在对低延迟传输协议进行调查后,我们确定了实现各种算法所需的原语列表。这些原语实现了各种读-改-写(RMW)操作,并作为P4外部程序展示给数据平面程序员。Sivaraman等人,[60]提出了以下一组在许多数据平面应用中都很有用的状态原语:
我们发现,对于某些传输协议(例如NDP),这些操作就足够了。然而,其他协议(例如Homa)需要更复杂的状态原语,例如多端口内存,以便在流水线状态之间以及输入端和输出端流水线之间共享状态变量。
此外,nanoTransport还包括一个优先级调度器,它作为P4外部变量向程序员公开。调度程序可以使用用户提供的优先级值和谓词函数来存储和比较多个有状态对象。程序员可以插入和删除对象,并更新现有对象的优先级。调用时,调度程序将返回谓词评估为真的最高优先级对象。§4.4描述了我们如何使用优先级调度器和其他原语来实现Homa的SRPT消息授权逻辑。这个原语对于其他协议也是有用的[3,20,24]。
根据我们的调查,NDP和Homa是两个需要所有已识别原语的协议。因此,我们评估了nanoTransport在这些协议上的性能。§6.2进一步讨论了在nanoTransport上实现其他协议。
>3.3 重组模块
重组模块负责以正确的顺序传递消息数据。如果消息内的数据包无序到达(例如,由于逐个数据包的多路径路由或重传),则重组模块会在将消息传递给应用线程之前对它们重新正确排序。由于数据包重新排序逻辑与协议无关,因此nanoTransport使用固定的功能块来处理它。
重组模块为每条消息维护一个位图,称为receivedBitmap,其中每个位对应于消息中的一个数据包。2到达重组模块的每个数据包都存储在相应的缓冲区中。如果在相应的元数据上设置了is_last_pktflag,则模块会将整个消息转发到内核。is_last_pkt标志将在下面描述的GetRxMsgInfo外部变量调用期间进行计算。
· GetRxMsgInfo外部变量
维持receivedBitmap以允许消息重组,并确定下一步要发送哪些数据/控制数据包。位图状态由输入流水线通过使用get_rx_msg_info_req_t元数据调用外部变量来获取。GetRxMsgInfo外部变量的输入和输出元数据的内容如清单3所示。
输入元数据中的mark_Received标志表示外部调用是否应该更新receivedBitmap。如果为真,则在生成输出元数据之前将索引pkt_offset处的值置为1。3剩余的get_rx_msg_info_req_t元数据被用作重组模块中rx_msg_id_table的匹配字段,该查找表为到达的消息产生唯一的本地分配的rx_msg_id。如果表中没有匹配的条目,则从空闲ID列表中分配新的ID。
GetRxMsgInfo外部变量返回get_rx_msg_info_resp_t元数据,包括消息的rx_msg_id和消息对应的状态。失败标志表示重组模块无法为该消息分配资源,程序员决定输入流水线如何处理此类消息。is_new_msgis用于初始化新消息的数据包处理逻辑。is_new_pkthelps预防处理重复的数据包。is_last_pkt表示receivedBitmapp中的所有位都设置为1。该值与数据包一起传递到重组模块,来标记消息完成。
>3.4 分组模块
NanoTransport接受来自应用程序线程的完整消息,并将它们分解成以太网数据包进行网络传输。
除了存储消息数据外,分组模块还维护消息的状态变量,类似于[4],以便模块可以跟踪发送方和接收方之间的通信。状态变量及其作用如下所示:
deliveredBitmap:跟踪哪些数据包被传送到目的地。可以将输入流水线编程为触发DeliveredEvent来更新此位图值。最终,当消息的所有数据包都被传送时,分组模块清除分配给该消息的存储器。
credit:允许传输最大pkt_offset值。允许将所有较小的pkt_offset值发送到网络中。输入流水线中的协议逻辑使用CreditTxEvent来更新此值。
txBitmap:跟踪要(重新)/传输的数据包。为了发送数据包,分组模块需要从该位图中选择值为1的最小索引,然后将对应的值重置为0。可以触发CreditTxEvent来将该位图中的值设置回1进行重传。
maxTxPktOffset:跟踪到目前为止发送的最高pkt_offset值。确定超时后要重新传输数据包。
timeoutCnt:跟踪消息在未更新maxTxPktOffset值的情况下收到的超时次数。如果该数值高于配置的阈值,分组模块将放弃该消息,并清除分配给它的所有内存。
分组模块还存储消息ID,发送方和接收者的端口号以及接收者的IP地址。每当发送一个包时,都会从这些值生成清单2中所示的输出元数据。分组模块从内存中选择具有允许发送的数据包的消息。具有最小允许索引的数据包与元数据一起转发给仲裁器。
下面,我们描述用于更新分组模块的状态变量的事件。
· DeliveredEvent
通知分组模块数据包已成功传送到远程主机。发送方在deliedBitmap中设置相应的位,这样数据包就不会在将来被重新传输。通常,收到的确认数据包会触发此事件,这由程序员决定。Algorithm1显示了此事件触发的主要处理逻辑。ackBitmapi是由输入流水线创建的位图,用于指示将哪些数据包标记为已发送。
· creditTxEvent
表示消息当前允许发送更多数据包(新数据或重传)的信号。txBitmap被修改以识别当下一次有足够的credit来传输一个数据包时,可以发送哪些数据包。例如,在HOMA,到达的Grant数据包触发此事件。Algorithm2显示了由事件触发的主要处理逻辑。rtxBitmapi是指示要重传哪些数据包的输入自变量。它是由输入流水线在程序员的控制下设置的。例如,NDP为修剪后的数据包设置NACK数据包的位。一个协议可能需要同时重发几个数据包,例如选择性NACK类似于SACK[31]。
· TimeoutEvent
当元数据调用rtx_Offset时,分组模块中的每条消息都会启动计时器模块中的一个计时器。元数据是在调用计时器时为消息传输的最高PKT_OFFSET。当计时器超时后,计时器模块触发分组模块的Timeout Event来计算要重新传输的数据包。所有偏移量小于rtx_offset 的未传送数据包都被重传。最后,为相同的消息调用一个新的计时器,以考虑将来的重传。Algorithm3显示了该事件触发的处理逻辑。计时器模块如何工作的详细说明见§3.5。
到目前为止,我们的经验是,固定功能超时事件处理对于多数传输协议来说已经足够了。但是,有些协议可能需要以不同的方式处理超时事件。例如,计时器事件可能需要生成控制数据包,或者定期更新输入/输出流水线中的协议状态。因此,未来版本的nanoTransport架构可能也会因将超时事件处理设置为可编程而受益。
>3.5 计时器模块
计时器需要用于两个目的:(1)识别尚未被确认并且需要重发的数据包;(2)识别长时间空闲(尚未发送或接收数据包)的消息;即,清理每条消息的软状态。
软件实现可以为每个数据包维护一个计时器。在硬件方面,根据网络的BDP和配置的超时时间为每个传输中的数据包维护一个计时器是一项挑战,可能会有大量的数值。为了减少内存需求,nanoTransport为每条消息维护一个计时器。
当应用程序向分组模块写入新消息时,输出端计时器模块的ScheduleEvent被触发。此事件为相应的消息以及关联的元数据创建新的计时器。当该计时器超时后,分组模块的超时事件被触发。此事件可能会也可能不会导致为同一消息安排新计时器。当消息成功传递到远程客户端时,分组模块在删除消息的状态之前会在计时器模块内触发CancelEvent.。此事件确保不会留下任何可能会错误超时的计时器。
类似地,当消息的第一个数据包到达重组模块时,输入端计时器模块的ScheduleEvent会被触发,从而为相应的消息创建一个新的计时器。由于在输入方向上没有重传的概念,因此该计时器仅用于丢弃来自重组模块的消息的状态。为了防止超时,每个到达的消息包都会触发ReScheduleEvent,主要是重置计时器。最后,完整的消息信号CancelEvent使输入端计时器模块中的关联条目无效。
4. 硬件实现
我们的nanoTransport原型通过添加2500行Chisel[6]代码和1000行P4代码扩展了开源nanoPU设计[28]。我们使用Firesm[35]在WS FPGA[59]上对我们的原型进行大规模、精确的周期模拟。这使我们可以评估我们设计的端到端功能和性能。以下各节提供了我们的nanoTransport原型的详细信息。
>4.1 可编程模块
我们使用P4和Xilinx SDNet4[61]实现了输入和输出流水线。SDNet编译器生成具有所需功能的Verilog模块,我们将其集成到nanoTransport原型中。我们使用Synopsys VCS[63] 周期性精确模拟验证设计的正确功能,但是,由于许可限制,我们目前无法在WS FPGA上使用SDNet生成的模块。因此,我们将P4代码手工编译成Chisel,这样我们就可以在WS FPGA上使用Firesm来评估整个系统。§5中描述的评估结果使用的是我们手工编译的P4代码。每个P4程序都作为自定义流水线实现,类似于SDNet将P4程序映射到FPGA的方式。ASIC原型将具有固定数量的流水线阶段,所有程序都必须映射到这些阶段;我们计划在未来的工作中探索这种方法。
回想一下,nanoTransport中的数据包生成器是一个可编程模块。当处理来自输入流水线的CtrlPktEvent时,数据包生成器在(可选地)调整其传输速率的同时可以生成一个或多个控制数据。我们观察到,这些操作并不适合P4流水线,P4流水线通常用于转换单个数据包。因此,在我们目前的原型中,我们使用Chisel对数据包生成器进行编程。我们将在以后的工作中探索更方便、更高级的抽象来生成可编程的数据包。一种可能性是将P4与新的自定义外部变量一起使用,以在流水线内拆分(复制)和调整数据包。
>4.2 重组和分组模块
重组模块将可能无序到达的数据包重组成连续的消息,以便传递给应用程序。分组模块将消息分成多个数据段,这些字段可能会由于网络中的数据包丢失而被乱序重传。为了以线速执行这些任务,我们必须使用只需要恒定时间操作的简单数据结构。我们可以从几种不同的方法中进行选择;本节描述了我们原型中的缓冲区设计。
我们的消息缓冲区被划分为几个不同固定大小的缓冲区,每个大小类的空闲列表跟踪哪些缓冲区可用。当要分配缓冲区时,选择足够大以存储整个消息的最小可用缓冲器。对于消息重组,当消息的第一个数据包从网络到达时分配缓冲区,并且当消息被转发到处理核心时释放缓冲区。5对于消息分组,当应用写入消息的第一个字时分配缓冲区,并且当整个消息被成功传送到接收器时释放缓冲区。该设计使用按消息标识符索引的表来跟踪每条消息的存储位置(缓冲区指针)。
使用固定大小的缓冲区存储消息的好处之一是,它简化了无序重组和重传:要找到特定数据包在消息中的位置,硬件只需将适当的偏移量添加到消息的缓冲区指针即可。此外,管理内存缓冲区所需的逻辑非常简单,可以线速运行。缓冲区分配需要从空闲列表中出队一次,释放缓冲区需要一次入队到空闲列表中;不需要对可变大小的缓冲区进行复杂的分区和合并。
使用固定大小缓冲区的主要缺点是它会导致内存碎片和潜在的较差的缓冲区空间利用率。因此,正确配置这些消息缓冲区模块非常重要。配置包括选择如何将总缓冲区空间划分为固定大小的缓冲区。如果在配置时知道消息大小分布,则通常可以实现非常高的缓冲区利用率。
>4.3 计时器模块
NanoTransport架构中的计时器模块为重组/分组模块中的每条消息维护一个计时器以及相关的元数据。我们的目标是最大限度地减少内存和逻辑需求,同时确保可以在固定时间内安排或取消计时器。此外,由于计时器用于触发数据包重传或在后台进行垃圾收集,因此我们不需要计时器精确准时超时,也不需要它们以正确的顺序超时。主要要求是它们在有限的时间内超时。
这些需求导致了非常简单的硬件设计。每条消息的计时器存储在按消息ID索引的单个存储器中。该表项包含以下字段:一个表示表项是否有效的有效位、一个表示计时器过超时的64位超时值以及相关的计时器元数据。后台线程依次扫描表项并检查计时器是否超时。如果是,它将提取元数据并触发超时事件。调用和取消计时器只涉及将单个表项写入内存。在某些情况下,计时器可能会在后台线程检查计时器之后立即超时,在这种情况下,直到后台线程循环回到计时器时才会触发超时事件。然而,请注意,即使在这种情况下,计时器也会在有限的时间量内超时,这由系统中的最大计时器/消息数量决定。这个简单的设计符合我们的要求。
>4.4 协议实现
为了评估nanoTransport,我们将其编程为支持两种不同的协议,选择它们来代表其他协议[2,3,7,13,20,24]所需的相对广泛的功能。
NDP[23]是我们在原型上编写的第一个协议。NDP由接收器驱动,旨在通过确保快速重传所有丢弃的数据包来缩短网络消息的尾部延迟。当拥塞时,启用NDP的交换机将修剪原本会被丢弃的数据包,只将数据包报头转发到优先级高的接收器。然后,接收方迅速发送否定确认(NACK)以通知发送方数据包丢失。此机制允许NDP避免依赖长时间超时。NDP发送器最初只发送最多一个带宽延迟积(BDP)的数据包;接收器显式拉取其余的数据包,同时调整它们的速度,以确保拉取的数据包的到达率不会超过瓶颈链路的容量。新的数据包在消息之间循环拉取,假设如果一个数据包离开网络,可以插入一个新的数据包而不会使其过载。
Algorithm4为我们在P4中的NDP实现提供了伪代码。该协议使用有状态操作来读取消息先前的credit,并在需要时递增该credit。此操作由IfElseRaw外部变量表示,如§3.2中所述。
Homa[50]是我们在原型上编写的第二个协议。Homa也是一种接收器驱动的协议,但与NDP不同的是,它假设数据包的设计在现代网络中是极其罕见。因此,它只是依靠超时来检测丢失的数据包,而不是利用网络中的数据包修剪。但是,它确实需要交换机至少支持几个严格的优先级队列。此外,Homa旨在通过近似接收方的SRPT[58]调度来最小化消息完成时间,而不是使用循环“拉取”机制。我们使用§3.2中描述的优先级调度程序外部变量来实现Homa的SRPT消息授予逻辑。调度程序维护有关所有活动消息的元数据,我们将rank(即优先级)指定为消息的剩余大小(值越低,优先级越高)。调度程序返回最高优先级的“可授予”消息,其中可授予消息是具有少于一个未完成数据的BDP的消息。消息在被完全授予后将从调度程序中删除。
优先级调度器的实现利用了这样一个事实,即大多数消息都很小(小于1BDP),因此不需要调度;在任何给定时间只需要调度少数消息。因此,调度程序外部变量在寄存器中维护消息状态,以便可以同时对它们进行比较。我们的原型调度器外部变量支持多达16条调度消息用于同时比较,而其余的调度消息(如果有的话)将存储在FIFO队列中,直到寄存器空间打开。
除了调度程序外,Homa还使用两个双端口内存原语(§3.2),如Algorithm5所示。这些双端口存储器中的一个用于维护关于消息的信息-当数据包到达时被数据包访问/更新,然后在决定授予哪个消息之后,才在流水线中进一步更新。另一个双端口存储器用于跟踪正在传输的消息的优先级。输入的GRANT数据包会更新内存,输出的数据包会读取内存。因此,此状态在输入和输出流水线之间共享。
为了评估原型的可编程性,我们创建了一个新的低延迟、可靠的消息传输协议,我们称之为Homa-Tr。Homa-Tr结合了NDP和Homa的功能,就像用户程序员可能会从不同的协议中挑选功能一样。我们选择包括NDP通过在交换机中修剪数据包和发送否定确认(NACK)来快速从数据包丢失中恢复的功能。我们采用Homa的能力,通过按SRPT顺序授予消息以减少消息完成时间。事实证明,通过将NDP的数据包修剪和NACK机制整合到Homa中, Homa-Tr的实现相对快速且简单。评估详情见§5.2。
协议的P4源代码可以在我们的开源架构中找到[27]。我们的NDP和Homa实现分别需要376行和520行P4代码,这比现有的基于软件的实现少了一个数量级的代码。
5. 评估
我们评估了我们在nanoTransport架构上实现的传输协议的性能、正确性和可行性。为了评估性能和正确性,我们在带有Firesm[35]的WS FPGA[59]上运行微基准测试和精确周期性模拟的端到端实验。FPGA的工作频率为90 MHz,模拟目标CPU和网卡的时钟频率为3.2 GHz。本节中报告的所有结果都基于3.2 GHz的目标时钟频率。为了评估在硬件中部署我们设计的可行性,我们检查了FPGA的资源利用率,并与传统的开源NIC(IceNIC)[35]进行了比较,后者没有在硬件中实现传输层。
硬件原型的设计、实现和测试周期是缓慢且昂贵的(即使在FPGA上也是如此)。然而,传输协议设计者通常需要进行大规模实验来验证协议的功能性和有用性。为了简化开发过程,我们还为在NS3中的nanoTransport架构开发了一个基于C++的行为模型[54]。在对硬件进行编程之前,首先使用NS3对协议进行规模测试。由于我们的NS3模型和硬件原型的性能结果是相同的,因此我们在这里省略它们。NS3行为模型的源代码作为开源工件的一部分与硬件原型一起提供[27]。
>5.1 延迟和吞吐量基准测试
NanoTransport设计以200 Gb/s的速度处理数据包,对于1088字节的数据包,200 Gb/s意味着每隔44 ns就可以发送或接收一个新的数据包。我们在§5.2中描述的incast实验中证实了这一点。
我们还评估了最坏情况下的流量模式的最大吞吐量。为了测量RX吞吐量,我们以200 Gb/s(380 Mrps)的速度向nanoTransport接收器发送65字节的小数据包。每个数据包是单独的消息,携带1字节的有效载荷以及64字节的数据包报头。我们验证最小大小的输入消息是否以线速转发到核心。在发送端,我们在核心上生成相同的工作负载,并验证传出消息是否以线速传输到线路上。我们的原型能够在NDP和Homa实施的最坏情况下支持200 Gb/s的目标吞吐量。
Table 1显示了我们的NDP和Homa实施的RX和TX延迟细目。Homa的输入和输出流水线分别使用五级和两级,由于其中央消息调度决策,延迟略高,而NDP仅使用三级和一级。级的数量由外部调用/存储器访问之间的顺序依赖性确定。然而,传输处理在输入路径中最多需要7.2 ns,在输出路径中最多需要3.8ns,导致最大传输层往返时间为11 ns。
NanoTransport的延迟比Homa Linux Kernel Module报告的4.8us低三个数量级[52]。通过Linux网络堆栈的延迟对中断处理开销和OS线程调度决策非常敏感。Ousterhout[52]报告了Homa、TCP和DCTCP的静态往返延迟分别为15.1us、23.4us和24.1us。
eRPC[34]是一个最先进的低延迟软件网络堆栈,报告的线对线延迟为850ns。很难将nanoTransport直接与eRPC的传输层进行比较。然而,本文报告的测量结果表明,拥塞控制逻辑增加了平均17.8ns的每包软件延迟,这与nanoTransport的延迟相当。也就是说,这种测量是在网络没有拥塞的最佳情况下报告的,因此几乎所有数据包都绕过了大多数拥塞控制逻辑。另一方面,表1中报告的nanoTransport延迟值是确定的。此外,eRPC测量不包括传输协议的其他方面,例如消息分组/重组或重传逻辑。最后,由于在软件中运行,单个eRPC内核只能最多处理约10Mrps的吞吐量,这比流水线nanoTransport设计低约38倍。
>5.2 端对端评估
为了评估端到端性能、架构和协议功能的实现(即 NDP、Homa 和 Homa-Tr),我们使用Firesim进行了incast实验。在这些实验中,10个发送者每人同时向同一接收者发送一条消息。每条消息都有不同的大小,范围从20到38 MTU大小(1088B) 不等的数据包。本实验在简单的哑铃拓扑上运行;瓶颈链路是接收器的下行链路。发送方和接收方之间的RTT为525 ns,所有链路的速率为200 Gb/s。我们进行了两个实验,一个是瓶颈缓冲区大小足以吸收incast,另一个是瓶颈缓冲区太小,无法吸收incast,导致丢包和/或修剪。
我们通过检查incast的数据包跟踪来验证协议程序的正确性。图2显示了每个实验中的瓶颈队列占用率。正如预期的那样,NDP客户端每次收到一个数据包时都会提取一个数据包,因此,在某些消息完成之前,传输中的数据包总数以及队列占用率都会保持较高水平。另一方面,Homa客户端仅为少量消息发送GRANT,这使得队列占用率在第一次RTT事件后稳定在较低的水平。
图2b显示了两个实验中每条消息的消息完成时间减慢。我们将减慢定义为实际消息完成时间与网络中没有任何拥塞的理想完成时间的比率(越小越好)。
当缓冲区较大时,数据包不会丢失,从而使NDP和Homa都能顺利地从发送方PULL/GRANT新数据包。然而,Homa实现了较低的减速,因为消息是按SRPT顺序授予的-这是一种旨在最小化消息完成时间的策略。由于较大的消息要等到较小的消息完成,所以Homa的速度会随着消息大小的增加而增加。另一方面,NDP以循环方式拉取消息,导致所有消息的速度都有类似的高减速。
当缓冲区尺寸太小而无法吸收incast时,协议的相对性能会完全改变。在这种情况下,NDP能够实现较低的减速,因为它使发送者能够使用数据包修整和NACK快速重传丢失的数据。另一方面,Homa依靠超时来检测数据包丢失。因此,NDP仍然对所有消息实现类似的减速,而Homa完成消息需要更长的时间。
我们对nanoTransport原型进行了编程,以实现一种名为Homa-Tr(§4.4)的新协议,该协议结合了Homa和NDP的特性。Homa-Tr将NDP的数据包修剪和Nack机制合并到Homa中,以便按SRPT顺序授予消息,同时实现从数据包丢失中快速恢复。图2b显示,当缓冲区大小足够大时,Homa-Tr的性能与Homa完全相同。然而,当缓冲器大小减少一半(54KB)时,Homa-Tr能够快速地从丢失中恢复,并且与 Homa 相比实现了约2 倍更好的减速和与 NDP 相比约1.5 倍更好的减速。
实验结果表明,nanoTransport架构可以被编程为运行不同的低延迟协议,并且我们协议实现的行为符合预期。
>5.3 可行性
我们评估了在硬件中实现可编程传输层的成本。图3显示了我们的NDP和Homa实现的FPGA资源利用率。为了衡量在硬件中放置传输层的成本,我们将nanoTransport使用的资源与称为IceNIC[35]的基线进行了比较,后者不实现任何传输处理。
像IceNIC这样的基本NIC非常简单:它包含以太网头解析、一些临时内存和用于在主机内存之间传输数据包的DMA逻辑。相对于IceNIC,nanoTransport添加了上面描述的所有传输逻辑,图3显示NDP的逻辑和触发器利用率增长了大约30%,Homa增长了60%。这既反映了IceNIC的简单性,也反映了nanoTransport的额外复杂性:表2显示,nanoTransport消耗的逻辑和触发器不到Virtex UltraScale+FPGA的2%[67];它需要的ASIC要小得多。
与IceNIC不同,NanoTransport还需要内存来进行分组和重组。内存量大小取决于并发消息的数量。当nanoTransport被设计为支持多达16条并发39kB消息时,它需要大约1.2MB的片内SRAM7(表2)。相反,如果支持128条并发39kB消息,则消耗8.4MB,在现代7 nm ASIC上占用不到2mm。2内存需求随支持的并发消息数量线性增加。
我们得出结论,nanoTransport可以很容易地添加到现代NIC中。现代NIC ASIC已经包括数十MB的板载SRAM[66];为可编程、低延迟、可靠的消息传输层添加逻辑和内存似乎是相对较小的额外成本。
6. 讨论
>6.1 FPGA与ASIC
我们的原型是构建在FPGA上运行,作为概念验证和评估平台。然而,对于基于FPGA的NIC来说,我们的设计不一定是正确的选择,因为FPGA本身可以使用Verilog针对新的传输协议进行重新优化。
然而,ASIC大多比FPGA运行速度更快,消耗更少的功率和更少的成本(15)。nanoTransport在FPGA上进行测试时,设计用于在定制NIC ASIC中实现。在未来的工作中,我们计划综合nanoTranspor设计并开发ASIC实现,可能使用RISC-V CPU内核。
>6.2 编程新协议
到目前为止,我们在运行低延迟接收器驱动协议NDP、Homa和Homa-Tr时对nanoTransport进行了编程和评估。为了进行比较,我们还评估了将nanoTransport编程为运行HPCC[42]所需的资源,HPCC是发送方驱动的(而不是接收方驱动的)。HPCC发送器检查每个数据包中的INT报告堆栈[37],确定瓶颈链路,并计算新窗口大小。如果交换机能够生成INT报告,则nanoTransport中的PISA流水线可以用于处理INT报告。如果需要,P4可编程交换机可以利用PINT[9]中提出的优化来减少NIC中的处理量,从而减少流水线级数。8然后,发送器nanoTransport客户端可以使用P4流水线中的简单查找表来计算拥塞窗口大小。
我们还评估了DCQCN[68]和Swift[38]的实现,它们都需要在NIC进行浮点运算来计算速率和拥塞窗口。我们的nanoTransport原型不支持浮点运算。这就留下了三种设计选择:(1)在硬件中向P4流水线添加浮点;假设我们需要大约每秒2亿次浮点运算,这在现代ASIC中相对简单;(2) 使用更高精度的浮点算法,这在开关 ASIC 中已经支持 [30],或(3)在P4流水线中使用查找表。我们预计ASIC的实现将利用所有这三种技术。
>6.3 多并发协议
CPU可能承载多个应用程序,每个应用程序都需要高性能传输协议;因此,NIC可能需要同时支持多个协议。例如,它可以为RPC提供尾部延迟优化协议,同时为同一应用程序的批量传输流量运行吞吐量优化协议。
如果有足够的资源,nanoTransport可以做到这一点。本质上,可编程解析器根据数据包报头中的传输协议标识符进行分支,并且应用相应的控制逻辑。
协议设计者需要小心避免网络中不同传输协议之间的不良交互。这并不是nanoTransport所特有的,这是所有云服务提供商都需要解决的问题,无论传输层是在硬件还是软件中。例如,Homa和NDP都假设其接收方是唯一为输入消息分配瓶颈带宽的实体。如果链路与non-GRANTed/PULL流量共享,则Homa和NDP的PULL/GRANT机制可能过度/不足利用瓶颈链路。
>6.4 加密和压缩
出于安全原因,网络运营商可以选择在其网络中使用加密通信。现代NIC通常包括用于端到端加密的专用硬件模块,以及压缩进出存储的数据[47,51,53]。虽然我们的原型中没有包含这样的模块,但nanoTransport的ASIC实现可以很容易地将它们包含在其处理流水线中。
>6.5 序列化RPC数据
低延迟可靠消息协议经常携带RPC请求,这些请求需要在两端进行序列化和反序列化。最近观察到,这个过程会给RPC请求增加相当多的延迟[65]。Zerializer展示了如何在硬件中进行编组和解编组。虽然超出了本文的范围,但我们预计nanoTransport的ASIC实现会将这些功能添加到硬件P4流水线中。
>6.6 可拓展性
在设计nanoTransport ASIC时,一个关键的设计选择是SRAM的大小。一旦在设计时选定,所有编程的协议都需要在约束范围内运行。这意味着ASIC设计者需要预先决定可以支持多少消息,以及最大消息的大小。我们的原型支持多达128条并发32KB消息,这对于Homa和NDP来说是合理的。但是,在将大小提交给ASIC之前,需要更仔细地研究其他传输协议。
在选择P4流水线级数的数量时也需要仔细考虑,这又决定了可以在每个数据包报头上执行多少串行相关的操作。与目前商业P4流水线通常支持的10-20个级数相比,我们的NDP和Homa项目需要的级数要少得多;然而,在致力于ASIC设计之前,应该对更多的协议进行评估。
>6.7 其他使用情况
除了RPC之外,还经常为 RDMA 操作发送小消息。通常,支持RDMA的NIC使用固定协议(即RoCEv2或Infiniband)终止传输逻辑,并直接访问主机内存,而不干扰主机CPU。nanoTransport可以通过将重组的消息直接发送到DMA引擎来实现同样的功能。我们预计这种方法将在nanoTransport的ASIC实现上得到普遍支持。
此外,对于应用程序开发人员喜欢在软件中处理传输层,ASIC设计可能可以配置为绕过分组和重组模块。这对于实现硬件上不可用的复杂传输特性的应用程序尤其有用。
只要有足够的TCAM、SRAM和流水线阶段可用,可用的PISA流水线还可以运行与传输层无关的数据平面程序,例如NetCache[33]、SwitchML[56]和PPS[32]。我们把可以加到nanoTransport上的其他服务的探索留作未来的工作。
7. 总结
摩尔定律和Dennard Scaling定律的放缓意味着单核性能正在趋于平稳;新的应用程序必须分布在不断增加的内核上。这得益于稳步提高的网络速度。服务器网卡已从10 Gb/s快速过渡到25 Gb/s、100 Gb/s和现在的400 Gb/s。
但往往会因为低效的网卡设计、网络堆栈中的软件或次优的网络拥塞控制算法而失去“多核快速网络”的好处。
因此,考虑将传输层放到以线速运行且延迟非常低的流水线NIC硬件中是很自然的。但是,尽管进行了几十年的研究,但社区还没有找到一种对每一种边缘情况都表现最佳的协议-没有一种适合所有情况的协议。至少在目前,对堆栈进行编程和部署定制协议的灵活性至关重要。
NanoTransport的关键之处在于,可以构建吞吐量非常高(200 Gb/s)的NIC,其传输层具有非常低的延迟(往返10 ns),而且是可编程的。我们的设计公开了一种单向可靠的消息传递接口,以向CPU内核或RDMA引擎提供即用消息,这进一步提高了网络堆栈性能。
我们还处于云计算的早期阶段。云服务提供商及其客户仍在学习如何开发在共享基础设施上运行良好的大型、快速分布式应用程序。随着他们了解的更多,他们可能会想发明并尝试新的传输层协议。我们的工作表明在不影响吞吐量或延迟的情况下这是可能的。
致谢
We thank our shepherd Feng Qian, and Muhammad Shahbaz for their invaluable feedback. This work was supported by the Defense Advanced Research Projects Agency (DARPA) under Contract No. HR0011-20-C-0107 and FA8650-18-2-7865.