2016-04-04 49 views
0

我們有一個使用UDP多播發送日誌事件的日誌記錄系統。事件發生率約爲10,000次/秒,平均事件大小約爲2Kb。Java NIO UDP多播 - 丟棄的數據包

在每次測試期間,應用程序的NIO版本都會失去一小部分事件(大約12M的約2000個事件)。有沒有人有這方面的見解?

示例代碼: 沒有NIO:

byte[] buf = new byte[65535]; 
    DatagramPacket packet = new DatagramPacket(buf, buf.length); 

    try { 
     while (!Thread.currentThread().isInterrupted()) { 

      socket.receive(packet); 

      final byte[] tmpBuffer = new byte[packet.getLength()]; 
      System.arraycopy(packet.getData(), 0, tmpBuffer, 0, 
        tmpBuffer.length); 

      insertToNonBlockingQueue(tmpBuffer, packet.getSocketAddress()); 
     } 
    } catch (Throwable t) { 
     throw new RuntimeException("Encountered exception in Acceptor", t); 
    } finally { 
     Util.closeQuietly(socket); 
    } 

隨着NIO:

ByteBuffer inBuffer = ByteBuffer.allocate(65535); 
    try { 
     while (!Thread.currentThread().isInterrupted()) { 

      SocketAddress addr = channel.receive(inBuffer); 

      inBuffer.flip(); 

      final byte[] tmpBuffer = new byte[inBuffer.limit()]; 
      inBuffer.get(tmpBuffer); 

      inBuffer.clear(); 

      insertToNonBlockingQueue(tmpBuffer, addr); 
     } 
    } catch (ClosedByInterruptException ex) { 
     log.info("Channel closed by interrupt"); // normal shutdown 
    } catch (Throwable t) { 
     throw new RuntimeException("Encountered exception in Acceptor", t); 
    } finally { 
     Util.closeQuietly(channel); 
    } 

這兩個監聽器在同一時間,每一個非NIO版本捕獲所有,而日誌事件時運行NIO版本錯過了一些。這不是網絡問題,因爲即使我們將代碼切換到計算機上的其他版本,也是如此。

+0

對不起,我錯過了包括清除當我複製粘貼代碼時,我有代碼中的buffer.clear(),我編輯了張貼以反映它 – user2677485

回答

2

您忘記了compact()clear()之後的緩衝區get()。該代碼將在緩衝區填滿後立即開始丟棄數據包。

DatagramPacket大小寫應在每次接收前重置數據包長度。

這將是簡單的插入實際DatagramPacket到隊列中,使用新的每接收,或合成的NIO情況下,一個新的。這樣你就不需要新的數據結構。

+0

我沒有在Non NIO中每次使用新的DatagramPacket因爲事件大小範圍從200字節到64K(最大),平均值<2K,我不想在每個事件的隊列中插入帶有64K數據的數據包。然而,由於隊列大小几乎不會超過幾千(除非有更大的問題),我認爲你每次使用新的DatagramPacket的建議性能會更好(支持更高的事件速率)。 – user2677485

+0

對於NIO的情況,當我發佈問題時,我的clear(),複製粘貼失敗,我將用DirectByteBuffer進行測試。 (我認爲你的最後一句話是指非NIO案件而不是NIO) – user2677485

+0

它涉及兩種情況。 – EJP

1

除了EJP所說的,你應該使用一個直接的字節緩衝區作爲讀緩衝區,否則套接字將在內部分配一個DBB,然後從那裏複製到你的BB中,然後你將從那裏複製到數組中。即有一個多餘的複製操作。

此外,您可能希望將套接字的接收緩衝區配置爲可容納多個數據包的大小。