【问题标题】:Network programming achieving nowhere near benchmark网络编程远未达到基准
【发布时间】:2011-03-24 07:13:05
【问题描述】:

我一直在使用 Java 和 C 进行一些网络编程。到目前为止,我只能使用不同的技术实现大约 15 兆字节/秒的网络速度,而且似乎不管环回的消息大小如何,远程网络也能产生速度差不多。

尽管如此,我还是使用iperf 对网络速度进行了基准测试,它达到了 1.6 GigaBytes/sec。这显然是一个显着的改进。有没有人知道如何在实际编程中达到这种速度?

【问题讨论】:

    标签: java c networking performance benchmarking


    【解决方案1】:

    警告:接下来是错误的 ASCII 艺术!

    如果您的网络模式如下所示,您将永远无法获得真正出色的速度:

    REQ   REQ   REQ   REQ   REQ
       RSP   RSP   RSP   RSP
    

    如果你能做到这一点,你会获得一些极好的速度:

    REQ-A REQ-B REQ-C REQ-D REQ-E
         RSP-A RSP-B RSP-C RSP-D RSP-E
    

    有几件事可以将您锁定在第一种模式中。单线程、单状态进程。一个多线程进程,锁做得不好。

    如果您使用异步、多状态网络,或者如果您使用做得非常好的多线程(或多进程),则可以使用第二种模式。

    如果可以,您应该尽量避免为每个请求/响应使用新的 TCP 会话。当每个 TCP 会话寻求其最佳速率时,它会导致网络过载和未充分利用。一些新的网络协议如 SCTP 更好。流水线等 HTTP 协议选项也很好。

    【讨论】:

      【解决方案2】:

      首先,您为 iperf 提供的数字听起来不正确。

      1.6Gigabytes/sec = 12.8Gigabits/s。这超出了 10Gigabit 以太网标准。 也许你想重做数字。

      另一方面,如果您有千兆以太网,那么我预计 60-100 兆字节/秒的速度

      windows下的主要因素是发送和接收缓冲区。如果你增加这些,你会看到性能的显着提高。 不过我不太确定你是如何在 Java 中做到这一点的。

      在 C 下是这样完成的(例如 1MegaByte 缓冲区):

      int sndbuf_size = 1048575;
      result = setsockopt(thesocket, SOL_SOCKET, SO_SNDBUF, &sndbuf_size, sizeof(int));
      if (result != -1){
         socklen_t optlen = sizeof(sndbuf_size);
         if (getsockopt(native_socket, SOL_SOCKET, SO_RCVBUF, &sndbuf_size, &optlen) != -1){
              printf("  SO_SNDBUF: %d bytes\n", sndbuf_size);
         }
      } else {
         printf("Error setting socket opt SO_SNDBUF (%d)\n", errno);
      }
      

      在调用listen 或connect 之前,请确保为发送和接收缓冲区调用此方法。 注意:如果你调用 setsockopt 的值大于最大值,它不会失败。要了解调用后它的实际大小,您必须使用相同的选项调用 getsockopt。

      编辑:另一个瓶颈可能是您的协议或磁盘。但是,如果您只是通过像 HTTP 服务器这样开销很小的套接字传输文件,您应该考虑在 Windows 下使用 TransmitFile API,如果您使用的是 Linux,则应考虑使用 sendfile。

      sendfile() 在一个文件描述符和另一个文件描述符之间复制数据。因为这种复制是在内核中完成的,所以 sendfile() 比 read(2) 和 write(2) 的组合更有效,后者需要在用户空间和用户空间之间传输数据。

      TransmitFile 函数使用操作系统的缓存管理器来检索文件数据,并通过套接字提供高性能的文件数据传输。

      【讨论】:

      • 感谢您的建议。 iperf 肯定说:服务器在 TCP 端口 5001 上侦听 TCP 窗口大小:256 KByte(默认)本地 127.0.0.1 端口 5001 与 127.0.0.1 端口 51816 连接。15.0 GBytes 12.8 Gbits/sec 请记住,这是我自己连接的。如果它永远不会离开主机,我怀疑会有很多网络开销。 (我无法显示 iperf 输出的行,因此对其进行了一些复制和编辑)。
      • 好吧,loopback接口往往是内存到内存,不打网卡。您可能还会增加 TCP 窗口大小。
      • 糟糕,术语混杂了。 TCP 窗口大小实际上与发送/接收缓冲区大小相同。
      【解决方案3】:

      确定每秒获得 1.6 Giga 字节吗?这相当于 13 Gbps。除非您坐在具有多条光纤链路的核心网络交换机上(并且设法生成那么多流量),否则我认为您的数字可能有问题。

      【讨论】:

      • 我认为当您以这种方式使用环回地址时,您的操作系统可能足够聪明,可以使用优化/“快捷方式”路径,有效地将“发送”数据包直接写入“接收”缓冲。换句话说,这是一个内存操作。
      • 我会尝试在两台机器之间使用 iperf。给我一分钟。虽然如果操作系统这样做,那么为什么我的程序不能达到相同的速度?
      • 好的。我只是进行了一些测试。首先:(带千兆以太网的笔记本电脑直接连接到没有千兆以太网的笔记本电脑)94.1 兆比特/秒。第二:(具有千兆以太网的笔记本电脑通过路由器到具有千兆以太网的服务器)704 兆比特/秒。仅顾名思义,千兆以太网就意味着正常运行时可能约为 1000。为什么我实际上不能以这种速度发送数据?
      • 名称可能具有欺骗性。首先,通信术语中的“千兆”意味着 1000 Mbps,而不是 1024。因此,首先,当转换为兆字节/秒时,我们会得到较小的数字。然后你必须考虑link layer 加上layer 3layer 4 封装的开销。最重要的是,您必须考虑到(至少对于 TCP/IP 而言),您不能在没有收到回复的情况下不断发送数据包。
      • 也许 iperf 正在使用 UDP 而您的应用程序在 TCP 上?这将产生巨大的性能差异。 TCP 无法继续发送数据包 n,直到数据包 m 被接收方确认,其中 n - m是“窗口大小”。
      猜你喜欢
      • 2010-12-04
      • 2010-11-23
      • 2011-01-22
      • 2016-10-28
      • 2022-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多