这只是我一直想知道的一些高性能计算的一般性问题。某个低延迟消息传递供应商在其支持文档中讲述了如何使用原始套接字将数据直接从网络设备传输到用户应用程序,这样做可以说明减少消息传递延迟甚至比无论如何还要多(在其他情况下)经过仔细考虑的设计决定。)
因此,我的问题是那些在Unix或类Unix系统上浏览网络堆栈的人。他们可能能够实现这种方法有多大差异?您可以随意回忆内存副本,获救的鲸鱼数量或威尔士面积;)
他们的消息是基于UDP的,据我所知,因此建立TCP连接等没有问题。对此主题的任何其他兴趣点都会感激不尽!
祝福,
迈克答案 0 :(得分:1)
要减少高性能的延迟,您应该拒绝使用内核驱动程序。使用用户空间驱动程序可以实现最小的延迟(MX可以,Infinband也可以)。
Linux网络内部“Linux内核2.4.20中的网络代码映射”有一个相当不错(但稍微过时)的概述。有一些TCP / UDP数据路径方案。
使用原始套接字会使tcp数据包的路径更短(感谢您的想法)。内核中的TCP代码不会增加其延迟。但是用户必须自己处理所有tcp协议。在某些特定情况下,有一些机会对其进行优化。与默认的TCP / UDP堆栈一样,群集代码不需要处理长距离链路或慢速链路。
我对这个主题也很感兴趣。
答案 1 :(得分:1)
有一些图片http://vger.kernel.org/~davem/tcp_output.html
用tcp_transmit_skb()
搜索,这是tcp datapath的关键部分。他的网站上有一些更有趣的事情http://vger.kernel.org/~davem/
在数据路径的user - tcp
传输部分,有skb_copy_to_page
从用户到skb的 1份(当通过 {{发送时) 1}} )和 0副本与tcp_sendmsg()
(由 do_tcp_sendpages
调用)。需要复制以保留未交付段的数据备份。可以克隆内核中的skb缓冲区,但是它们的数据将保留在第一个(原始)skb中。 Sendpage可以从其他内核部分获取一个页面并保留备份(我认为像COW一样)
呼叫路径(从lxr手动)。发送tcp_sendpage()
/ tcp_push_one
__tcp_push_pending_frames
接收tcp_sendmsg() <- sock_sendmsg <- sock_readv_writev <- sock_writev <- do_readv_writev
tcp_sendpage() <- file_send_actor <- do_sendfile
tcp_recv_skb()
在接收中,内核与用户tcp_recvmsg() <- sock_recvmsg <- sock_readv_writev <- sock_readv <- do_readv_writev
tcp_read_sock() <- ... spliceread for new kernels.. smth sendfile for older
(从skb_copy_datagram_iovec
调用)可以 1次复制。对于tcp_read_sock(),可以进行复制。它将调用tcp_recvmsg
回调函数。如果它对应于文件或内存,则它可能(或可能不)从DMA区域复制数据。如果它是另一个网络,它有一个接收数据包的skb,并且可以在其中重复使用它的数据。
对于udp - receive = 1副本 - 从udp_recvmsg调用skb_copy_datagram_iovec。 transmit = 1 copy - udp_sendmsg - &gt; ip_append_data - &gt; getfrag(似乎是ip_generic_getfrag,来自用户的1份副本,但可能是没有页面复制的smth sendpage / splicelike。)
一般来说,从/接收到用户空间时必须至少有1个副本,当使用内核空间源/目标缓冲区用于数据的零拷贝(惊奇!)时,必须至少有0个副本。添加所有标头而不移动数据包,启用DMA(所有现代)的网卡将从启用DMA的地址空间中的任何位置获取数据。对于古代的卡片,需要PIO,因此将有一个副本,从内核空间到PCI / ISA / smthelse I / O寄存器/内存。
UPD:在来自NIC的路径中(但这是依赖于nic的,我检查了8139too)到tcp堆栈有一个副本:从rx_ring到skb,并且相同的接收:从skb到tx缓冲区 + 1copy 。你必须填写ip和tcp标题,但skb是否包含它们或为它们放置?