Domanda

Sto avviando un progetto Java EE che deve essere fortemente scalabile.Finora il concetto era:

  • diversi Message Driven Bean, responsabili di diverse parti dell'architettura
  • a ogni MDB è stato inserito un Session Bean, che gestisce la logica aziendale
  • un paio di Entity Beans, che forniscono l'accesso allo strato di persistenza
  • comunicazione tra le diverse parti dell'architettura tramite il concetto di Richiesta/Risposta tramite messaggi JMS:
    • MDB riceve un messaggio contenente la richiesta di attività
    • utilizza il proprio bean di sessione per eseguire la logica aziendale necessaria
    • restituisce l'oggetto di risposta nel messaggio al richiedente originale

L'idea era che disaccoppiando le parti dell'architettura le une dalle altre tramite il bus dei messaggi, non vi fosse alcun limite alla scalabilità.Basta avviare più componenti: finché sono collegati allo stesso bus, possiamo crescere e crescere.

Sfortunatamente, stiamo riscontrando enormi problemi con il concetto di richiesta-risposta.La gestione delle transazioni sembra essere molto d'intralcio.Sembra che i bean di sessione non dovrebbero consumare messaggi?!

Lettura http://blogs.oracle.com/fkieviet/entry/request_reply_from_an_ejb E http://forums.sun.com/message.jspa?messageID=10338789, ho la sensazione che le persone lo consiglino davvero contro il concetto di richiesta/risposta per gli EJB.

Se è così, come Fare comunichi tra i tuoi EJB?(Ricorda, la scalabilità è ciò che cerco)

Dettagli della mia configurazione attuale:

  • MDB 1 'TestController', utilizza (locale) SLSB 1 'TestService' per la logica aziendale
  • TestController.onMessage() fa sì che TestService invii un messaggio alla coda XYZ e richieda una risposta
    • TestService utilizza transazioni gestite da Bean
    • TestService stabilisce una connessione e una sessione al broker JMS tramite una factory di connessione congiunta al momento dell'inizializzazione (@PostConstruct)
    • TestService conferma la transazione dopo l'invio, quindi inizia un'altra transazione e attende 10 secondi per la risposta
  • Il messaggio arriva all'MDB 2 "LocationController", che utilizza SLSB 2 "LocationService" (locale) per la logica aziendale
  • LocationController.onMessage() fa sì che LocationService invii un messaggio Indietro alla coda JMSReplyTo richiesta
    • Stesso concetto BMT, stesso concetto @PostConstruct
  • tutti utilizzano la stessa factory di connessione per accedere al broker

Problema:Il primo messaggio viene inviato (da SLSB 1) e ricevuto (da MDB 2) ok.Anche l'invio del messaggio di ritorno (tramite SLSB 2) va bene.Tuttavia, SLSB 1 non riceve mai nulla - è semplicemente scaduto.

Ho provato senza il messageSelector, nessuna modifica, ancora nessun messaggio ricevuto.

Non è corretto consumare il messaggio tramite un bean di sessione?

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 il metodo di risposta, il resto è lo stesso di sopra)

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;
}

risorse-sole.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"  />
È stato utile?

Soluzione

Il modello di richiesta/risposta, anche se si utilizza JMS, è ancora sincrono in sostanza.Il chiamante invia un messaggio e quindi attende la risposta.Ciò non solo è complicato a causa delle transazioni distribuite, ma significa anche che durante l'attesa della risposta, una o più risorse (il thread almeno in questo caso) vengono allocate e sprecate.Non puoi ridimensionare in questo modo:sei intrinsecamente limitato dal numero di thread.

Per avere un'architettura JMS veramente scalabile tutto deve essere asincrono.In altri termini:non dovresti mai aspettare.Il messaggio inviato e ricevuto dovrebbe trasmettere le informazioni necessarie per attivare l'attività successiva.

Se la dimensione del messaggio fosse troppo grande, è possibile memorizzare solo un identificatore e archiviare i dati corrispondenti in un database.Ma poi il database diventa nuovamente un punto di contesa.

Se diversi messaggi necessitano di sapere a quale processo di lunga durata partecipano, è anche possibile utilizzare identificatori di correlazione.Quando viene ricevuto un messaggio, la ricezione può "riprendere" l'attività di lunga durata utilizzando l'identificatore di correlazione.Questo è uno schema tradizionale con BPEL.La differenza principale tra richiesta/risposta sincrona e messaggio asincrono con identificatore di correlazione è che le risorse possono essere liberate tra ogni passaggio.Puoi scalare con il successivo, ma non con il primo.

Ad essere sincero, ero confuso con il tuo lungo post e non ho capito se il tuo design fosse piuttosto asincrono (e corretto) o sincrono con richiesta/risposta (e problematico).Ma spero di aver fornito qualche elemento di risposta.

In ogni caso andate a visitare il sito Modelli di integrazione aziendale, è una preziosa fonte di informazioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top