26

我的问题:我可以/应该采取什么方法在本地运行的两个或多个 JVM 实例之间进行通信?

问题的一些描述:
我正在为一个项目开发一个系统,该项目需要单独的 JVM 实例来完全隔离某些任务。

在它运行时,“父”JVM 将创建它期望执行的“子”JVM,然后将结果返回给它(以相对简单的 POJO 类的格式,或者可能是结构化的 XML 数据)。这些结果不应该使用 SysErr/SysOut/SysIn 管道传输,因为子进程可能已经使用这些作为其运行的一部分。

如果子 JVM 在一定时间内没有响应结果,则父 JVM 应该能够向子 JVM 发出信号以停止处理或终止子进程。否则,子 JVM 应该在完成其任务结束时正常退出。

迄今为止的研究:
我知道有许多技术可能有用,例如...

  • 使用 Java 的 RMI 库
  • 使用套接字传输对象
  • 使用分发库,例如 Cajo、Hessian

...但我很想听听其他人在追求这些选择之一或任何其他选择之前可能会考虑什么方法。

感谢您对此提供任何帮助或建议!

编辑:
要传输的数据量 -相对较小,主要是少数 POJO,其中包含表示子执行结果的字符串。如果任何解决方案在大量信息上效率低下,这不太可能是我的系统中的问题。转移的金额应该是相当静态的,因此不必可扩展的。

传输延迟——在这种情况下不是一个关键问题,尽管如果需要对结果进行任何“轮询”,这应该能够相当频繁地进行,而不会产生大量开销,因此我可以在以后在此之上维护一个响应式 GUI(例如进度条)

4

11 回答 11

6

不是直接回答您的问题,而是建议替代方案。你考虑过OSGI吗?

它允许您在相同的 jvm 中完全隔离地运行 java 项目。它的美妙之处在于项目之间的通信非常容易通过服务进行(参见核心规范 PDF第 123 页)。这样就不会进行任何类型的“序列化”,因为数据和调用都在同一个 jvm 中。

此外,您对服务质量(响应时间等)的所有要求都消失了 - 您只需要担心在您想要使用服务时服务是 UP 还是 DOWN。为此,您有一个非常好的规范,称为声明式服务(参见企业规范 PDF第 141 页)

对不起,题外话的答案,但我认为其他一些人可能会认为这是一个替代方案。

更新

要回答您有关安全性的问题,我从未考虑过这种情况。我不相信有办法在 OSGI 中强制使用“内存”。

但是,有一种方法可以在不同 OSGI 运行时之间在 JVM 之外进行通信。它被称为远程服务(参见Enterprise Spec PDF,第 7 页)。他们还很好地讨论了在做类似的事情时要考虑的因素(见 13.1 谬误)。

Apache Felix 的人(OSGI 的实现)我认为已经用 iPOJO 实现了这个,称为分布式服务和 iPOJO(他们的包装器使使用服务更容易)。我从来没有使用过这个 - 如果我错了,请忽略我。

于 2011-02-19T18:16:36.317 回答
5

会将 KryoNet与本地套接字一起使用,因为它非常专注于序列化并且非常轻量级(您还可以获得远程方法调用!我现在正在使用它),但禁用套接字断开超时。

RMI 的工作原理是你有一个远程类型并且远程类型实现了一个接口。这个接口是共享的。在您的本地机器上,您通过 RMI 库将接口绑定到从 RMI 库“注入”内存中的代码,结果是您拥有满足接口但能够与远程对象通信的东西。

于 2011-02-19T18:03:17.193 回答
5

akka是另一种选择,以及其他 java actor 框架,它提供了从actor 模型派生的通信和其他好处。

于 2011-02-19T21:12:07.550 回答
4

如果您不能使用标准输入/标准输出,那么我会使用套接字。您需要在套接字之上的某种序列化层(就像使用 stdin/stdout 一样),而 RMI 是一个非常易于使用且非常有效的此类层。

