2010-01-05 15 views
12

La aplicación tiene un proceso largo intensivo de CPU que actualmente se ejecuta en un servidor (un método EJB) en serie cuando el cliente lo solicita.¿Cómo puede un EJB paralelizar un proceso largo, intensivo de CPU?

Es teóricamente posible (desde un punto de vista conceptual) para dividir el proceso en N trozos y ejecutarlos en paralelo, siempre y cuando la salida de todos los trabajos paralelos se pueden recoger y unidos entre sí antes de enviarlo de vuelta al cliente que inició el proceso. Me gustaría utilizar esta paralelización para optimizar el rendimiento.

¿Cómo puedo implementar esta paralelización con los EJB? Sé que no deberíamos crear hilos en un método EJB. En su lugar, debemos publicar mensajes (uno por trabajo) para ser consumidos por beans controlados por mensajes (MDB). Pero entonces ya no sería una llamada síncrona. Y ser sincrónico parece ser un requisito en este caso, ya que necesito recopilar la salida de todos los trabajos antes de enviarlos al cliente.

¿Existe una solución para esto?

Respuesta

6

Esta pregunta en particular ha surgido en múltiples ocasiones y resumiré que hay varias soluciones posibles, de las cuales solo 1 recomendaría.

Use un WorkManager de la API de commonj. Permite subprocesos administrados en un contenedor Java EE y está específicamente diseñado para adaptarse a su caso de uso. Si está utilizando WebSphere o WebLogic, estas API ya están disponibles en su servidor. Para otros, tendrá que poner una solución de terceros en usted mismo.

WorkManager info

preguntas relacionadas Why Spawning threads is discouraged

+0

Parece que 'WorkManager' es específico de WebSphere, por lo que no es adecuado en general: http://stackoverflow.com/questions/9026516/replacing-webspheres-workmanager-in-jboss – Raedwald

+1

Eso no se refiere al Commonj WorkManager, sino a una solución específica de IBM que lo antecede. Como ya he mencionado, commonj no es específico de IBM y está disponible en la mayoría de las plataformas. – Robin

1

Una vez participé en un proyecto donde las transacciones de EJB se ejecutaron durante hasta 5 horas a la vez. ¡Aargh!

Esta misma aplicación también tenía un consultor especialista en BEA que aprobó el inicio de hilos adicionales de las transacciones. Si bien no se recomienda en las especificaciones ni en ningún otro lugar, no da como resultado automáticamente un error. Debes ser consciente de que tus hilos adicionales están fuera del control del contenedor y, por lo tanto, si algo sale mal es tu culpa. Pero si puede asegurar que el número de subprocesos iniciados en el peor de los casos no excede los límites razonables, y que todos terminan de forma limpia en un tiempo razonable, entonces es bastante posible trabajar así. De hecho, en tu caso suena como la solución casi única.

Existen algunas soluciones ligeramente esotéricas en las que su aplicación EJB llega a otra aplicación para un servicio, que luego realiza el subprocesamiento en sí mismo antes de volver al llamador EJB. Pero esto es esencialmente solo cambiar el problema.

Puede, sin embargo, considerar una solución de agrupamiento de subprocesos para mantener un límite superior en la cantidad de subprocesos generados. Si tiene demasiados hilos, su aplicación se comportará de manera horrible.

+0

no "disrecommended", de plano no permitido: http://stackoverflow.com/ a/9739300/545127 – Raedwald

1

Has analizado la situación bastante bien, y no, no hay patern para esto que coincida con el modelo EJB.

La creación de subprocesos está prohibida principalmente porque omite la aplicación . gestión de hilo del servidor estrategia y también debido a las transacciones .

Trabajé en un proyecto con requisitos similares y decidí engendrar hilos adicionales (yendo contra el sepc luego). La operación para paralelizar era de solo lectura, por lo que funcionó con respecto a la transacción (el hilo básicamente no tendría una transacción asociada). También sabía que no generaría demasiados subprocesos por llamadas EJB, por lo que el número de subprocesos no era un problema. Pero si se supone que sus hilos modifiquen datos, entonces se rompe el modelo transaccional del EJB con seriedad. Pero si su operación en computación pura, eso podría estar bien.

