java sockets jvm rmi cajo

java - Comunicación entre JVM locales



sockets rmi (11)

¿Qué hay de http://code.google.com/p/protobuf/ Es liviano.

Mi pregunta: ¿Qué enfoque puedo / debo tomar para comunicarme entre dos o más instancias de JVM que se ejecutan localmente?

Alguna descripción del problema:
Estoy desarrollando un sistema para un proyecto que requiere instancias de JVM separadas para aislar por completo ciertas tareas entre sí.

En ejecución, la JVM ''principal'' creará JVM ''hijo'' que esperará ejecutar y luego le devolverá los resultados (en el formato de clases POJO relativamente simples, o tal vez datos XML estructurados). Estos resultados no deben transferirse utilizando las canalizaciones SysErr / SysOut / SysIn ya que el niño ya puede usarlos como parte de su ejecución.

Si una JVM secundaria no responde con resultados dentro de un tiempo determinado, la JVM padre debe poder indicarle al niño que deje de procesar o que mate el proceso secundario. De lo contrario, la JVM secundaria debería salir normalmente al finalizar su tarea.

Investigación hasta el momento:
Soy consciente de que hay varias tecnologías que pueden ser de utilidad, por ejemplo ...

  • Usando la biblioteca RMI de Java
  • Usando enchufes para transferir objetos
  • Usando bibliotecas de distribución como Cajo, Hessian

... pero estoy interesado en escuchar qué enfoques pueden considerar otros antes de seguir una de estas opciones, o cualquier otra.

Gracias por cualquier ayuda o consejo sobre esto!

Ediciones:
Cantidad de datos a transferir: relativamente pequeña, será principalmente un puñado de POJO que contienen cadenas que representarán el resultado de la ejecución del niño. Si alguna solución sería ineficiente en grandes cantidades de información, es poco probable que esto sea un problema en mi sistema. La cantidad que se transfiere debe ser bastante estática y, por lo tanto, no tiene que ser escalable.

Latencia de transferencia: no es una preocupación crítica en este caso, aunque si se necesita una ''encuesta'' de resultados, esto debería ser bastante frecuente sin gastos indirectos significativos, por lo que puedo mantener una GUI receptiva sobre esto en un momento posterior ( por ejemplo, barra de progreso)


Aunque está diseñado para una comunicación remota entre las JVM, creo que Netty funciona muy bien entre las instancias JVM locales.

Probablemente sea la biblioteca de mayor rendimiento / robusta / ampliamente respaldada de su tipo para Java.


Como mencionaste, obviamente puedes enviar los objetos a través de la red, pero eso es una tarea costosa, sin mencionar el inicio de una JVM separada.

Otro enfoque si solo desea separar sus diferentes mundos dentro de una JVM es cargar las clases con diferentes cargadores de clases. ClassA @ CL1! = ClassA @ CL2 si están cargadas por CL1 y CL2 como cargadores de clase hermanos.

Para habilitar las comunicaciones entre classA @ CL1 y classA @ CL2, puede tener tres cargadores de clases.

  • CL1 que carga el proceso1
  • CL2 que carga el proceso2 (las mismas clases que en CL1)
  • CL3 que carga clases de comunicación (POJO y servicio).

Ahora deja que CL3 sea el cargador de clases principal de CL1 y CL2.

En las clases cargadas por CL3 puede tener una funcionalidad de envío / recepción de comunicación ligera (enviar (Pojo) / recibir (Pojo)) los POJO entre las clases en CL1 y las clases en CL2.

En CL3, expone un servicio estático que permite implementaciones desde el registro CL1 y CL2 para enviar y recibir los POJO.


Mucho se discutió arriba. Pero sean tomas, rmi, jms, hay un montón de trabajo sucio involucrado. Yo le daría un consejo a akka . Es un modelo basado en el actor que se comunican entre sí utilizando Mensajes.

La belleza es que los actores pueden estar en la misma JVM u otra (muy poca configuración) y Akka se ocupa del resto por ti. No he visto una manera más limpia que hacer esto :)


No directamente una respuesta a su pregunta, sino una sugerencia de una alternativa. ¿Has considerado OSGI ?

Le permite ejecutar proyectos Java completamente aislados entre sí, dentro de MISMO jvm. La belleza de esto es que la comunicación entre proyectos es muy fácil con los servicios (ver Especificaciones Básicas PDF página 123). De esta forma, no se realiza ninguna "serialización" de ningún tipo, ya que los datos y las llamadas están todos en el mismo jvm.

Además, todos sus requisitos de calidad de servicio (tiempo de respuesta, etc.) desaparecen; solo tiene que preocuparse de si el servicio está ARRIBA o ABAJO en el momento que desee usarlo. Y para eso tiene una muy buena especificación que hace eso para usted llamado Servicios Declarativos (Ver Enterprise Spec PDF página 141)

