Pregunta

Estoy iniciando un proyecto Java EE que debe ser altamente escalable.Hasta ahora, el concepto era:

  • Varios Message Driven Beans, responsables de diferentes partes de la arquitectura.
  • Cada MDB tiene un Session Bean inyectado, manejando la lógica de negocios.
  • un par de Entity Beans, que proporcionan acceso a la capa de persistencia
  • Comunicación entre las diferentes partes de la arquitectura mediante el concepto Solicitud/Respuesta mediante mensajes JMS:
    • MDB recibe un mensaje que contiene una solicitud de actividad
    • utiliza su bean de sesión para ejecutar la lógica empresarial necesaria
    • devuelve el objeto de respuesta en mensaje al solicitante original

La idea era que al desacoplar partes de la arquitectura entre sí a través del bus de mensajes, la escalabilidad no tenía límites.Simplemente inicie más componentes; siempre que estén conectados al mismo bus, podemos crecer y crecer.

Desafortunadamente, estamos teniendo grandes problemas con el concepto de solicitud-respuesta.La gestión de transacciones parece interponerse en nuestro camino.¿Parece que se supone que los beans de sesión no consumen mensajes?

Lectura http://blogs.oracle.com/fkieviet/entry/request_reply_from_an_ejb y http://forums.sun.com/message.jspa?messageID=10338789, tengo la sensación de que la gente realmente recomienda contra el concepto de solicitud/respuesta para EJB.

Si ese es el caso, ¿cómo hacer ¿Se comunica entre sus EJB?(Recuerde, lo que busco es escalabilidad)

Detalles de mi configuración actual:

  • MDB 1 'TestController', utiliza SLSB 1 'TestService' (local) para la lógica empresarial
  • TestController.onMessage() hace que TestService envíe un mensaje a la cola XYZ y solicita una respuesta
    • TestService utiliza transacciones administradas por Bean
    • TestService establece una conexión y sesión con el corredor JMS a través de una fábrica de conexiones conjunta durante la inicialización (@PostConstruct)
    • TestService confirma la transacción después del envío, luego comienza otra transacción y espera 10 segundos para recibir la respuesta.
  • El mensaje llega a MDB 2 'LocationController', que utiliza SLSB 2 (local) 'LocationService' para la lógica empresarial
  • LocationController.onMessage() hace que LocationService envíe un mensaje atrás a la cola JMSReplyTo solicitada
    • Mismo concepto BMT, mismo concepto @PostConstruct
  • todos usan la misma fábrica de conexiones para acceder al corredor

Problema:El primer mensaje se envía (por SLSB 1) y se recibe (por MDB 2) correctamente.El envío del mensaje de retorno (por SLSB 2) también está bien.Sin embargo, SLSB 1 nunca recibe nada - simplemente se agota el tiempo.

Lo intenté sin el selector de mensajes, no hubo cambios y todavía no recibí ningún mensaje.

¿No está bien consumir mensajes mediante un bean de sesión?

SLSB 1-TestService.java

@Resource(name = "jms/mvs.MVSControllerFactory")
private javax.jms.ConnectionFactory connectionFactory;

@PostConstruct
public void initialize() {
    try {
      jmsConnection = connectionFactory.createConnection();
      session = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
      System.out.println("Connection to JMS Provider established");
    } catch (Exception e) { }
}

public Serializable sendMessageWithResponse(Destination reqDest, Destination respDest, Serializable request) {
    Serializable response = null;

    try {
        utx.begin();
        Random rand = new Random();
        String correlationId = rand.nextLong() + "-" + (new Date()).getTime();

        // prepare the sending message object
        ObjectMessage reqMsg = session.createObjectMessage();
        reqMsg.setObject(request);
        reqMsg.setJMSReplyTo(respDest);
        reqMsg.setJMSCorrelationID(correlationId);

        // prepare the publishers and subscribers
        MessageProducer producer = session.createProducer(reqDest);

        // send the message
        producer.send(reqMsg);
        System.out.println("Request Message has been sent!");
        utx.commit();

        // need to start second transaction, otherwise the first msg never gets sent
        utx.begin();
        MessageConsumer consumer = session.createConsumer(respDest, "JMSCorrelationID = '" + correlationId + "'");
        jmsConnection.start();
        ObjectMessage respMsg = (ObjectMessage) consumer.receive(10000L);
        utx.commit();

        if (respMsg != null) {
            response = respMsg.getObject();
            System.out.println("Response Message has been received!");
        } else {
            // timeout waiting for response
            System.out.println("Timeout waiting for response!");
        }

    } catch (Exception e) { }

    return response;
}

