2016-04-04 11 views
0

UDPマルチキャストを使用してログイベントを送信するロギングシステムがあります。イベントレートは約10,000イベント/秒で、平均イベントサイズは約2KBです。Java NIO UDPマルチキャスト - 廃棄パケット

NIOバージョンのアプリケーションでは、テストごとにイベントのマイナーパーセンテージ(約2000万イベント〜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を内部的に割り当て、BBBからコピーしてから、その配列にコピーします。私。余分なコピー操作があります。

さらに、ソケットの受信バッファを複数のパケットを保持できるサイズに構成することができます。

関連する問題