Perdón por la respuesta fuera del tema, pero pensé que otras personas podrían considerar esto como una alternativa.

Actualizar

Para responder a su pregunta sobre la seguridad, nunca he considerado tal escenario. No creo que haya una forma de imponer el uso de "memoria" dentro de OSGI.

Sin embargo, hay una forma de comunicarse fuera de JVM entre diferentes tiempos de ejecución OSGI. Se llama Servicios remotos (consulte el PDF de especificaciones empresariales , página 7). También tienen una agradable discusión sobre los factores a tener en cuenta al hacer algo así (ver 13.1 Falacias).

Gente en Apache Felix (implementación de OSGI) Creo que tengo la implementación de esto con iPOJO, llamado Distributed Services con iPOJO (su envoltorio para facilitar el uso de los servicios). Nunca he usado esto, así que ignórame si estoy equivocado.


No parece que a muchas personas les guste RMI.

Opciones:

  1. Servicios web. por ejemplo, http://cxf.apache.org
  2. JMX. Ahora, esto es realmente un medio de usar RMI debajo de la mesa, pero funcionaría.
  3. Otros protocolos IPC; Usted citó Hessian
  4. Roll-tu-propio usando sockets, o incluso memoria compartida. (Abra un archivo asignado en el elemento primario, ábralo de nuevo en el elemento secundario. Aún necesitará algo para la sincronización).

Ejemplos de notas son Apache ant (que bifurca todo tipo de Jvms para un propósito u otro), Apache maven y la variante de código abierto del kit de daemonización de Tanukisoft.

Personalmente, soy muy fácil con los servicios web, así que ese es el martillo que suelo convertir en clavos. Un servicio típico JAX-WS + JAX-B o JAX-RS + JAX-B es muy poco código con CXF, y gestiona toda la serialización y deserialización de datos para mí.


Prueba jGroups si los datos a ser comunicados no son enormes.


Se mencionó anteriormente, pero quería ampliar un poco la sugerencia de JMX. en realidad estamos haciendo exactamente lo que planeas hacer (por lo que puedo deducir de tus diversos comentarios). llegamos a utilizar jmx por varias razones, algunas de las cuales mencionaré aquí. Por un lado, jmx tiene que ver con la administración, por lo que en general se ajusta perfectamente a lo que desea hacer (especialmente si ya planea tener servicios de jmx para otras tareas de administración). cualquier esfuerzo que pongas en las interfaces jmx servirá como una tarea doble a la que puedes llamar utilizando herramientas de administración de Java como jvisualvm. esto lleva a mi siguiente punto, que es el más relevante para lo que quieres. la nueva API Attach en jdk 6 y superior es muy agradable. le permite descubrir dinámicamente y comunicarse con ejecutar jvms. esto permite, por ejemplo, que su proceso de "controlador" se bloquee, reinicie y vuelva a encontrar todos los procesos de trabajo existentes. esta es la base de un sistema muy robusto. se mencionó anteriormente que jmx básicamente rmi bajo el capó, sin embargo, a diferencia del uso de rmi directamente, no es necesario que administre todos los detalles de conexión (por ejemplo, tratar con puertos únicos, descubrimiento, etc.). la aplicación adjunta es un poco una joya escondida en el jdk, ya que no está muy bien documentada. Cuando estaba metiéndome en esto inicialmente, no sabía el nombre de la API, por lo que calcular cómo funcionaba la "magia" en jvisualvm y jconsole fue muy difícil. finalmente, me encontré con un artículo como este , que muestra cómo usar el API de forma dinámica en tu propio programa.


Si no puede usar stdin / stdout, entonces iré con sockets. Necesita algún tipo de capa de serialización en la parte superior de los sockets (como lo haría con stdin / stdout), y RMI es una capa muy fácil de usar y bastante efectiva.

Si utilizó RMI y descubrió que el rendimiento no era lo suficientemente bueno, cambiaría a un serializador más eficiente: hay muchas opciones .

No me acercaría a servicios web o XML. Parece una completa pérdida de tiempo, es probable que requiera más esfuerzo y ofrezca menos rendimiento que RMI.



KryoNet con sockets locales ya que se especializa mucho en serialización y es bastante liviano (¡también recibes Invocación de método remoto! Lo estoy usando ahora mismo), pero deshabilita el tiempo de espera de desconexión del socket.

RMI básicamente funciona según el principio de que tiene un tipo de control remoto y que el tipo remoto implementa una interfaz. Esta interfaz es compartida. En su máquina local, vincula la interfaz a través de la biblioteca RMI para codificar ''inyectado'' en la memoria desde la biblioteca RMI, y el resultado es que tiene algo que satisface la interfaz pero puede comunicarse con el objeto remoto.