【发布时间】:2011-05-25 23:36:39
【问题描述】:
我最近开始开发一个密集使用网络的应用程序。 第一次尝试使用 RMI,出于几个原因,我们切换到纯套接字。然而,当通过网络测试套接字时,甚至在 localhost 上,我们的速度下降到 25 个请求/秒。使用 RMI 时,它要高两个数量级。
通过更多测试,我们获得了以下结果(对于 localhost):
- 始终发送相同的对象:31628 个请求/秒
- 始终发送一个新对象:25 个请求/秒
- 仅对象创建速率:每秒 3-4 百万(因此这不是瓶颈)
这是客户端代码:(服务器端只是回复一个“ACK”)
public static void main(String[] args) throws IOException, ClassNotFoundException
{
Socket kkSocket = null;
ObjectOutputStream out = null;
ObjectInputStream in = null;
kkSocket = new Socket("barium", 4444);
out = new ObjectOutputStream(kkSocket.getOutputStream());
in = new ObjectInputStream(kkSocket.getInputStream());
long throughput;
long millis;
TcpRequest hello = null;
throughput = 0;
millis = System.currentTimeMillis();
while (System.currentTimeMillis() < millis + 1000)
{
hello = new TcpRequest();
hello.service = "hello";
hello.payload = Math.random();
throughput++;
}
System.out.println("-------------------------------------------------------");
System.out.println("| Objects created: " + (throughput) + " requests/sec.");
System.out.println("-------------------------------------------------------");
throughput = 0;
millis = System.currentTimeMillis();
while (System.currentTimeMillis() < millis + 1000)
{
out.writeObject(hello);
Object res = in.readObject();
throughput++;
}
System.out.println("-------------------------------------------------------");
System.out.println("| Same object throughput: " + (throughput) + " requests/sec.");
System.out.println("-------------------------------------------------------");
throughput = 0;
millis = System.currentTimeMillis();
while (System.currentTimeMillis() < millis + 1000)
{
hello = new TcpRequest();
out.writeObject(hello);
Object res = in.readObject();
throughput++;
}
System.out.println("-------------------------------------------------------");
System.out.println("| New objetcs throughput: " + (throughput) + " requests/sec.");
System.out.println("-------------------------------------------------------");
out.close();
in.close();
kkSocket.close();
}
TcpRequest 类只是一个没有任何特殊的虚拟类。
那么,如果创建对象很快,如果通过网络发送它很快......为什么通过网络发送一个新对象这么慢?!?!
如果你保留一个相同的对象并在发送之前修改它的内容,你也会有很高的传输率......但会陷入令人讨厌的陷阱:
使用对象序列化时 重要的是要记住 ObjectOutputStream 维护一个 哈希表映射写入的对象 进入流到一个句柄。当一个 对象被写入流中 第一次,其内容将是 复制到流中。随后的 但是,写入会导致句柄 正在写入的对象 流。
...这发生在我们身上并导致了几个小时的调试才弄明白。
所以基本上...如何使用套接字实现高吞吐量? (...我的意思是,RMI 是它的包装器,我们已经高了两个数量级!)
已解决:
通过替换:
out = new ObjectOutputStream(kkSocket.getOutputStream());
与:
out = new ObjectOutputStream(new BufferedOutputStream(kkSocket.getOutputStream()))
性能再次正常(与相同对象情况几乎相同的高吞吐量)
【问题讨论】:
-
与此问题相同:stackoverflow.com/questions/2251051/… ...也没有答案。
-
如果您的对象不相互引用,您可能需要在写入后调用 ObjectOutputStream.reset(),以防止流记住它写入的所有对象。虽然它通常会导致读取端的内存问题,而不是服务器端的性能问题。您是否尝试过分析您的应用程序以查看它花费最多时间的地方?