【问题标题】:TCP buffer sizes and ethernet bondingTCP 缓冲区大小和以太网绑定
【发布时间】:2015-12-07 12:27:53
【问题描述】:

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

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

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

我做了几个实验。

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

此设置下的实际吞吐量约为 117 MB/s。在这种情况下,一对服务器和客户端只使用了一个双向网络控制器。检查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
    

然后我为一对服务器和客户端尝试了几种发送/接收缓冲区大小的组合。下表总结了结果:

| 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. 为什么更大的缓冲区会导致吞吐量下降?

提前致谢。

【问题讨论】:

  • 您可以通过这个问题在 ServerFault.com 上获得更快的帮助
  • 我已经在server fault重新发布了这个问题。

标签: tcp linux-kernel


【解决方案1】:

我对几个问题的分析。

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

  1. 为什么我需要多个进程来用完带宽?

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

正如bonded interface信息中提到的,选择一个slave取决于L3 header(IP src & dst)和L4 header(src和dst端口)。在您运行多个客户端应用程序的情况下,您实际上使用不同的 src 端口,因此可能会选择不同的从属设备,这与拥有单个应用程序的情况不同。检查此wiki 以获取传输哈希策略。

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-22
    • 1970-01-01
    • 1970-01-01
    • 2015-05-01
    • 1970-01-01
    • 2010-12-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多