2016-04-04 11 views
0

Wir haben ein Protokollierungssystem, das UDP-Multicast verwendet, um Protokollereignisse zu senden. Die Ereignisrate beträgt etwa 10.000 Ereignisse/Sekunde und die durchschnittliche Ereignisgröße beträgt etwa 2 KB.Java NIO UDP Multicast - verworfene Pakete

Die NIO-Version der Anwendung verliert bei jedem Test einen kleinen Prozentsatz von Ereignissen (ca. 2000 Ereignisse in ca. 12M). Hat jemand diesbezüglich irgendwelche Einsichten?

Beispielcode: Ohne 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); 
    } 

Mit 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); 
    } 

Sowohl die Zuhörer zugleich und jedes Mal, wenn die nicht NIO Version erfasst alle Log-Ereignisse ausgeführt werden, während die NIO-Version vermisst ein paar. Es handelt sich nicht um ein Netzwerkproblem, denn es ist das gleiche Verhalten, selbst wenn wir den Code auf eine andere Version auf einem Computer umstellen.

+0

Entschuldigung, ich habe vergessen, die klare, wenn ich den Code einfügen eingefügt, ich hatte die buffer.clear() im Code und ich habe die Buchung bearbeitet, um es widerzuspiegeln – user2677485

Antwort

2

Sie haben compact() oder clear() den Puffer nach der get() vergessen. Dieser Code beginnt mit dem Löschen von Paketen, sobald der Puffer voll ist.

Der DatagramPacket Fall sollte die Paketlänge vor jedem Empfang zurücksetzen.

Es wäre einfacher, die tatsächliche DatagramPacket in die Warteschlange einzufügen und eine neue pro Empfang zu verwenden oder eine neue im NIO-Fall zu synthetisieren. Auf diese Weise benötigen Sie keine neue Datenstruktur.

+0

Ich habe nicht ein neues DatagramPacket jedes Mal in Non NIO Da die Ereignisgrößen zwischen 200 und 64 KB (maximal) liegen und der Durchschnitt <2 KB ist, wollte ich kein Paket mit 64 KB Daten in die Warteschlange für jedes Ereignis einfügen. Da die Größe der Warteschlange jedoch selten über einige Tausend hinausgeht (es sei denn, es gibt größere Probleme), denke ich, dass Ihre Empfehlung, jedes Mal ein neues DatagramPacket zu verwenden, bessere Ergebnisse bringt (Unterstützung von noch höheren Ereignisraten). – user2677485

+0

Für den NIO-Fall, ich hatte die clear(), kopieren einfügen fehlschlagen meinerseits, wenn ich die Frage, ich werde mit dem DirectByteBuffer testen. (Ich nehme an, dass Ihr letzter Satz bezieht sich auf den Nicht-NIO-Fall anstelle von NIO) – user2677485

+0

Es bezieht sich auf beide Fälle. – EJP

1

Zusätzlich zu dem, was EJP sagte, sollten Sie einen direkten Bytepuffer als Lesepuffer verwenden, andernfalls wird der Socket intern einen DBB zuweisen, dann von diesem in Ihr BB kopieren und dann von diesem in das Array kopieren. I.e. Es gibt eine überflüssige Kopieroperation.

Darüber hinaus möchten Sie möglicherweise den Empfangspuffer des Sockets auf eine Größe konfigurieren, die mehrere Pakete enthalten kann.