TCP缓冲区大小和以太网绑定

时间:2015-12-07 12:27:54

标签: tcp linux-kernel

我正在试验Linux上的TCP缓冲区大小调整,但各种结果让我感到困惑。

测试程序包括服务器和客户端。服务器只是侦听端口,等待客户端从mmaped文件发送数据。使用recv将接收的数据复制到应用程序缓冲区中,然后删除。在发送数据时,客户端使用send将mmapped缓冲区的完整大小作为初始参数。

程序在两个不同数据中心的两个节点上运行,它们之间的ping响应时间约为9毫秒。两个节点都安装了两个千兆以太网控制器。最大吞吐量为256 MB / s,发送/接收缓冲区大小的正确设置应为256 MB / s * 0.09 s~2415919字节。

我做了几次实验。

在第一次运行中,我运行了一个服务器实例和一个客户端实例。我没有设置发送缓冲区或接收缓冲区的大小,让内核自动调整它们。本案例的目的是建立其他实验的基线。

此设置中的实际吞吐量约为117 MB / s。在这种情况下,一对服务器和客户端仅使用一个netnet控制器。检查ifconfig,我发现大多数数据包都通过eth0eth1之间的单一界面。

然后我尝试了两台服务器和两台客户端,这次吞吐量上升到大约225 MB / s,更接近理想的最大吞吐量。

这是令我困惑的第一个问题:

  1. 为什么我需要多个进程才能占用带宽? 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
    
  2. 然后我为一对服务器和客户端尝试了几种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 |                           |
    

    以下是从上表中提出的其他一些问题:

    1. 为什么理论值不会产生最佳吞吐量(117 MB / s)?
    2. 为什么最好的结果(51.5 MB / s)仍然不如内核自动调整(117 MB / s)的结果好?
    3. 为什么较大的缓冲区导致吞吐量较差?
    4. 提前致谢。

1 个答案:

答案 0 :(得分:1)

我对几个问题的分析。

有一点需要注意的是,即使链接速度为1 Gbits / sec(128 MBps),由于在OS上运行,我们永远不会直接获得相同的吞吐量。应用程序/内核延迟导致链路空闲,因此我们的吞吐量会降低。

  
      
  1. 为什么我需要多个进程才能占用带宽?

    /proc/net/bonding/bond0  
    Bonding Mode: IEEE 802.3ad Dynamic link aggregation  
    Transmit Hash Policy: layer3+4 (1)
    
  2.   

如绑定接口信息中所述,拾取从属设备取决于L3标头(IP src& dst)和L4标头(src和dst端口)。在您运行多个客户端应用程序的情况下,您实际上使用不同的src端口,因此可能选择不同的从属设备,这与单个应用程序的情况不同。检查此wiki是否为transmit-hash-policy。

  
      
  1. 为什么理论值不会产生最佳吞吐量(117 MB / s)?
  2.   

如前所述,在OS上运行时很难获得链接速度。尝试使用UDP而不是TCP,您可以看到您更接近链接速度。 TCP的吞吐量较低,因为TCP是可靠的,因此缓存数据,有时依赖于定时器触发(低频定时器)来传输数据包。尝试使用TCP_NODELAY选项让tcp堆栈在应用程序调用sendmsg()后立即发送数据 您还可以尝试使用iperf应用程序来测量TCP / UDP吞吐量,该吞吐量可以选择在同一个套接字上运行多个线程。

  
      
  1. 为什么最好的结果(51.5 MB / s)仍然不如内核自动调整(117 MB / s)的结果好?
  2.   

不确定但可能是因为,我看到内核通过基于服务器传播的TCP窗口大小经常调用tcp_sndbuf_expand()来调整sk_sndbuf。因此它会根据指标(如拥塞,服务器处理时间等)不断更改sndbuf大小。