web-dev-qa-db-ja.com

ローカルJVM間の通信

私の質問:ローカルで実行されている2つ以上のJVMインスタンス間で通信するには、どのようなアプローチを取ることができますか?

問題の説明:
特定のタスクを互いに完全に分離するために個別のJVMインスタンスを必要とするプロジェクトのシステムを開発しています。

実行中、「親」JVMは、実行を期待する「子」JVMを作成し、結果を返します(比較的単純なPOJOクラス、またはおそらく構造化XMLデータの形式で)。これらの結果は、SysErr/SysOut/SysInパイプを使用して転送しないでください。子は、実行の一部としてすでにこれらを使用している可能性があります。

子JVMが特定の時間内に結果で応答しない場合、親JVMは、処理を停止するか、子プロセスを強制終了するように子に通知できる必要があります。それ以外の場合、子JVMは、タスクの完了時に正常に終了する必要があります。

これまでの研究:
役立つ可能性のあるテクノロジーがいくつかあることは承知しています。

  • JavaのRMIライブラリを使用する
  • ソケットを使用してオブジェクトを転送する
  • Cajo、Hessianなどの配布ライブラリを使用する

...しかし、これらのオプションの1つ、または他のオプションを追求する前に、他の人がどのようなアプローチを検討する可能性があるかを聞くことに興味があります。

これに関する助けやアドバイスをありがとう!

編集:
転送するデータの量-比較的小さいため、ほとんどの場合、子の実行結果を表す文字列を含むPOJOはほんの一握りです。大量の情報に対して解決策が非効率的である場合、これは私のシステムで問題になる可能性は低いです。転送される量はかなり静的である必要があるため、これはnotスケーラブルである必要はありません。

転送の待ち時間-この場合、重大な懸念事項ではありませんが、結果の「ポーリング」が必要な場合は、大きなオーバーヘッドなしでかなり頻繁に実行できるはずなので、応答性の高いGUIを上に維持できます後でこれの(例えばプログレスバー)

26
obfuscation

ローカルソケットでは KryoNet を使用します。これは、シリアル化に重点を置いており、非常に軽量であるためです(Remote Method Invocationも取得できます!現在使用しています)が、ソケット切断タイムアウトを無効にします。

RMIは基本的に、リモートタイプがあり、リモートタイプがインターフェイスを実装するという原則に基づいて機能します。このインターフェースは共有されます。ローカルマシンでは、RMIライブラリを介してインターフェイスをバインドし、RMIライブラリからメモリ内に「注入された」コードを作成します。その結果、インターフェイスは満たされますが、リモートオブジェクトと通信できるものが得られます。

5
Chris Dennett

あなたの質問に対する直接の答えではなく、代替案の提案です。 [〜#〜] osgi [〜#〜] を検討しましたか?

これにより、同じjvm内でJavaプロジェクトを互いに完全に分離して実行できます。プロジェクト間の通信がサービスを使用して非常に簡単であるという利点があります( コア仕様PDFを参照) 123ページ)。この方法では、データと呼び出しがすべて同じjvmにあるため、いかなる種類の「シリアル化」も行われません。

さらに、サービス品質の要件(応答時間など)がすべてなくなります。使用するときにサービスがUPかDOWNかを心配するだけで済みます。そしてそのために、宣言型サービスと呼ばれるそれを行う本当に素晴らしい仕様があります( エンタープライズ仕様PDF 141ページを参照)

トピック外の回答で申し訳ありませんが、他の人はこれを代替案と見なすかもしれないと思いました。

更新

セキュリティについてのあなたの質問に答えるために、私はそのようなシナリオを考えたことがありません。 OSGI内で「メモリ」の使用を強制する方法はないと思います。

ただし、異なるOSGIランタイム間でJVMの外部と通信する方法があります。これはリモートサービスと呼ばれます(7ページの エンタープライズ仕様PDF を参照)。彼らはまた、そのようなことをするときに考慮に入れるべき要因についての素晴らしい議論をしています(13.1誤謬を参照)。

Apache Felix(OSGIの実装)の人々私はこれをiPOJOで実装していると思います iPOJOを使用した分散サービス (サービスの使用を容易にするラッパー)。私はこれを使ったことがないので、間違っている場合は無視してください。

6
Andriy Drozdyuk
5
superfav

Stdin/stdoutを使用できない場合は、ソケットを使用します。 (stdin/stdoutの場合と同様に)ソケットの上にある種のシリアル化レイヤーが必要です。RMIは非常に使いやすく、非常に効果的なレイヤーです。

RMIを使用していて、パフォーマンスが十分でないことがわかった場合は、より効率的なシリアライザーに切り替えます 豊富なオプション