creo que sirve ...

+0

Buscar t El WorkManager de CommonJ API. Le permite hacer esto en hilos gestionados. – Robin

4

EJB es una última instancia un componente transaccional de un sistema cliente-servidor que proporciona petición/respuesta semántica. Si se encuentra en la posición de que necesita encasillar una transacción de larga duración dentro de los límites de un ciclo de solicitud/respuesta, entonces, en algún lugar, su arquitecto de sistemas (ure) ha tomado un giro equivocado.

La situación que describe se maneja de forma limpia y correcta mediante una arquitectura basada en eventos con un servidor de mensajes. El evento inicial inicia el proceso (que luego puede paralelizarse de manera trivial al hacer que los trabajadores se suscriban al tema del evento) y el proceso de agregación en sí mismo plantea un evento al completarse. Todavía puede exprimir estas secuencias dentro de los límites de un ciclo de solicitud/respuesta, pero necesariamente violará la letra y el espíritu de las especificaciones de la arquitectura del sistema Java EE.

+0

Esa es una vista en blanco y negro del mundo, la mayoría de nosotros tiene que lidiar con tonos de gris. No desearía volver a crear un sistema completo solo para proporcionar esta funcionalidad. Sin mencionar que no hay nada intrínsecamente incorrecto en tener una llamada síncrona que realice múltiples operaciones paralelas antes de regresar cuando ya están listas. Esto por sí solo no justifica una arquitectura basada en eventos en lugar de una simple solicitud/respuesta. – Robin

+0

No hay nada de malo con lo que describe en el contexto de un marco o plataforma que se especifica y se diseña con tales operaciones en mente. Pero esa no es la plataforma JEE. El objetivo de JEE es la adopción de restricciones para promover la distribución y la disponibilidad (y el objetivo ahora olvidado de la orientación de los componentes). Una vez que comienzas a romper las restricciones estás efectivamente en un camino autodestructivo. Entonces, debemos estar en desacuerdo sobre el punto de rechazar el mal uso de la tecnología como un caso de punto de vista dogmático ("blanco y negro"). – alphazero

+0

"semántica de solicitud/respuesta ... una arquitectura basada en eventos con un mensaje de fondo" Veo su punto si las solicitudes sematnics son "realizar un proceso a largo plazo" y la respuesta es "proceso a largo plazo finalizado". Pero, ¿cabría dentro del modelo JEE si la solicitud significa "iniciar un proceso a largo plazo" y la respuesta es "proceso a largo plazo en cola"? Luego, como sugiere otra respuesta, el EJB puede simplemente enviar un mensaje usando JMS para que un MDB (o incluso un consumidor que no sea JEE) realice el trabajo. – Raedwald

10

Hay todo tipo de maneras de hacer esto.

Uno, puede usar un temporizador EJB para crear un proceso de ejecución única que se iniciará inmediatamente. Esta es una buena técnica para generar procesos en el fondo. Un temporizador EJB está asociado con una implementación específica de Session Bean. Puede agregar un temporizador EJB a cada Session Bean que desee para poder hacer esto, o puede tener un solo Session Bean que luego puede invocar la lógica de la aplicación a través de algún mecanismo de despacho.

Para mí, paso una cantidad serializable de parámetros junto con un nombre de clase que cumple una interfaz específica para un Session Bean genérico que luego ejecuta la clase. De esta manera, puedo copiar fácilmente cualquier cosa.

Una advertencia sobre el temporizador EJB es que los temporizadores EJB son persistentes. Una vez que crea un temporizador EJB permanece en el contenedor hasta que su trabajo finaliza o se cancela. El problema es que si tiene un proceso largo y el servidor se cae, cuando se reinicia el proceso continuará y volverá a realizar una copia de seguridad. Tenga en cuenta que esto puede ser algo bueno, pero solo si su proceso está preparado para reiniciarse. Pero si tienes un proceso simple que itera a través de "10,000 artículos", si el servidor deja de funcionar en el artículo 9,999, cuando vuelve a aparecer puedes verlo simplemente comenzando de nuevo en el ítem 1. Todo es factible, solo una advertencia que debes tener en cuenta de.

