2012-02-26 17 views
0

我已經編寫了一個用於遠程存儲(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字節(更大的大小對此現象沒有任何影響)。

任何想法可能會導致這種情況或如何解決這個問題?

回答

1

...而客戶機服務器發送32KiB寫在兩個連接的命令(即4個 連續數據分組)。

您能提供一些關於測試設置的細節嗎?客戶端是否將數據包連續發送到兩個連接?然後根據設置增加可能是由客戶驅動的。

它是本地主機設置(一臺機器上的客戶端和服務器)還是不同主機上的客戶端和服務器?你有沒有測試過?不要欺騙自己看到本地主機設置的執行時間增加,特別是如果只有一個cpu並且測試客戶端也在本地運行,甚至可能是單線程的。

+0

客戶端和服務器運行在不同的機器上,都有大量的空閒內核。但你是對的,錯誤似乎在於客戶端。我一開始並沒有看到這一點,因爲在我的初步測量過程中,我對測試軟件和切換版本的質量過於信服。我正在使用[iometer](http://www.iometer.org/)和Microsoft iSCSI Initiator,其中一個似乎會引入大的延遲,而不管它連接到哪個目標/服務器。 – andreas 2012-02-26 18:42:24