本地JVM之间的通信

时间:2011-02-19 16:48:45

标签: java sockets jvm rmi cajo

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

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

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

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

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

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

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

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

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

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

11 个答案:

答案 0 :(得分:6)

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

它允许您在SAME jvm中彼此完全隔离地运行Java项目。 它的美妙之处在于项目之间的沟通非常容易(见Core Specifications PDF第123页)。这样就没有任何类型的“序列化”,因为数据和调用都在同一个jvm中。

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

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

更新

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

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

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

答案 1 :(得分:5)

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

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

答案 2 :(得分:5)

akka是另一个选项,other java actor frameworks,它提供了来自actor model的通信和其他好处。

答案 3 :(得分:4)

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

如果您使用RMI并发现性能不够好,我会切换到更高效的序列化程序 - 有plenty of options

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

答案 4 :(得分:3)

似乎没有多少人喜欢RMI。

选项:

  1. 网络服务。例如http://cxf.apache.org
  2. JMX。现在,这实际上是在表格下使用RMI的一种方法,但它可以工作。
  3. 其他IPC协议;你引用了Hessian
  4. 使用套接字甚至共享内存自行滚动。 (在父级中打开一个映射文件,在子级中再次打开它。你仍然需要一些东西进行同步。)
  5. 注意事项包括Apache ant(为各种目的分发各种Jvms),Apache maven以及Tanukisoft daemonization kit的开源变体。

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

答案 5 :(得分:3)

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

答案 6 :(得分:2)

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

它可能是Java类型中性能最佳/健壮/广泛支持的库。

答案 7 :(得分:2)

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

美丽的是,演员可以在同一个JVM或另一个(非常小的配置)上,而akka会照顾好你的其余部分。我没有看到比这样做更清洁的方式:)

答案 8 :(得分:1)

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

答案 9 :(得分: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。

答案 10 :(得分:0)

http://code.google.com/p/protobuf/怎么样 它很轻巧。