本地 JVM 之间的通信
我的问题:我可以/应该采取什么方法在本地运行的两个或多个 JVM 实例之间进行通信?
问题的一些描述:
我正在为一个项目开发一个系统,该项目需要单独的 JVM 实例来完全隔离某些任务。
在运行过程中,“父”JVM 将创建它希望执行的“子”JVM,然后将结果返回给它(以相对简单的 POJO 类的格式,或者可能是结构化 XML 数据)。这些结果不应使用 SysErr/SysOut/SysIn 管道进行传输,因为子进程可能已将这些结果用作其运行的一部分。
如果子 JVM 在一定时间内没有响应结果,父 JVM 应该能够向子 JVM 发出信号以停止处理,或者终止子进程。否则,子 JVM 应在完成其任务后正常退出。
迄今为止的研究:
我知道有许多技术可能有用,例如...
- 使用 Java 的 RMI 库
- 使用套接字传输对象
- 使用 Cajo、Hessian 等分发库
...但我有兴趣听听其他人在追求之前可能会考虑的方法这些选项之一或任何其他选项。
感谢您对此的任何帮助或建议!
编辑:
要传输的数据量相对较小,大部分只是少数 POJO,其中包含代表子级执行结果的字符串。如果任何解决方案在处理大量信息时效率低下,那么这不太可能成为我的系统中的问题。传输的金额应该是相当静态的,因此这不必必须是可扩展的。
传输延迟 - 在这种情况下不是一个关键问题,尽管如果需要对结果进行任何“轮询”,这应该能够相当频繁,而不会产生大量开销,因此我可以在顶部维护一个响应式 GUI稍后再进行(例如进度条)
My question: What approach could/should I take to communicate between two or more JVM instances that are running locally?
Some description of the problem:
I am developing a system for a project that requires separate JVM instances to isolate certain tasks from each other entirely.
In it's running, the 'parent' JVM will create 'child' JVMs that it will expect to execute and then return results to it (in the format of relatively simple POJO classes, or perhaps structured XML data). These results should not be transferred using the SysErr/SysOut/SysIn pipes as the child may already use these as part of its running.
If a child JVM does not respond with results within a certain time, the parent JVM should be able to signal to the child to cease processing, or to kill the child process. Otherwise, the child JVM should exit normally at the end of completing its task.
Research so far:
I am aware there are a number of technologies that may be of use e.g....
- Using Java's RMI library
- Using sockets to transfer objects
- Using distribution libraries such as Cajo, Hessian
...but am interested in hearing what approaches others may consider before pursuing one of these options, or any others.
Thanks for any help or advice on this!
Edits:
Quantity of data to transfer- relatively small, it will mostly be just a handful of POJOs containing strings that will represent the result of the child executing. If any solution would be inefficient on larger amounts of information, this is unlikely to be a problem in my system. The amount being transferred should be pretty static and so this does not have to be scalable.
Latency of transfer- not a critical concern in this case, although if any 'polling' of results is needed this should be able to be fairly frequent without significant overheads, so I can maintain a responsive GUI on top of this at a later time (e.g. progress bar)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
不是直接回答您的问题,而是提供替代方案的建议。
您考虑过OSGI吗?
它允许您在同一个 jvm 中运行彼此完全隔离的 Java 项目。
它的美妙之处在于,通过服务,项目之间的通信非常容易(请参阅核心规范 PDF 第 123 页)。这样就不会进行任何类型的“序列化”,因为数据和调用都在同一个 jvm 中。
此外,您对服务质量(响应时间等)的所有要求都消失了 - 您只需担心服务在您想要使用时是处于启动状态还是处于关闭状态。为此,您有一个非常好的规范,可以为您执行此操作,称为声明性服务(请参阅 企业规范 PDF 第 141 页)
对于偏离主题的答案感到抱歉,但我认为其他一些人可能会认为这是一种替代方案。
更新
为了回答您有关安全的问题,我从未考虑过这种情况。我不相信有一种方法可以在 OSGI 中强制使用“内存”。
然而,有一种方法可以在 JVM 之外的不同 OSGI 运行时之间进行通信。它称为远程服务(请参阅企业规范 PDF,第 7 页)。他们还对做类似事情时要考虑的因素进行了很好的讨论(参见 13.1 谬误)。
Apache Felix 的人们(OSGI 的实现)我认为已经使用 iPOJO 实现了这一点,称为 使用 iPOJO 的分布式服务(它们的包装器使服务的使用更加容易)。我从来没有用过这个 - 所以如果我错了请忽略我。
Not directly an answer to your question, but a suggestion of an alternative.
Have you considered OSGI?
It lets you run java projects in complete isolation from each other, within the SAME jvm.
The beauty of it is that communication between projects is very easy with services (see Core Specifications PDF page 123). This way there is not "serialization" of any sort being done as the data and calls are all in the same jvm.
Furthermore all your requirements of quality of service (response time etc...) go away - you only have to worry about whether the service is UP or DOWN at the time you want to use it. And for that you have a really nice specification that does that for you called Declarative Services (See Enterprise Spec PDF page 141)
Sorry for the off-topic answer, but I thought some other people might consider this as an alternative.
Update
To answer your question about security, I have never considered such a scenario. I don't believe there is a way to enforce "memory" usage within OSGI.
However there is a way of communicating outside of JVM between different OSGI runtimes. It is called Remote Services (see Enterprise Spec PDF, page 7). They also have nice discussion there of the factors to take into consideration when doing something like that (see 13.1 Fallacies).
Folks at Apache Felix (implementation of OSGI) I think have implementation of this with iPOJO, called Distributed Services with iPOJO (their wrapper to make using services easier). I've never used this - so ignore me if I am wrong.
我会将 KryoNet 与本地套接字一起使用,因为它专门从事序列化并且非常轻量级(您还获得远程方法调用!我现在正在使用它),但禁用套接字断开超时。
RMI 的基本工作原理是,您有一个远程类型,并且该远程类型实现一个接口。该接口是共享的。在本地计算机上,您通过 RMI 库将接口绑定到从 RMI 库“注入”到内存中的代码,结果是您拥有满足接口但能够与远程对象通信的东西。
I'd use KryoNet with local sockets since it specialises heavily in serialisation and is quite lightweight (you also get Remote Method Invocation! I'm using it right now), but disable the socket disconnection timeout.
RMI basically works on the principle that you have a remote type and that the remote type implements an interface. This interface is shared. On your local machine, you bind the interface via the RMI library to code 'injected' in-memory from the RMI library, the result being that you have something that satisfies the interface but is able to communicate with the remote object.
akka 是另一种选择,还有 其他 java actor 框架,它提供了源自 演员模型。
akka is another option, as well as other java actor frameworks, it provides communication and other goodies derived from the actor model.
如果你不能使用标准输入/标准输出,那么我会使用套接字。您需要在套接字之上某种序列化层(就像使用 stdin/stdout 一样),而 RMI 是一个非常易于使用且非常有效的此类层。
如果您使用 RMI 并发现性能不够好,我会切换到一些更高效的序列化器 - 有 大量选项。
我不会去任何接近 Web 服务或 XML 的地方。这看起来完全是浪费时间,与 RMI 相比,可能会花费更多的精力,但性能却较差。
If you can't use stdin/stdout, then i'd go with sockets. You need some sort of serialization layer on top of the sockets (as you would with stdin/stdout), and RMI is a very easy to use and pretty effective such layer.
If you used RMI and found the performance wasn't good enough, i'd switch to some more efficient serializer - there are plenty of options.
I wouldn't go anywhere near web services or XML. That seems like a complete waste of time, likely take more effort and deliver less performance than RMI.
似乎不再有多少人喜欢 RMI。
选项:
值得注意的示例包括 Apache ant(出于某种目的分叉各种 Jvm)、Apache maven 和Tanukisoft 守护进程工具包的开源变体。
就我个人而言,我对网络服务非常熟悉,所以这就是我倾向于把东西变成钉子的锤子。典型的 JAX-WS+JAX-B 或 JAX-RS+JAX-B 服务只需很少的 CXF 代码,并为我管理所有数据序列化和反序列化。
Not many people seem to like RMI any longer.
Options:
Examples of note are Apache ant (which forks all sorts of Jvms for one purpose or another), Apache maven, and the open source variant of the Tanukisoft daemonization kit.
Personally, I'm very facile with web services, so that's the hammer which which I tend to turn things into nails. A typical JAX-WS+JAX-B or JAX-RS+JAX-B service is very little code with CXF, and manages all the data serialization and deserialization for me.
上面已经提到了,但我想对 JMX 建议进行一些扩展。实际上,我们正在做的事情几乎正是您计划做的(从我从您的各种评论中收集到的信息)。我们出于多种原因开始使用 jmx,我将在这里提到其中的一些原因。一方面,jmx 是关于管理的,所以一般来说它非常适合您想要做的事情(特别是如果您已经计划使用 jmx 服务来执行其他管理任务)。您在 jmx 接口上投入的任何努力都将发挥双重作用,因为您可以使用 jvisualvm 等 java 管理工具来调用 api。这引出了我的下一点,这与你想要的最相关。 jdk 6 及更高版本中的新 Attach API很甜蜜。它使您能够动态发现正在运行的 jvm 并与之通信。例如,这允许您的“控制器”进程崩溃并重新启动并重新查找所有现有的工作进程。这是一个非常强大的系统的基础。上面提到 jmx 本质上是 rmi,但是,与直接使用 rmi 不同,您不需要管理所有连接细节(例如处理唯一端口、可发现性等)。 Attach api 是 jdk 中的一个隐藏宝石,因为它没有很好的文档记录。当我最初研究这些东西时,我不知道 api 的名称,因此弄清楚 jvisualvm 和 jconsole 中的“魔力”是如何工作的非常困难。最后,我遇到了一篇类似这篇的文章,它展示了如何实际在您自己的程序中动态使用附加 API。
It was mentioned above, but i wanted to expand a bit on the JMX suggestion. we actually are doing pretty much exactly what you are planning to do (from what i can glean from your various comments). we landed on using jmx for a variety of reasons, a few of which i'll mention here. for one thing, jmx is all about management, so in general it is a perfect fit for what you want to do (especially if you already plan on having jmx services for other management tasks). any effort you put into jmx interfaces will do double duty as apis you can call using java management tools like jvisualvm. this leads to my next point, which is the most relevant to what you want. the new Attach API in jdk 6 and above is very sweet. it enables you to dynamically discover and communicate with running jvms. this allows, for example, for your "controller" process to crash and restart and re-find all the existing worker processes. this is the makings of a very robust system. it was mentioned above that jmx basically rmi under the hood, however, unlike using rmi directly, you don't need to manage all the connection details (e.g. dealing with unique ports, discoverability, etc). the attach api is a bit of a hidden gem in the jdk, as it isn't very well documented. when i was poking into this stuff initially, i didn't know the name of the api, so figuring how the "magic" in jvisualvm and jconsole worked was very difficult. finally, i came across an article like this one, which shows how to actually use the attach api dynamically in your own program.
尽管它是为 JVM 之间潜在的远程通信而设计的,但我认为您会发现 Netty 在本地之间工作得非常好JVM 实例也是如此。
它可能是 Java 同类库中性能最高/最强大/最受广泛支持的库。
Although it's designed for potentially remote communication between JVMs, I think you'll find that Netty works extremely well between local JVM instances as well.
It's probably the most performant / robust / widely supported library of its type for Java.
上面讨论了很多。但无论是套接字、rmi、jms——都涉及大量肮脏的工作。
我会提供建议akka。它是一个基于参与者的模型,使用消息相互通信。
美妙之处在于,参与者可以位于同一个 JVM 或另一个(非常少的配置)上,akka 会为你处理剩下的事情。我还没有见过比这样做更干净的方法:)
A lot is discussed above. But be it sockets, rmi, jms - there is a lof of dirty work involved.
I would ratter advice akka. It is a actor based model which communicate with each other using Messages.
The beauty is, the actors can be on same JVM or another (very little config) and akka takes care the rest for you. I haven't seen a more cleaner way than doing this :)
如果要传递的数据不大,请尝试jGroups。
Try out jGroups if the data to be communicated is not huge.
http://code.google.com/p/protobuf/ 怎么样
它很轻。
How about http://code.google.com/p/protobuf/
It is lightweight.
正如您所提到的,您显然可以通过网络发送对象,但这是一件成本高昂的事情,更不用说启动一个单独的 JVM 了。
如果您只想在一个 JVM 中分离不同的世界,另一种方法是使用不同的类加载器加载类。 ClassA@CL1!=ClassA@CL2(如果它们由 CL1 和 CL2 作为同级类加载器加载)。
要启用 classA@CL1 和 classA@CL2 之间的通信,您可以拥有三个类加载器。
现在让 CL3 成为 CL1 和 CL2 的父类加载器。
在 CL3 加载的类中,您可以在 CL1 中的类和 CL2 中的类之间拥有轻量级通信发送/接收功能(发送(Pojo)/接收(Pojo))POJO。
在 CL3 中,您公开一个静态服务,使 CL1 和 CL2 寄存器的实现能够发送和接收 POJO。
As you mentioned you can obviously send the objects over the network but that is a costly thing not to mention start up a separate JVM.
Another approach if you just want to separate your different worlds inside one JVM is to load the classes with different classloaders. ClassA@CL1!=ClassA@CL2 if they are loaded by CL1 and CL2 as sibling classloaders.
To enable communications between classA@CL1 and classA@CL2 you could have three classloaders.
Now you let CL3 be the parent classloader of CL1 and CL2.
In classes loaded by CL3 you can have a light-weight communication send/receive functionality (send(Pojo)/receive(Pojo)) the POJOs between classes in CL1 and classes in CL2.
In CL3 you expose a static service that enables implementations from CL1 and CL2 register to send and receive the POJOs.