layout | title | categories | tags | |||
---|---|---|---|---|---|---|
post |
mTCP |
|
|
##mTCP
mTCP:a highly scalable user-level tcp stack for multicore systems 阅读报告
###背景介绍和主要贡献
扩展在多核系统上的TCP短连接的性能很有挑战性。虽然许多提案都试图解决各种不足之处,但内核执行效率低下仍然存在。 例如,即使是最先进的设计花费70%到80%的CPU周期在内核中处理TCP连接,使得用户级程序创新空间很小。 这项工作提出了一个高性能多核系统上的用户级别的TCP协议栈-MTCP,从底层包I / O和TCP连接管理到应用接口。 除了采用众所周知的技术,作者设计将开销巨大的系统调用转换成一个单一的共享内存参数,使能高效的流级别的事件集合,和执行批量包I/O。 作者在一个8-core的机器上评估表明,mTCP在短消息传输的性能上面相比最新的Linux的TCP协议栈提高了25倍, 相比迄今已知的表现最好的系统研究提高了3倍。相比Linux协议栈它也提高了当前各种流行的应用程序33%至320%性能。
TCP短连接变得越来越普遍。当大的内容传输消耗了最多的贷款,短的事务支配了TCP流2的数量,在具有大量节点的网络中,比如, 超过90%的TCP流少于32KB,多于一般少于4KB。 扩展这些短连接的处理速度不仅对于流行的面向用户在线服务是重要的,对于后台系统(比如memcached 集群)和中间盒(比如SSL proxies和消除冗余)也一定要高速处理。 即使近来软件包处理的进步,支撑高的TCP事务比率仍然具有挑战性。例如,Linux TCP 失事务率在峰值达到每秒30万次,而包的I/O可以扩展到每秒千万包。 mTCP设计有三个明确的目标:TCP协议栈多核上面的可扩展性;易于使用,易于部署。
作者这篇论文的主要贡献有,通过包级别和socket级别分批的整合可以获得巨大的性能提升。此外还将所有已知的优化, 如每核listen socket和并发流多核CPU接收扩展(RSS)的负载平衡。所得的TCP协议栈在处理TCP事务上分别优于Linux和megapipe25x和3倍。 这应用程序性能的直接转换;MTCP增加现有的应用程序的性能33% (sslshader)和 320%(lighttpd)。 第二点贡献是,它并不像其他的设计,这样的整合可以单纯在用户层进行,这种方式释放了端口的压力不需要对内核进行大量的修改。 mTCP提供了像BSD-like socket和epoll-like事件驱动的接口。迁移已有的事件驱动的应用很简单,因为仅仅需要替换socket calls到他们的同姓mTCP和使用单核listen socket。 内核TCP协议栈的限制,许多应用是在多核系统上面的多线程来扩展性能。然而,他们主要分享listen socket在众所周知的端口上接收收到的连接。结果是, 多线程争锁访问socket的接收队列,导致显著的性能下降。执行处理TCP连接的内核代码的内核不同于实际运行发送接受数据应用代码的内核, 缺少局部的连接由于额外的CPU cache丢失和cache-line共享式的引进了额外的开销。
共享文件描述符空间:在POSIX-兼容的操作系统中,文件描述符空间在一个进程中共享。例如,linux搜索最小可获取的文件描述数字当分配一个新的socket。 在一个繁忙的服务器中处理大量的并发连接,这导致了多个线程之间锁冲突的开销,为socket使用文件描述符,相反的创建了额外的遍历Linux虚拟文件系统的开销, 伪文件系统层支持了共同的文件操作。失效的每个包的处理:先前研究表明每个包的内存分配和DMA开销,NUMA-未知的内存控制。每个包处理低效,系统调用负载。
用户层TCP:虽然许多以前的设计中试图扩展在多核系统TCP的性能,很少有人真正克服上述效率低下的内核。事实证明,即使是表现最好的系统,megapipe, 花费内核中CPU周期(∼80%)。更令人震惊的是事实上这些CPU周期不能有效地利用;根据自己的测量,Linux处理相同数量的TCP交易比MTCP花费超过4周期(在内核和TCP协议栈合并)。
###设计
MTCP的目标是在多核系统上实现高可扩展性,同时保持向后兼容现有的多线程,事件驱动的应用程序。图3介绍我们的系统的概述。在最高级别,应用程序链接到MTCP库, 提供一种socket API和向后兼容事件驱动的编程接口。这两个基本的组成部分,用户级的TCP协议栈和数据包的I / O库,负责实现高可扩展性。我们的用户级的TCP实现运行在 每个CPU核心在同一应用程序中作为一个线程。MTCP线程使用我们的自定义分组I / O库直接从网络接口控制器发送和接收数据包。现有的用户分组级库只允许一个应用程序访 问一个NIC端口。因此,MTCP可以只在每个网卡接口控制器支持一个应用程序。然而,我们相信,这可以在未来使用虚拟化的网络接口来解决。应用程序仍然可以选择与现有的TCP协议栈工作, 他们只提供使用NICS 而不使用MTCP。在这一部分中,我们首先提出MTCP的高度可扩展的较低级别的组件。然后,我们讨论TCP提供支持应用的API和语义。
用户层的包的I/O库
几个数据包的输入输出系统从一个用户级应用允许高速分组I / O(∼1亿包/秒)。然而,它们不适合用于实现传输层,因为它们的接口主要是基于轮询。 轮询会很大的浪费先前处理器周期,这对于应用有潜在的好处。此外,我们的系统需要从多个网卡TX和RX队列中进行有效的复用。 例如,我们不想阻塞TX队列而发送一个数据包,当控制分组等待接收。这是因为如果我们阻止TX队列,重要的控制包,如SYN和ACK,可能被丢弃,由于重传导致显著的性能退化。
为了应对这些挑战,MTCP延伸packetshader I/O引擎(PSIO)支持高效的事件驱动I/O接口的数据包。PSIO提供高速分组I/O利用RSS分发传入的数据包的流量从多个接收队列, 并提供流量级内核密切关系减少CPU核之间的竞争。在顶部的PSIO的高速包I/O接口驱动允许MTCP线程有效一次同时等待从多个网卡端口RX和TX队列新的事件。事件驱动接口, ps_select(),类似select(),除了它在操作发送/接收队列而不是网卡接口I / O数据包。
新的事件驱动的接口,ps_select(),运行起来和select()相似,除了它操作感兴趣网卡端口的输入输出包的发送/接收队列。例如,mTCP在毫秒时间范围内为收发事件指定感兴趣的网卡接口, 它为接收/发送队列使能中段,推出线程上下文。最终,如果一个输入输出事件超过时间界限,驱动程序中的中断处理程序会唤醒线程。ps_select()也是类似于netmap支持的select()/poll()接口。 然而,不像netmap,我们没有整合为像Linux通用事件系统来避免其开销。
用户层次的TCP协议栈
一个用户层次的TCP协议栈自然地减少了许多系统调用,潜在减少很大一部分Linux TCP开销。一个用户级别的TCP协议栈的方法是完全实现一个库像应用主线程的一部分运行。 然而,方法基本的局限性是内在TCP处理的正确性取决于应用中实时TCP函数创新。应用使用mTCP库函数和mTCP线程通过共享缓冲区交互。 访问共享缓冲区的权限只通过库函数的方式授予,考虑内在的TCP数据的共享。当一个库函数修改共享数据,它仅仅把请求至于工作队列中, 这种方式使得多个请求不同于数据流可以在每个循环中进入管道流。
当mTCP线程从网卡接收队列中读取一系列数据包,mTCP传递它们到TCP数据处理逻辑中。对于每个包mTCP首先搜索流哈希表相应流的TCP控制块。 如果一个服务器接收一个为它的SYN/ACK应答ACK。新的连接的tcb排队到接受队列,读事件产生于listening socket。如果一个新的数据包到达, mTCP复制载荷到相应socket的读缓冲区。mTCP也产生一个应答包并且保持在发送管理的应答列表中直到写进一个局部发送队列中。 没有锁 每个核数据结构为了减少在mTCP线程核之间的冲突,在每个核上面定位了所有的资源(例如:数据流池,socket缓冲区等等),此外使用RSS作为流量级核紧密关系。 此外,在应用和mTCP之间使用没有锁的数据结构完全减少锁。基于以上,设计一个有效的方式管理TCP时钟操作。
批事件处理
MTCP透明地使能多个流事件批量处理,从而有效地分担在多个事件切换上下文开销。在批处理接收数据包后,mTCP处理产生一批流级别的事件。这些事件传递到应用程序。 和发送方向工作类似,mTCP库透明批量把事件写入队列。而缓冲系统调用的开销使用批次不是新的表明批处理系统调用在用户级别的TCP可以有效实现。 在实验中,8个接收/发送队列每10 Gbps端口,MTCP线程产生的在一个单一的调度周期事件的在发送和接收方向平均数是约2170个。 这保证了一个上下文切换成本分摊到大量的事件中。注意事实是使用多个队列并不会减少在批处理中处理的事件的数目。
###应用程序接口
主要目标是使得现有应用程序端口的努力简化因此它们可以轻易地收益于我们的用户层次TCP协议栈。因此我们的编程接口一定保存最多共同使用的语义和应用接口。 在这个层次上,mTCP提供了一个socketAPI和一个事件驱动的编程接口。 用户层次的socket API 我们提供像BSD 的socket 接口;对于每个BSD socket函数,我们有一个相应的程序调用(例如:accept()变成了mtcp_accept())。 此外提供了经常使用socket的功能,比如fcntl和ioctl,对于设置socket非阻塞或者获取设置socket的缓冲区大小。为了支持不同的应用需要进程之间的通信,使用pipe(), 也可以使用mtcp_pipe()。在用户级别的事件系统中提供了epoll()这样的函数调用。mTCP在这个不需要实质性内核修改就整合了所有已知的技术,同时保存了应用接口。因此, 它允许应用程序简单的扩展它们的性能不需修改他们的逻辑。作者也一直了许多应用程序,包括lighttpd,ab和SSLShader来使用mTCP。对于大多数移植的应用,行数的改变少于100 。
###实现
作者实现了11473行C代码,包括数据包输入输出,TCP流管理,用户层socket API和事件系统,和552行代码来对PSIO库打补丁。对于线程和线程同步没作者使用了pThread,标准的POSIX线程库。 TCP实现遵循RFC793 。它支持基本的TCP特性例如连接管理,可信赖的数据传输,流控制和拥塞控制。为了可靠的传输,它实现了累积确认,重传超时和快速重传, mTCP也实现了流行选项比如时间戳,最大段大小,和窗口扩展。为了拥塞控制,mTCP实现了NewReno,但是它可以轻易地支持其他的机制像是TCP CUBIC。为了正确性, 作者对mTCP协议栈和其他不同版本的linux TCP协议栈并且把它传给压力测试,包括大量数据包丢失或者被记录的情况。 我们BSD-like socket API以单个线程的语义为单位。每个mTCP socket函数需要有上下文,mctx_t,分辨了相应的mTCP线程,事件通知函数,mtcp_epoll,也使能已有事件驱动应用简单的迁移
###评测
处理短的TCP事务:mTCP是否能够在处理短小事务上提供高性能,显示mTCP优于MegaPipe和linux3倍到25倍。
正确性:mTCP提供正确性而没有不想要的副作用。验证MTCP连接上面的吞吐量公平性,作者使用ab产生8K的并发连接,每下载一个10MIB文件使得10 Gbps的链路饱和。 在服务器端,使用MTCP和Linux TCP运行lighttpd。因为MTCP很大程度上依赖于批处理,有人可能会认为它可能会引入不想要的长延迟。 表2显示的延迟突破当我们用并发连接对64B消息服务器运行AB 8K。总共产生1000万个请求。Linux和MTCP版本评价每秒分别达到45K和428k事务。 应用性能:mTCP能否在真实的负载下面使得真实的应用受益。
###相关工作:
系统调用和输入输出批处理:频繁的系统调用经常是繁忙服务器的性能瓶颈,flexsc 识别CPU缓存污染会比用户/内核模式开关本身浪费更多的CPU周期。 他们在用户和内核空间共享系统调用页面进行批处理系统调用,可以显着提高性能,为事件驱动服务器。megapipe采用socket系统调用批处理类似的方式, 但它使用一个标准的系统调用接口与内核进行交互。 在多核系统上的局部连接:TCP性能可以在CPU内核之间提供连接的局部进一步优化多处理器。通过在同一个内核上处理同一连接的所有操作, 可以避免内核之间的竞争和不必要的缓存污染。MTCP采用同样的想法,但它适用于流量和数据包级处理。 用户层TCP协议栈:已经有几个尝试将整个网络堆栈从内核移动到用户级。这些主要易于定制和调试新的网络协议来加速现有协议的性能,通过调整一些内部变量,如TCP拥塞控制参数等。 轻量级网络协议栈,多核,研究工作为多核系统加强了操作系统可扩展性。微核,微内核方法承受了在用户层次操作系统服务运行mTCP的相似性
###结论
MTCP是一个高性能的用户级多核系统TCP协议栈设计。作者发现,Linux内核仍然没有有效地使用CPU周期在处理小数据包尽管最近有所改善,这严重限制了处理短TCP连接可扩展性。 MTCP释放的TCP协议栈从内核直接提供的利益高性能数据包的I / O的传输层和应用层。主要推动者是透明和双向批处理包或者流级别事件,上一个批处理的事件下文切换开销被分担。 此外,使用无锁数据结构,高速缓存线程替换,每核高效的资源管理,都对MTCP的性能做出了贡献。最后,评估表明,现有应用程序移植到MTCP是代价很小的, MTCP 改进了现有的应用程序的性能320%。