9

Linux over loopback(127.0.0.1)で最適化されたJavaNIOセレクターを使用していくつかのベンチマークを実行しています。

私のテストはとても簡単です:

  • あるプログラムがUDPパケットを別のプログラムに送信し、それが送信者にエコーバックされ、ラウンドトリップ時間が計算されます。次のパケットは、前のパケットが確認されたとき(戻ったとき)にのみ送信されます。ベンチマークが実行される前に、数百万のメッセージによる適切なウォームアップが実行されます。メッセージは13バイトです(UDPヘッダーはカウントされません)。

往復時間については、次の結果が得られます。

  • 最小時間:13マイクロ
  • 平均時間:19マイクロ
  • 75%パーセンタイル:18,567ナノ
  • 90%パーセンタイル:18,789ナノ
  • 99%パーセンタイル:19,184ナノ
  • 99.9%パーセンタイル:19,264ナノ
  • 99.99%パーセンタイル:19,310ナノ
  • 99.999%パーセンタイル:19,322ナノ

しかし、ここでの落とし穴は、私が100万のメッセージを回転させているということです。

10個のメッセージだけをスピンすると、非常に異なる結果が得られます。

  • 最小時間:41マイクロ
  • 平均時間:160マイクロ
  • 75%パーセンタイル:150,701ナノ
  • 90%パーセンタイル:155,274ナノ
  • 99%パーセンタイル:159,995ナノ
  • 99.9%パーセンタイル:159,995ナノ
  • 99.99%パーセンタイル:159,995ナノ
  • 99.999%パーセンタイル:159,995ナノ

間違っている場合は訂正してください。ただし、NIOセレクターを回転させると、応答時間が最適になると思われます。ただし、メッセージの間隔を十分に長くしてメッセージを送信する場合は、セレクターを起動する代償を払います。

1つのメッセージだけを送信して遊んでみると、150〜250マイクロの間でさまざまな時間が発生します。

したがって、コミュニティに対する私の質問は次のとおりです。

1-私の最小時間は13マイクロで、この往復パケットテストには平均19マイクロが最適です。私はZeroMQをはるかに上回っているように見えるので、ここで何かが欠けている可能性があります。このベンチマークから、ZeroMQの標準カーネルでの平均時間は49マイクロ(99%パーセンタイル)であるように見えます=> http://www.zeromq.org/results:rt-tests-v031

2-単一またはごく少数のメッセージをスピンするときのセレクターの反応時間を改善するためにできることはありますか?150マイクロはよく見えません。または、本番環境ではセレクターが完全に機能しないと想定する必要がありますか?


selectNow()の周りで忙しいスピンをすることで、より良い結果を得ることができます。少数のパケットを送信することは、多くのパケットを送信することよりもさらに悪いですが、私は現在、セレクターのパフォーマンスの限界に達していると思います。私の結果:

  • 単一のパケットを送信すると、一貫した65マイクロの往復時間が得られます。
  • 2つのパケットを送信すると、平均で約39マイクロの往復時間が得られます。
  • 10個のパケットを送信すると、平均で約17マイクロの往復時間が得られます。
  • 10,000パケットを送信すると、平均で約10,098ナノ秒のラウンドトリップ時間が得られます。
  • 100万パケットを送信すると、平均で9,977ナノの往復時間が得られます。

結論

  • したがって、UDPパケットのラウンドトリップの物理的な障壁は平均10マイクロ秒のように見えますが、8マイクロ秒(最小時間)でトリップするパケットがいくつかあります。

  • 忙しい回転で(Peterに感謝)、1つのパケットで平均200マイクロから平均65マイクロまで一貫して移動することができました。

  • ZeroMQがそれより5倍遅い理由はわかりません。(編集:ループバックを介して同じマシンでこれをテストしていて、ZeroMQが2つの異なるマシンを使用しているためか?)

4

2 に答える 2

4

スレッドのウェイクアップに時間がかかるだけでなく、キャッシュと

私が過去にこれを回避してきた方法は、忙しく待つことです。残念ながら、空のコレクションであっても、selectNow を呼び出すたびに新しいコレクションが作成されます。これにより、使用する価値のない大量のゴミが生成されます。

これを回避する 1 つの方法は、ノンブロッキング ソケットでビジー状態で待機することです。これは特にうまくスケーリングしませんが、スレッドをウェイクする必要がなく、この後に実行するコードがキャッシュにある可能性が高いため、レイテンシを最小限に抑えることができます。スレッド アフィニティも使用すると、スレッドの障害を減らすことができます。

また、コードのロックを減らし、ガベージを減らすことをお勧めします。これを行うと、90% の確率で 100 マイクロ秒未満で着信パケットに応答を送信するプロセスを Java で実行できます。これにより、到着時に各パケットを 100 Mb で処理できます (帯域幅の制限により、最大 145 マイクロ秒の間隔があります)。


Java の同じボックスで高速なプロセス間通信が必要な場合は、https://github.com/peter-lawrey/Java-Chronicleのようなものを検討でき ますソケットで効率的に) 200ナノ秒未満です。また、データを永続化するため、ジャーナル ファイルをすばやく作成する方法が必要な場合に役立ちます。

于 2012-08-24T09:39:57.967 に答える
-1

セレクターを正しく調整すると、Java でのソケット間通信を 2 マイクロ秒未満で取得できます。以下は、256 バイトの UDP パケットに対する片道の結果です。

Iterations: 1,000,000
Message Size: 256 bytes
Avg Time: 1,680 nanos
Min Time: 1379 nanos
Max Time: 7020 nanos
75%: avg=1618 max=1782 nanos
90%: avg=1653 max=1869 nanos
99%: avg=1675 max=1964 nanos
99.9%: avg=1678 max=2166 nanos
99.99%: avg=1679 max=5094 nanos
99.999%: avg=1680 max=5638 nanos

Java NIO とリアクター パターンについては、私の記事Inter-socket communication with less than 2 microsecond latency で詳しく説明しています。

于 2013-02-16T01:36:15.763 に答える