本地主机上的Java套接字性能变慢

时间:2018-12-06 19:18:59

标签: java linux performance networking

我正在构建一个简单的Java网络应用程序,但是我遇到了性能问题。
该应用程序非常简单,包含2个部分(source code):

  • 服务器是主线程。
  • 客户端是由main启动的新线程。

我正在尝试发送大量小数据,但最大发送速率为每秒50个包裹。
因此,在我的搜索中,我发现this question遇到了同样的问题。
当我将Buffered流添加到输出流时,速率变大(千位每秒)
在wireshark中,我可以很好地看到区别:

  • 在慢速运行中有推送标志,在不同的程序包中有ack标志,有些ack甚至可以达到45毫秒的延迟,并且CPU使用率非常低。
  • 在快速运行中,所有软件包都将推和ack包含在一起,因此所有延迟都不超过1毫秒,并且CPU使用率很高。

我也发现与此相关的question并没有帮助。

为什么简单的代码行如此不同?
为什么Java中的简单解决方案这么慢?

1 个答案:

答案 0 :(得分:0)

历史上,套接字是使用启用的Nagle's algorithm打开的,这会延迟小数据包以优化网络通信。

在处理小数据包时,应设置TCP_NODELAY套接字选项。在Java中,您可以通过调用socket.setTcpNoDelay(true);

调整后,我得到:

  • 没有缓冲区的12000个数据包/秒
  • 带有缓冲区的26000个数据包/秒

我调整后的代码:

public class Test {
    static DataOutputStream cout(Socket s) throws IOException {
        return new DataOutputStream( (s.getOutputStream()));
//        return new DataOutputStream(new BufferedOutputStream(s.getOutputStream()));
    }
    static DataInputStream cin(Socket s) throws IOException {
        return new DataInputStream( (s.getInputStream()));
    }
    public static void main(String[] args) throws IOException, InterruptedException {
        ServerSocket server = new ServerSocket(12345);
        new Thread(() -> {
            try {
                Thread.sleep(1000);
                Socket client = new Socket("127.0.0.1", 12345);
                client.setTcpNoDelay(true);
                DataOutputStream out = cout(client);
                DataInputStream in = cin(client);
                long tm1 = System.currentTimeMillis();
                int lastCount = 0;
                for (int i=0;i<300000;i++) {
                    int a = in.readInt();
                    out.writeInt(a);
                    out.flush();
                    long tm2 = System.currentTimeMillis();
                    if ((tm2 - tm1) >= 1000) {
                        System.out.println(i - lastCount);
                        lastCount = i;
                        tm1 += 1000;
                    }
                }
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        Socket client=server.accept();
        client.setTcpNoDelay(true);
        DataOutputStream out = cout(client);
        DataInputStream in = cin(client);
        for (int i=0;i<300000;i++){
            out.writeInt(i);
            out.flush();
            if (i!=in.readInt()){
                System.out.println("ERROR");
            }
        }
        client.close();
        server.close();
        Thread.sleep(1000);
    }
}