Otra forma de hacer un fondo de algo es que puede usar una cola JMS. Coloque un mensaje en la cola y el controlador se ejecuta de forma sincrónica desde el resto de la aplicación.

La parte inteligente aquí, y algo que también he hecho aprovechando el trabajo con el Timer Bean, es que puede controlar cuántos "trabajos" se ejecutarán según la cantidad de instancias de MDB que configure el sistema.

Por lo tanto, para la tarea específica de ejecutar un proceso en múltiples partes paralelas, tomo la tarea, la divido en "pedazos" y luego envío cada pieza a Message Queue, donde los ejecutan los MDB. Si permití 10 instancias del MDB, puedo tener 10 "partes" de cualquier tarea ejecutándose simultáneamente.

Esto realmente funciona sorprendentemente bien. Hay un poco de sobrecarga dividiendo el proceso y enrutando a través de la cola JMS, pero eso es básicamente "tiempo de inicio". Una vez que se pone en marcha, obtienes un beneficio real.

Otra ventaja del uso de Message Queue es que puede ejecutar sus procesos de ejecución larga en una máquina separada, o puede crear fácilmente un clúster de máquinas para manejar estos procesos. Sin embargo, la interfaz es la misma y el código no conoce la diferencia.

Descubrí que una vez que ha relegado a un segundo plano el proceso, puede pagar el precio de tener un acceso menos instantáneo a ese proceso. Es decir, no hay ninguna razón para supervisar directamente las clases de ejecución directamente, solo pídales que publiquen información y estadísticas interesantes a la base de datos, o JMX, o lo que sea, en lugar de tener algo que pueda supervisar el objeto directamente porque comparte el mismo espacio de memoria.

que era fácilmente capaz de establecer un marco que permite ejecución de la tarea, ya sea en el temporizador EJB o en la cola de dispersión de los BMD, las tareas son las mismas, y pude controlar su progreso, detenerlos, etc.

Puede combinar la técnica de dispersión para crear varios trabajos EJB Timer. Una de las ventajas gratuitas del MDB es que actúa como un grupo de subprocesos que puede regular sus trabajos (para que no sature repentinamente su sistema con demasiados procesos de fondo). Obtienes esto "gratis" simplemente aprovechando las funciones de administración de EJB en el contenedor.

Finalmente, Java EE 6 tiene un nuevo calificador "asincrónico" (o algo) para los métodos Session Bean. No conozco los detalles sobre cómo funciona esto, ya que aún tengo que jugar con un nuevo contenedor Java EE 6. Pero imagino que probablemente no querrás cambiar los contenedores solo por esta instalación.

2

Regreso al futuro: Java EE 7 tiene mucho más soporte de simultaneidad a través de ManagedThreadFactory, ManagedExecutor service etc (JSR 236: Concurrency Utilities para Java EE) con el que puede crear sus propios 'managed'Threads. Ya no es un tabú en EE como el apoyo a ella (? JBoss) a través de la usining ManagedThread * API

Más detalles

https://jcp.org/aboutJava/communityprocess/ec-public/materials/2013-01-1516/JSR236-EC-F2F-Jan2013.pdf http://docs.oracle.com/javaee/7/tutorial/doc/concurrency-utilities002.htm

+0

Al final, cuando necesitaba trabajar con JBoss AS 7.1 y enfrentar la tarea de ejecución paralela sin hilos, seguí automáticamente la arquitectura basada en mensajes que contenía una tarea maestra dividida en subtareas; utilizando Jboss y HorneQ clustering y balanceo de carga; publicado en GitHub el marco –

+0

JBoss AS 7.1 ya implementa la especificación EJB 3.1. Puede usar la invocación de método asincrónico para casos de uso simples. No olvide configurar el grupo de subprocesos en el servidor de aplicaciones para que se ajuste a sus necesidades. – JanM

Cuestiones relacionadas