我已经编写了一个用于远程存储(iSCSI目标)的Java服务器。客户端可以通过发送携带数据有效载荷的数据包序列来写入数据。这些数据包包含一个固定长度的头(48字节),后跟一个可变长度的数据段。数据段的长度在标题中指定,可以认为是固定的(8KiB)。对于大型ByteBuffers,单独SocketChannel的并发读取()速度较慢
接收数据包是一个由两部分组成的过程。首先将标题读入一个大小为48字节的ByteBuffer。之后立即通过ByteBuffer.allocate(...)创建第二个ByteBuffer。第二个缓冲区的大小与头中指定的数据段长度相匹配。然后使用SocketChannel.read(ByteBuffer)方法将数据段读入第二个ByteBuffer。在简单情况下,此过程按预期工作 - 较大的数据段和较长的序列会提高IO速度。通过“简单情况”我的意思是有一个单线程使用阻塞SocketChannel来接收(和处理)数据包。但是,如果添加了具有自己的TCP连接和关联的SocketChannel的第二个线程,则SockerChannel.read(ByteBuffer)执行时间将增加到超过2.5ms,而客户端服务器正在发送32KiB写入命令(即4个连续的数据包)连接。这是增加了8倍到10倍。
我想强调,在这个阶段,两个线程不会共享任何资源,除了相同的网络接口卡。每个SocketChannel的读取缓冲区大小为43690字节(更大的大小对此现象没有任何影响)。
任何想法可能会导致这种情况或如何解决这个问题?
客户端和服务器运行在不同的机器上,都有大量的空闲内核。但你是对的,错误似乎在于客户端。我一开始并没有看到这一点,因为在我的初步测量过程中,我对测试软件和切换版本的质量过于信服。我正在使用[iometer](http://www.iometer.org/)和Microsoft iSCSI Initiator,其中一个似乎会引入大的延迟,而不管它连接到哪个目标/服务器。 – andreas 2012-02-26 18:42:24