Java套接字性能瓶颈:在哪里?
问题内容:
我最近开始开发大量使用网络的应用程序。第一次尝试使用RMI,由于几个原因,我们切换到纯套接字。但是,在通过网络甚至在本地主机上测试套接字时,我们的速率下降为每秒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()))
性能再次恢复正常(与相同对象情况下的吞吐量几乎相同)
问题答案:
找到了:
代替:
out = new ObjectOutputStream(kkSocket.getOutputStream());
您应该使用:
out = new ObjectOutputStream(new BufferedOutputStream(kkSocket.getOutputStream()));
和
out.flush();
发送消息时。
…产生了巨大的差异…尽管我不知道为什么。