java - example - apache artemis
Solicitud-respuesta simultánea sincrónica con JMS/ActiveMQ-¿Patrones/bibliotecas? (5)
Tengo una aplicación web en la que cuando el usuario envía una solicitud, enviamos un mensaje JMS a un servicio remoto y luego esperamos la respuesta. (También hay solicitudes asíncronas, y tenemos varias mejoras configuradas para la reproducción de mensajes, etc., por lo que preferiríamos seguir con JMS en lugar de, por ejemplo, HTTP).
En ¿Cómo debo implementar la respuesta de solicitud con JMS? , ActiveMQ parece desalentar la idea de colas temporales por solicitud o consumidores temporales con selectores en el JMSCorrelationID, debido a la sobrecarga involucrada en su rotación.
Sin embargo, si utilizo los consumidores agrupados para las respuestas, ¿cómo envío del consumidor de respuesta al hilo de solicitud original?
Ciertamente, podría escribir mi propio hilo de retorno seguro de devolución de llamada / envío, pero odio escribir el código que sospecho que ya ha sido escrito por alguien que sabe mejor que yo.
Esa página de ActiveMQ recomienda Lingo , que no se ha actualizado desde 2006, y Camel Spring Remoting , que ha sido descartada por mi equipo por sus muchos errores.
¿Existe una solución mejor, en forma de una biblioteca que implementa este patrón, o en la forma de un patrón diferente para simular la solicitud-respuesta síncrona sobre JMS?
Pregunta de SO relacionada:
- ¿Es una buena práctica usar la cola temporal de JMS para uso sincrónico? , lo que sugiere que aumentar el consumo de un consumidor con un selector en el JMSCorrelationID es realmente bajo, lo que contradice lo que dice la documentación de ActiveMQ. Quien tiene razon
Es una vieja, pero he llegado aquí buscando otra cosa y en realidad sí tengo algunas ideas (con suerte, será útil para alguien).
Hemos implementado casos de uso muy similares con Hazelcast siendo nuestro chasis para la comunicación de los entrenudos de los clústeres. La esencia es 2 conjuntos de datos: 1 mapa distribuido para las respuestas, 1 lista ''local'' de personas que esperan respuesta (en cada nodo en el grupo).
- Cada solicitud (que recibe su propio hilo desde Jetty) crea una entrada en el mapa de los visitantes locales; la entrada tiene obviamente el UID de correlación y un objeto que servirá como un semáforo
- entonces la solicitud se envía al remoto (REST / JMS) y el hilo original comienza a esperar en el semáforo; UID debe ser parte de la solicitud
- remoto devuelve la respuesta y la escribe en el mapa de respuestas con el UID correlacionado
- Se está escuchando el mapa de respuestas; Si el UID de la nueva respuesta se encuentra en el mapa de los buscadores locales, se está notificando su semáforo, se está liberando el hilo de la solicitud original, recogiendo la respuesta del mapa de respuestas y devolviéndola al cliente
Esta es una descripción general, puedo actualizar una respuesta con algunas optimizaciones que tenemos, en caso de que haya algún interés.
Siempre he usado CorrelationID para solicitud / respuesta y nunca he tenido problemas de rendimiento. No puedo imaginar por qué ese sería un problema de rendimiento, debería ser súper rápido para que lo implementara cualquier sistema de mensajería y una característica bastante importante de implementar bien.
http://www.eaipatterns.com/RequestReplyJmsExample.html tiene las soluciones de flujo principal de remolque utilizando replyToQueue o correlationID.
Todavía pensaría en usar Camel y permitiría que maneje el enhebrado, tal vez sin control remoto, pero solo con ProducerTemplates en bruto.
Camel tiene una buena documentación sobre el tema y funciona muy bien con ActiveMQ. http://camel.apache.org/jms#JMS-RequestreplyoverJMS
Para su pregunta acerca de cómo girar un consumidor basado en un selector y la sobrecarga, lo que los documentos de ActiveMQ realmente afirman es que requiere un viaje de ida y vuelta al agente de ActiveMQ, que podría estar en el otro lado del mundo o en una red con alto retardo. La sobrecarga en este caso es el tiempo de ida y vuelta de TCP / IP al agente de AMQ. Consideraría esto como una opción. Lo he utilizado varias veces con éxito.
Un colega sugirió una solución potencial: una cola / consumidor de respuesta por subproceso de aplicación web, y podemos establecer la dirección de retorno a la cola de respuesta que pertenece a ese subproceso en particular. Dado que estos subprocesos suelen ser de larga duración (y se reutilizan para solicitudes web posteriores), solo tenemos que sufrir los gastos generales en el momento en que el conjunto genera el subproceso.
Dicho esto, todo este ejercicio me está haciendo repensar JMS vs HTTP ... :)
En un proyecto anterior tuvimos una situación similar, en la que una solicitud de sincronización de WS se manejó con un par de mensajes JMS requeridos / asincrónicos de Async. Estábamos usando la implementación Jboss JMS en ese momento y los destinations
temporales en los que había una gran sobrecarga.
Terminamos escribiendo un despachador seguro para subprocesos, dejando el WS en espera hasta que recibiera la respuesta de JMS. Usamos el ID de correlación para asignar la respuesta a la solicitud.
Esa solución fue totalmente desarrollada en casa, pero me he encontrado con un bonito mapa de bloqueo que resuelve el problema de hacer coincidir una respuesta con una solicitud.
Si su solución está agrupada, debe cuidar que los mensajes de respuesta se envíen al nodo correcto en la agrupación. No sé ActiveMQ, pero recuerdo que la mensajería de JBoss tuvo algunos problemas técnicos en sus destinos agrupados.