SLSB 2 - LocationService.Java (solo el método de respuesta, el resto es el mismo que el anterior)

public boolean reply(Message origMsg, Serializable o) {
    boolean rc = false;

    try {
        // check if we have necessary correlationID and replyTo destination
        if (!origMsg.getJMSCorrelationID().equals("") && (origMsg.getJMSReplyTo() != null)) {
            // prepare the payload
            utx.begin();
            ObjectMessage msg = session.createObjectMessage();
            msg.setObject(o);

            // make it a response
            msg.setJMSCorrelationID(origMsg.getJMSCorrelationID());
            Destination dest = origMsg.getJMSReplyTo();

            // send it
            MessageProducer producer = session.createProducer(dest);
            producer.send(msg);
            producer.close();
            System.out.println("Reply Message has been sent");
            utx.commit();

            rc = true;
        }

    } catch (Exception e) {}

    return rc;
}

recursos-sol.xml

<admin-object-resource enabled="true" jndi-name="jms/mvs.LocationControllerRequest"  res-type="javax.jms.Queue"  res-adapter="jmsra">
    <property name="Name" value="mvs.LocationControllerRequestQueue"/>
</admin-object-resource>
<admin-object-resource enabled="true" jndi-name="jms/mvs.LocationControllerResponse"  res-type="javax.jms.Queue"  res-adapter="jmsra">
    <property name="Name" value="mvs.LocationControllerResponseQueue"/>
</admin-object-resource>

<connector-connection-pool name="jms/mvs.MVSControllerFactoryPool"  connection-definition-name="javax.jms.QueueConnectionFactory"  resource-adapter-name="jmsra"/>
<connector-resource enabled="true" jndi-name="jms/mvs.MVSControllerFactory" pool-name="jms/mvs.MVSControllerFactoryPool"  />
¿Fue útil?

Solución

La solicitud / patrón responder, incluso si se utiliza JMS, sigue siendo sincrónica en esencia. La persona que llama envía un mensaje y, a continuación, espera por la respuesta. Esto no sólo es complicado debido a las transacciones distribuidas, pero también significa que mientras espera por la respuesta, uno o varios recursos (el hilo al menos en este caso) se asigna y se desperdicia. No se puede escalar esta manera:. Que está inherentemente limitado por el número de hilos

Para tener una arquitectura realmente escalable JMS todo debe ser asíncrono . En otros términos: nunca se debe esperar. El mensaje enviado y recibir debe pasar la información necesaria para desencadenar la siguiente actividad.

Si el tamaño del mensaje sería demasiado grande, puede almacenar sólo un identificador y almacenar los datos correspondientes en una base de datos. Pero entonces se convierte en la base de datos de nuevo un punto de contención.

Si los diferentes mensajes necesitan saber en qué proceso de larga ejecución que participan, también se puede utilizar identificadores de correlación . Cuando se recibe un mensaje, el recibir puede "reanudar" la actividad de larga duración utilizando el identificador de correlación. Eso es un patrón tradicional con BPEL. La principal diferencia entre síncrono de petición / respuesta y el mensaje asíncrono con identificador de correlación es que los recursos pueden ser liberados entre cada paso. Puede escalar la tarde, pero no con el primero.

Para ser honesto, yo estaba confundido con su puesto de largo y no entendía si su diseño era bastante asíncrono (y correcta) o sincrónica con la petición / respuesta (y problemática). Pero espero que he proporcionado algún elemento de respuesta.

En cualquier caso, ir a visitar el sitio web patrones de integración empresarial , es una valiosa fuente de información.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top