Java套接字性能瓶颈:在哪里?
我最近开始开发一个应用程序,充分利用网络。 第一次尝试使用RMI,出于几个原因,我们切换到纯套接字。然而,当在网络上,甚至在本地主机上测试套接字时,我们将速率降至每秒25个请求。而使用RMI则高出两个数量级 通过进一步的测试,我们获得了以下结果(对于localhost):Java套接字性能瓶颈:在哪里?,java,sockets,Java,Sockets,我最近开始开发一个应用程序,充分利用网络。 第一次尝试使用RMI,出于几个原因,我们切换到纯套接字。然而,当在网络上,甚至在本地主机上测试套接字时,我们将速率降至每秒25个请求。而使用RMI则高出两个数量级 通过进一步的测试,我们获得了以下结果(对于localhost): 始终发送相同的对象:31628个请求/秒 始终发送新对象:25个请求/秒 仅对象创建速率:每秒300-400万(因此这不是瓶颈) 以下是客户端代码:(服务器端只回复一个“ACK”) 与: 性能再次正常(几乎与相同对象情况下
- 始终发送相同的对象:31628个请求/秒
- 始终发送新对象:25个请求/秒
- 仅对象创建速率:每秒300-400万(因此这不是瓶颈)
out = new ObjectOutputStream(kkSocket.getOutputStream());
你应使用:
out = new ObjectOutputStream(new BufferedOutputStream(kkSocket.getOutputStream()));
及
发送消息时
…产生了巨大的变化…尽管我不知道确切的原因。我不相信基准测试的结果。它不能确保JVM已预热;i、 e.在测量执行时间之前,类被加载、初始化并编译为本机代码。本机代码编译很有可能在一定程度上通过运行基准测试发挥作用,这会增加一个或多个循环所花费的时间。您遇到的问题不是套接字的吞吐量低;这是缓慢的默认Java序列化 当您一遍又一遍地发送同一个对象时,它实际上只被序列化一次,然后每次都发送对它的引用;这就解释了为什么它进展如此之快 每次创建新对象时,必须使用相对较慢的Java序列化机制对新对象进行序列化,这可能比您需要的要复杂得多 要改进这一点,您可以为类实现自定义序列化代码,或者创建自己的类外部对象序列化协议(并使用DataOutput而不是ObjectOutputStream) 这篇文章有很多好的信息,即使它有点过时:
请参阅关于性能注意事项的最后一部分处理小数据包时,应设置
TCP\u节点延迟
选项。否则,它们将在尝试优化网络通信(也称为)时被延迟
使用缓冲区之所以有帮助,是因为延迟只影响小数据包。因此,缓冲本身并不是有帮助的,而是数据包的大小。与此问题相同:…也没有答案。如果对象彼此不引用,则可能需要在写入后调用ObjectOutputStream.reset(),以防止流记住它写入的所有对象。虽然它通常会导致读取端的内存问题,而不是服务器端的性能问题。您是否尝试分析您的应用程序以查看它在哪里花费的时间最多?这可能是问题的一部分,但只是问题的一部分。请看我的评论,我可以解释。如果使用不使用缓冲区的流,则每次
write
都会产生一个系统调用。每个syscall的开销可能是数千条额外的机器指令。ObjectOutputStream在内部运行自己的1k缓冲区。将BufferedOutputStream添加到堆栈中并没有多大区别。问题不是“缓慢的默认Java序列化”,而是序列化对象和句柄之间的区别。仅仅重新发送同一个对象的测试实际上并没有执行任何有趣的操作,因此其结果也不感兴趣。
out = new ObjectOutputStream(new BufferedOutputStream(kkSocket.getOutputStream()))
out = new ObjectOutputStream(kkSocket.getOutputStream());
out = new ObjectOutputStream(new BufferedOutputStream(kkSocket.getOutputStream()));
out.flush();
socket.setTcpNoDelay(true);