如果您使用 RMI 并发现性能不够好,我会切换到一些更高效的序列化程序 - 有很多选项

我不会去任何靠近 Web 服务或 XML 的地方。与 RMI 相比,这似乎完全是在浪费时间,可能需要更多的努力并提供更少的性能。

于 2011-02-19T17:59:59.227 回答
3

似乎没有多少人不再喜欢 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 代码,并为我管理所有数据序列化和反序列化。

于 2011-02-19T17:17:39.727 回答
3

上面提到过,但我想对 JMX 建议进行一些扩展。实际上,我们所做的几乎与您计划做的完全一样(从我可以从您的各种评论中收集到的信息)。我们出于各种原因开始使用 jmx,我将在这里提到其中的一些。一方面,jmx 是关于管理的,所以总的来说它非常适合你想做的事情(特别是如果你已经计划为其他管理任务提供 jmx 服务)。您在 jmx 接口上所做的任何努力都将起到双重作用,因为您可以使用 java 管理工具(如 jvisualvm)调用 api。这引出了我的下一点,这与您想要的最相关。新的附加 API在 jdk 6 及更高版本中非常甜蜜。它使您能够动态地发现正在运行的 jvm 并与之通信。例如,这允许您的“控制器”进程崩溃并重新启动并重新找到所有现有的工作进程。这是一个非常强大的系统的组成部分。上面提到了 jmx 基本上是 rmi 底层,但是,与直接使用 rmi 不同,您不需要管理所有连接细节(例如处理唯一端口、可发现性等)。attach api 在 jdk 中有点像隐藏的宝石,因为它没有很好的文档记录。当我最初研究这些东西时,我不知道 api 的名称,所以弄清楚 jvisualvm 和 jconsole 中的“魔法”是如何工作的非常困难。终于,我看到了这样一篇文章在您自己的程序中动态使用附加 api。

于 2011-02-20T03:05:15.420 回答
2

尽管它是为 JVM 之间的潜在远程通信而设计的,但我认为您会发现Netty在本地 JVM 实例之间也能很好地工作。

它可能是同类 Java 中性能最高/最健壮/受广泛支持的库。

于 2011-02-19T18:12:30.210 回答
2

上面讨论了很多。但无论是套接字、rmi、jms - 都涉及大量肮脏的工作。我会建议akka。它是一个基于actor的模型,使用消息相互通信。

美妙之处在于,演员可以在同一个 JVM 或另一个(非常少的配置)上,而 akka 会为您处理其余的事情。我还没有看到比这样做更清洁的方法:)

于 2013-05-09T09:23:09.803 回答
1

如果要传达的数据不是很大,请尝试使用 jGroups 。

于 2011-02-19T18:01:42.390 回答
0

正如您所提到的,您显然可以通过网络发送对象,但这是一件昂贵的事情,更不用说启动一个单独的 JVM。

如果您只想在一个 JVM 中分离不同的世界,另一种方法是使用不同的类加载器加载类。ClassA@CL1!=ClassA@CL2 如果它们由 CL1 和 CL2 作为同级类加载器加载。

要启用 classA@CL1 和 classA@CL2 之间的通信,您可以拥有三个类加载器。

  • 加载 process1 的 CL1
  • 加载 process2 的 CL2(与 CL1 中的类相同)
  • 加载通信类(POJO 和服务)的 CL3。

现在让 CL3 成为 CL1 和 CL2 的父类加载器。

在 CL3 加载的类中,您可以在 CL1 中的类和 CL2 中的类之间拥有轻量级通信发送/接收功能(发送(Pojo)/接收(Pojo))POJO。

在 CL3 中,您公开了一个静态服务,该服务使 CL1 和 CL2 寄存器中的实现能够发送和接收 POJO。

于 2011-02-19T17:07:40.880 回答
0

http://code.google.com/p/protobuf/怎么样? 它是轻量级的。

于 2011-02-19T19:40:41.473 回答