Javaアプリ、TCPソケットをC/C++で開発された「サーバー」に接続します。
アプリとサーバーの両方が同じマシン、Solarisボックスで実行されています(ただし、最終的にはLinuxへの移行を検討しています)。交換されるデータのタイプは単純なメッセージです(ログイン、ログインACK、クライアントが何かを要求する、サーバーが応答する)。各メッセージの長さは約300バイトです。
現在、私たちはソケットを使用していますが、すべて大丈夫ですが、IPCメソッドを使用して、データを交換するためのより高速な方法(低レイテンシー)を探しています。
私はネットを調査してきましたが、次の技術への言及を思いつきました。
しかし、私はそれぞれのパフォーマンスの適切な分析を見つけることができませんでした。JavaとC/C++でそれらを実装する方法もありませんでした。方法を想像できます。
このコンテキストでの各メソッドのパフォーマンスと実行可能性について誰でもコメントできますか?有用な実装情報へのポインタ/リンクはありますか?
編集/更新
ここで得たコメントと回答に従って、パイプ上に構築されているように見えるUnixドメインソケットに関する情報を見つけ、TCPスタック。それはプラットフォーム固有です。 JNIまたは juds または junixsocket でテストすることを計画してください。
次の可能性のあるステップはパイプの直接実装であり、それから共有メモリですが、私は余分なレベルの複雑さについて警告されています...
ご協力いただきありがとうございます
特定のCPUコアをタスクセットに割り当てずに、Java、シングルバイトのみの送受信、2 Javaプロセスが生成されたばかりのプロセスで、
TCP - 25 microseconds
Named pipes - 15 microseconds
taskset 1 Java Srvまたはtaskset 2)のようなコアマスクを明示的に指定するようになりましたJava Cli:
TCP, same cores: 30 microseconds
TCP, explicit different cores: 22 microseconds
Named pipes, same core: 4-5 microseconds !!!!
Named pipes, taskset different cores: 7-8 microseconds !!!!
そう
TCP overhead is visible
scheduling overhead (or core caches?) is also the culprit
同時にThread.sleep(0)(straceが示すように、単一のsched_yield()Linuxカーネル呼び出しが実行される)には0.3マイクロ秒かかります-そのため、シングルコアにスケジュールされた名前付きパイプにはまだ多くのオーバーヘッドがあります
共有メモリの測定:2009年9月14日– Solace Systemsは本日、Unified Messaging Platform APIが共有メモリトランスポートを使用して700ナノ秒未満の平均レイテンシを達成できることを発表しました。- http://solacesystems.com/news/fastest-ipc-messaging/
追伸-翌日、メモリマップファイルの形式で共有メモリを試しました。ビジーな待機が許容される場合、次のようなコードで1バイトを渡すためのレイテンシを0.3マイクロ秒に減らすことができます。
MappedByteBuffer mem =
new RandomAccessFile("/tmp/mapped.txt", "rw").getChannel()
.map(FileChannel.MapMode.READ_WRITE, 0, 1);
while(true){
while(mem.get(0)!=5) Thread.sleep(0); // waiting for client request
mem.put(0, (byte)10); // sending the reply
}
注:2つのプロセスが互いの変更を確認できるように、Thread.sleep(0)が必要です(別の方法はまだわかりません)。 2つのプロセスがタスクセットで同じコアに強制された場合、レイテンシは1.5マイクロ秒になります-これはコンテキストスイッチの遅延です
P.P.S-0.3マイクロ秒が良い数値です!次のコードは、正確に0.1マイクロ秒かかりますが、プリミティブ文字列の連結のみを実行します。
int j=123456789;
String ret = "my-record-key-" + j + "-in-db";
P.P.P.S-これがあまりトピックではないことを願っていますが、最後にThread.sleep(0)を静的揮発性int変数の増分に置き換えてみました(そうするとJVMはCPUキャッシュをフラッシュします)-記録します! -72ナノ秒のレイテンシJava-to-Javaプロセス通信!
ただし、同じCPUコアに強制された場合、揮発性の増加するJVMは相互に制御できず、したがって正確に10ミリ秒のレイテンシが発生します-Linuxタイムクォンタムは5ミリ秒のようです...それ以外の場合、sleep(0)の方が安全です。
DMAは、ハードウェアデバイスがCPUを中断せずに物理的なRAMにアクセスできる方法です。たとえば、一般的な例は、ディスクからRAMに直接バイトをコピーできるハードディスクコントローラです。 IPC。
共有メモリとパイプはどちらも最新のOSによって直接サポートされています。そのため、非常に高速です。キューは通常、抽象化です。ソケット、パイプ、共有メモリの上に実装されます。これはより遅いメカニズムのように見えるかもしれませんが、代替手段はyoそのような抽象化を作成することです。
質問は少し前に尋ねられましたが、興味があるかもしれません https://github.com/peter-lawrey/Java-Chronicle 200 nsの典型的なレイテンシーと20 Mメッセージのスループットをサポートしています/秒。プロセス間で共有されるメモリマップファイルを使用します(データを永続化するため、データを永続化する最速の方法になります)
以下に、さまざまなIPCトランスポートのパフォーマンステストを含むプロジェクトを示します。
遅れて到着したが、Java NIOを使用してpingレイテンシを測定するための オープンソースプロジェクト を指摘したかった。
この ブログの投稿 でさらに調査/説明しました。結果は次のとおりです(RTS in nanos):
Implementation, Min, 50%, 90%, 99%, 99.9%, 99.99%,Max
IPC busy-spin, 89, 127, 168, 3326, 6501, 11555, 25131
UDP busy-spin, 4597, 5224, 5391, 5958, 8466, 10918, 18396
TCP busy-spin, 6244, 6784, 7475, 8697, 11070, 16791, 27265
TCP select-now, 8858, 9617, 9845, 12173, 13845, 19417, 26171
TCP block, 10696, 13103, 13299, 14428, 15629, 20373, 32149
TCP select, 13425, 15426, 15743, 18035, 20719, 24793, 37877
これは受け入れられた答えの線に沿っています。 System.nanotime()エラー(何も測定しないことで推定)は約40ナノで測定されるため、IPCの実際の結果は低くなる可能性があります。楽しい。
ネイティブアクセスの使用を検討する場合(アプリケーションと「サーバー」の両方が同じマシン上にあるため)、 [〜#〜] jna [〜#〜] を検討してください。対処します。
ネイティブのプロセス間通信についてはあまり知りませんが、JNIメカニズムを使用してアクセスできるネイティブコードを使用して通信する必要があると思います。したがって、Javaから他のプロセスと通信するネイティブ関数を呼び出すことになります。
私の以前の会社では、このプロジェクト http://remotetea.sourceforge.net/ を使用していたため、理解と統合が非常に簡単でした。
接続を再利用できるように、ソケットを開いたままにしておくことを検討しましたか?