本地JVM之间的通信

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

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

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

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

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

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

…但我有兴趣听取其他人在推行其中一种方案或其他方案之前可能会考虑的方法。

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

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

转移的延迟 –在这种情况下不是一个关键问题,尽管如果需要对结果进行任何“轮询”,这应该能够相当频繁而没有显着的开销,因此我可以在以后维护响应式GUI(例如进度条)

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

RMI基本上基于您具有远程类型并且远程类型实现接口的原则。 此接口是共享的。 在本地计算机上,通过RMI库将接口绑定到RMI库中的“inject”内存代码,结果是您拥有满足接口但能够与远程对象通信的内容。

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

它允许您在SAME jvm中彼此完全隔离地运行Java项目。 它的美妙之处在于项目之间的通信很容易通过服务进行(参见核心规范PDF第123页)。 这种方式没有任何类型的“序列化”,因为数据和调用都在同一个jvm中。

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

对于非主题回答感到抱歉,但我认为其他人可能会认为这是另一种选择。

更新

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

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

Apache Felix的人(OSGI的实现)我认为用iPOJO实现了这个,用iPOJO称为分布式服务 (他们的包装器使服务更容易使用)。 我从来没有用过这个 – 所以如果我错了就不理我。

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

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

如果您使用RMI并发现性能不够好,我会转而使用更高效的串行器 – 有很多选择 。

我不会去任何Web服务或XML附近。 这似乎完全浪费时间,可能需要更多的努力并提供比RMI更低的性能。

似乎没有多少人喜欢RMI了。

选项:

  1. 网页服务。 例如http://cxf.apache.org
  2. JMX。 现在,这实际上是在表格下使用RMI的一种方法,但它可以工作。
  3. 其他IPC协议; 你引用了Hessian
  4. 使用套接字甚至共享内存自行滚动。 (在父级中打开一个映射文件,在子级中再次打开它。你仍然需要一些东西进行同步。)

注意事项的例子是Apache ant(为各种目的分配各种Jvms),Apache maven以及Tanukisoft daemonization kit的开源变体。

就个人而言,我非常容易使用网络服务,所以这就是我倾向于把东西变成钉子的锤子。 典型的JAX-WS + JAX-B或JAX-RS + JAX-B服务是CXF的非常少的代码,并为我管理所有数据序列化和反序列化。

上面提到过,但我想对JMX的建议进行一些扩展。 我们实际上正在做的正是你打算做的事情(从我可以从你的各种评论中收集到的)。 我们出于各种原因使用jmx,其中一些我会在这里提到。 首先,jmx是关于管理的,所以一般来说它非常适合你想要做的事情(特别是如果你已经计划为其他管理任务提供jmx服务)。 你在jmx接口中所做的任何努力都将扮演双重责任,因为你可以使用jvisualvm之类的java管理工具调用它。 这导致了我的下一点,这与你想要的最相关。 jdk 6及更高版本中的新Attach API非常甜蜜。 它使您能够动态发现并与正在运行的jvms通信。 例如,这允许您的“控制器”进程崩溃并重新启动并重新查找所有现有的工作进程。 这是一个非常强大的系统的材料。 上面提到jmx基本上是rmi,然而,与直接使用rmi不同,您不需要管理所有连接细节(例如处理独特端口,可发现性等)。 attach api在jdk中是一个隐藏的gem,因为它没有很好的记录。 当我最初开始研究这个东西时,我不知道api的名字,所以想想jvisualvm和jconsole中的“魔法”是如何工作的非常困难。 最后,我遇到了一篇类似这样的文章,它展示了如何在你自己的程序中动态实际使用 attach api。

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

它可能是Java类型中性能最高/最强大/最广泛支持的库。

上面讨论了很多。 但无论是套接字,rmi,jms – 都涉及到一些肮脏的工作。 我会劝告akka 。 它是基于actor的模型,它使用Messages进行相互通信。

美女是,演员可以在同一个JVM或另一个(非常小的配置)和akka照顾其余的你。 我还没有看到比这更干净的方式:)

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

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

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

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

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

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

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

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

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

Interesting Posts