我正在试验Linux上的TCP缓冲区大小调整,但各种结果让我感到困惑。
测试程序包括服务器和客户端。服务器只是侦听端口,等待客户端从mmaped文件发送数据。使用recv
将接收的数据复制到应用程序缓冲区中,然后删除。在发送数据时,客户端使用send
将mmapped缓冲区的完整大小作为初始参数。
程序在两个不同数据中心的两个节点上运行,它们之间的ping响应时间约为9毫秒。两个节点都安装了两个千兆以太网控制器。最大吞吐量为256 MB / s,发送/接收缓冲区大小的正确设置应为256 MB / s * 0.09 s~2415919字节。
我做了几次实验。
在第一次运行中,我运行了一个服务器实例和一个客户端实例。我没有设置发送缓冲区或接收缓冲区的大小,让内核自动调整它们。本案例的目的是建立其他实验的基线。
此设置中的实际吞吐量约为117 MB / s。在这种情况下,一对服务器和客户端仅使用一个netnet控制器。检查ifconfig
,我发现大多数数据包都通过eth0
和eth1
之间的单一界面。
然后我尝试了两台服务器和两台客户端,这次吞吐量上升到大约225 MB / s,更接近理想的最大吞吐量。
这是令我困惑的第一个问题:
为什么我需要多个进程才能占用带宽? FWIW,以下是/proc/net/bonding/bond0
的一部分:
Bonding Mode: IEEE 802.3ad Dynamic link aggregation
Transmit Hash Policy: layer3+4 (1)
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0
然后我为一对服务器和客户端尝试了几种send / recv缓冲区大小的组合。下表总结了结果:
| send buf size | recv buf size | throughput | comment |
| (client) | (server) | (MB/s) | |
| 1048576 | - | 51.5 | |
| 2621400 | - | 48.6 | server uses autotuning |
| 524288 | - | 43.3 | |
| 8388608 | - | 36.3 | |
| 2621400 | 2621400 | 33.0 | somewhat the theory value |
| - | 2621400 | 30.4 | client uses autotuning |
| 4194304 | - | 30.3 | |
| 262144 | - | 29.1 | |
| - | 1048576 | 27.9 | |
| 6291456 | 6291456 | 26.5 | |
| 8388608 | 8388608 | 23.9 | |
| 6291456 | - | 22.2 | |
| - | 4194304 | 20.8 | |
| 1048576 | 1048576 | 19.8 | |
| 4194304 | 4194304 | 19.3 | |
| - | 8388608 | 19.3 | |
| - | 6291456 | 13.8 | |
以下是从上表中提出的其他一些问题:
提前致谢。
答案 0 :(得分:1)
我对几个问题的分析。
有一点需要注意的是,即使链接速度为1 Gbits / sec(128 MBps),由于在OS上运行,我们永远不会直接获得相同的吞吐量。应用程序/内核延迟导致链路空闲,因此我们的吞吐量会降低。
- 醇>
为什么我需要多个进程才能占用带宽?
/proc/net/bonding/bond0 Bonding Mode: IEEE 802.3ad Dynamic link aggregation Transmit Hash Policy: layer3+4 (1)
如绑定接口信息中所述,拾取从属设备取决于L3标头(IP src& dst)和L4标头(src和dst端口)。在您运行多个客户端应用程序的情况下,您实际上使用不同的src端口,因此可能选择不同的从属设备,这与单个应用程序的情况不同。检查此wiki是否为transmit-hash-policy。
- 为什么理论值不会产生最佳吞吐量(117 MB / s)?
醇>
如前所述,在OS上运行时很难获得链接速度。尝试使用UDP而不是TCP,您可以看到您更接近链接速度。 TCP的吞吐量较低,因为TCP是可靠的,因此缓存数据,有时依赖于定时器触发(低频定时器)来传输数据包。尝试使用TCP_NODELAY选项让tcp堆栈在应用程序调用sendmsg()后立即发送数据 您还可以尝试使用iperf应用程序来测量TCP / UDP吞吐量,该吞吐量可以选择在同一个套接字上运行多个线程。
- 为什么最好的结果(51.5 MB / s)仍然不如内核自动调整(117 MB / s)的结果好?
醇>
不确定但可能是因为,我看到内核通过基于服务器传播的TCP窗口大小经常调用tcp_sndbuf_expand()来调整sk_sndbuf。因此它会根据指标(如拥塞,服务器处理时间等)不断更改sndbuf大小。