私はWebサービスやXMLの近くには行きません。これは完全に時間の無駄のように思われ、RMIよりも多くの労力を要し、パフォーマンスが低下する可能性があります。

4
Tom Anderson

それは上で述べましたが、私はJMXの提案を少し拡張したいと思いました。私たちは実際にあなたが計画していることをほぼ正確に行っています(私があなたのさまざまなコメントから収集できることから)。さまざまな理由でjmxを使用することにしましたが、そのいくつかをここで説明します。一つには、jmxはすべて管理に関するものなので、一般的には、やりたいことに完全に適合します(特に、他の管理タスク用にjmxサービスをすでに計画している場合)。 jmxインターフェースに注ぐ努力は、Java jvisualvmのような管理ツールを使用して呼び出すことができるAPIとしての二重の義務を果たします。これは、あなたが望むものに最も関連する次のポイントにつながります。 new Attach API jdk 6以降では非常に便利です。実行中のjvmを動的に検出して通信できます。これにより、たとえば、「コントローラー」プロセスをクラッシュさせて再起動し、再起動できます。既存のすべてのワーカープロセスを検索します。これは非常に堅牢なシステムの作成です。jmxは基本的に内部でrmiですが、rmiを直接使用する場合とは異なり、すべての接続の詳細を管理する必要はありません(例:一意のポート、検出可能性などを備えています)。attachapiは、十分に文書化されていないため、jdkに隠された宝石です。最初にこのようなものを突っ込んでいたとき、名前がわかりませんでした。 apiなので、jvisualvmとjconsoleの「魔法」がどのように機能するかを理解するのは非常に困難でした。最後に、記事のようなものに出くわしました。 e this one 、これは、独自のプログラムでアタッチapiを実際に使用する方法を示しています。

3
jtahlborn

もはやRMIを好む人はあまりいないようです。

オプション:

  1. ウェブサービス。例えば http://cxf.Apache.org
  2. JMX。さて、これは実際にはテーブルの下でRMIを使用する手段ですが、機能します。
  3. その他IPCプロトコル;あなたはヘシアンを引用しました
  4. ソケット、または共有メモリを使用して自分でロールバックします。 (マップされたファイルを親で開き、子でもう一度開きます。同期のために何かが必要です。)

注目すべき例は、Apache ant(何らかの目的で、あらゆる種類のJVMをフォークする)、Apache maven、およびTanukisoftデーモン化キットのオープンソースバリアントです。

個人的に、私はWebサービスに非常に慣れているので、それは私が物事を釘に変える傾向があるハンマーです。典型的なJAX-WS + JAX-BまたはJAX-RS + JAX-Bサービスは、CXFを使用した非常に小さなコードであり、すべてのデータのシリアル化と逆シリアル化を管理します。

3
bmargulies

JVM間の潜在的なリモート通信用に設計されていますが、 Netty はローカルJVMインスタンス間でも非常にうまく機能することがわかると思います。

これはおそらく、Java向けのタイプの中で最もパフォーマンスが高く、堅牢で、広くサポートされているライブラリです。

2
mikera

多くは上で議論されています。しかし、それがソケット、rmi、jmsであろうと、関係する汚い作業がたくさんあります。私はアドバイスをガラガラと言います akka 。これは、メッセージを使用して相互に通信するアクターベースのモデルです。

美しさは、アクターが同じJVMまたは別のJVM(非常に小さな構成)上にある可能性があり、akkaが残りを処理してくれることです。私はこれを行うよりもクリーンな方法を見たことがありません:)

2
Jatin

通信するデータが大きくない場合は、 jGroups を試してください。

1
zengr

あなたが言ったように、あなたは明らかにネットワークを介してオブジェクトを送ることができますが、それは別のJVMを起動することは言うまでもなくコストのかかることです。

1つのJVM内で異なるワールドを分離したいだけの場合の別のアプローチは、異なるクラスローダーでクラスをロードすることです。 ClassA @ CL1!= ClassA @ CL2(CL1およびCL2によって兄弟クラスローダーとしてロードされる場合)。

ClassA @ CL1とclassA @ CL2の間の通信を有効にするには、3つのクラスローダーを使用できます。

  • Process1をロードするCL1
  • Process2をロードするCL2(CL1と同じクラス)
  • 通信クラス(POJOおよびサービス)をロードするCL3。

ここで、CL3をCL1とCL2の親クラスローダーにします。

CL3によってロードされたクラスでは、CL1のクラスとCL2のクラスの間で、軽量の通信送信/受信機能(send(Pojo)/ receive(Pojo))を使用できます。

CL3では、CL1およびCL2レジスタからの実装がPOJOを送受信できるようにする静的サービスを公開します。

0
Niclas

どうですか http://code.google.com/p/protobuf/ 軽量です。

0
Felix Ng