2 Replies Latest reply on Feb 29, 2012 2:55 AM by Billy Sjöberg

    Still unclear of which provider/connectionfactory to use with Hornet/ESB combo

    Billy Sjöberg Newbie

      Hi guys,

       

      I've scoured the net trying to come to senses with how to setup a best-practice transactional JMS routing system using the ESB.

      In my current project I'm only using local JMS (local Hornet in AS 6.1 Final), but I can't find any good explanation on the different types of transaction settings.

       

      I.e. Hornet comes by default bundled with 2 separate connection factories:

       

      ConnectionFactory

      XAConnectionFactory

       

      The appserver (6.1) also has a JCA adaptor ConnectionFactory, wrapping either of the two above

      java:/JmsXA

       

      Now, if I read what the HornetQ guys tells me I should always use the JCA adaptor internally as the other ones are for external usage, meaning as an external JMS broker. Is this correct?

      I have laborated a bit with transactional rollbacks and found that the only way I can guarantee a rollback is by using the esb jms-jca-provider, not the regular jms-provider.

       

      However....

       

      * You can specify transactions in multiple places in the jboss-esb.xml file. The ones I've found yet are both on the jms-jca-provider element as well as for your jms-message-filters inside your bus. How does these correlate?

       

      * Also, do I really need the jms-jca-provider if I'm only interested in local transactions? My local jms impl is the only transaction participant so it seems a bit heavy to start an XA transaction when a local one would do. I've had clients that seen performance problems with regards to XA during heavy load.

       

      * Which one of the ConnectionFactories should I actually use for my usecase? And which provider type? And with which transactional setting? As mentioned my use case is to only guarantee message delivery without any DB participants etc.

       

      Best regards

       

      /Billy

       

      As of now, my ESB files looks something like this (with added actions of course):

       

      <providers>

              <jms-jca-provider adapter="jms-ra.rar"

                                connection-factory="/ConnectionFactory"

                                jndi-context-factory="org.jnp.interfaces.NamingContextFactory" name="HornetQ"

                                transacted="true">

                  <property name="jcaActivationMapper" value="org.jboss.soa.esb.listeners.jca.JBossActivationMapper"/>

                  <jms-bus busid="esb_jms_gateway">

                      <jms-message-filter dest-name="queue/in.gw"

                                          dest-type="QUEUE" transacted="true"/>

                  </jms-bus>

                  <jms-bus busid="esb_jms_master_bus">

                      <jms-message-filter dest-name="queue/in"

                                          dest-type="QUEUE" transacted="true"/>

                  </jms-bus>

                  <activation-config>

                      <property name="useJNDI" value="true" />

                      <property name="dLQMaxResent" value="1"/>

                  </activation-config>

              </jms-jca-provider>

          </providers>

          <services>

              <service category="TEST" name="local-transaction-test" description="">

                  <listeners>

                      <jms-listener busidref="esb_jms_gateway" is-gateway="true"

                                    name="gwListener"/>

                      <jms-listener busidref="esb_jms_master_bus" is-gateway="false"

                                    name="internalListener"/>

                  </listeners>

                  <actions mep="OneWay" webservice="false">

       

                      <action name="debug-incoming" class="org.jboss.soa.esb.actions.SystemPrintln">

                          <property name="printfull" value="false"/>

                          <property name="message" value="Received message"/>

                      </action>

       

                      <action name="threadSleep" class="org.rl.esb.ThreadSleeper"/>

       

                      <action name="debug-outgoing" class="org.jboss.soa.esb.actions.SystemPrintln">

                          <property name="printfull" value="false"/>

                          <property name="message" value="About to send message"/>

                      </action>

       

                      <action class="org.jboss.soa.esb.actions.routing.JMSRouter" name="routeToJms">

                          <property name="jndiName" value="queue/out"/>

                          <property name="persistent" value="true"/>

                          <property name="unwrap" value="true"/>

                      </action>

                  </actions>

              </service>

          </services>

        • 1. Re: Still unclear of which provider/connectionfactory to use with Hornet/ESB combo
          Billy Sjöberg Newbie

          I finally had time to do some digging in this issue and think I've got it all sorted out now.

          I started creating a request/reply test using JMeter and sampled 20 threads sending a total of 5000 persistent messages on the ESB Gateway queue. The service has 2 listeners, one GW and one ESB-aware. The service is just forwarding the incoming messages to an outbound queue using the org.jboss.soa.esb.actions.routing.JMSRouter router.

           

          If my reasoning is wrong, please correct me. Otherwise I'll just write it down here to benefit others and to have a reference for the future:

           

          1) Selecting between jms-provider and jms-jca-provider

          It's obvious the jms-provider is the fastest one for the simple reason that it does not introduce transactions. Forcing a server shutdown while having in-flight messages caused message loss.

          The jms-jca-provider however first seemed to always create an XA transaction and was therefore very slow in my tests.

           

          2) Selecting connectionfactory

          As I described in the previous post there are quite a few connectionfactories bundled with HornetQ. Simply put, you should use the java:/ConnectionFactory as that is in-memory and had a better performance.

           

          3) Transactional settings

          Choosing the jms-jca-provider left me with trying to force the ESB to only use local transactions. Seems that the key was to set transactions=false on the provider, but having transactions turned on for the jms buses. This setup did provide rollback capability after server crashes while at the same time was quite substantially faster than having both transactions turned on.

           

          4) Whether to explicitly set QCF on JMS router action

          I found that when you're routing between the same message provider you should not set the qcf jndi reference on outgoing jms actions. That took a bit longer (possibly due to an extra jndi call?).

           

          So, with that said "my" optimal configuration for a local transactional jms-provider seems to be:

           

                  <jms-jca-provider name="HornetQ"

                                    adapter="jms-ra.rar"

                                    connection-factory="java:/ConnectionFactory"

                                    jndi-context-factory="org.jnp.interfaces.NamingContextFactory"

                                    transacted="false">

                      <property name="jcaActivationMapper" value="org.jboss.soa.esb.listeners.jca.JBossActivationMapper"/>

                      <jms-bus busid="esb_jms_gateway">

                          <jms-message-filter dest-name="queue/in.gw"

                                              dest-type="QUEUE" transacted="true"/>

                      </jms-bus>

                      <jms-bus busid="esb_jms_master_bus">

                          <jms-message-filter dest-name="queue/in"

                                              dest-type="QUEUE" transacted="true"/>

                      </jms-bus>

                      <activation-config>

                          <property name="useJNDI" value="true" />

                          <property name="dLQMaxResent" value="1"/>

                      </activation-config>

                  </jms-jca-provider>

          • 2. Re: Still unclear of which provider/connectionfactory to use with Hornet/ESB combo
            Billy Sjöberg Newbie

            I actually dwelled a bit more on this and think I found the solution.

             

            HornetQ has the activation property useLocalTx which forces Hornet to not enable XA. I found that this increased performance substantially while being recoverable.

            Strange thing is that I have to set transacted=false everywhere, otherwise I get uncommited transactions. My rough guess is that the ESB expects an XA transaction to be in flight if transacted is set to true and has problem commiting it.

             

            <jms-jca-provider name="HornetQ"
                                      adapter="jms-ra.rar"
                                      connection-factory="java:/ConnectionFactory"
                                      jndi-context-factory="org.jnp.interfaces.NamingContextFactory"
                                      transacted="false">
                        <property name="jcaActivationMapper" value="org.jboss.soa.esb.listeners.jca.JBossActivationMapper"/>
                        <jms-bus busid="esb_jms_gateway">
                            <jms-message-filter dest-name="queue/in.gw"
                                                dest-type="QUEUE" transacted="false"/>
                        </jms-bus>
                        <jms-bus busid="esb_jms_master_bus">
                            <jms-message-filter dest-name="queue/in"
                                                dest-type="QUEUE" transacted="false"/>
                        </jms-bus>
                        <activation-config>
                            <property name="useJNDI" value="true" />
                            <property name="useLocalTx" value="true"/>
                            <property name="dLQMaxResent" value="1"/>
                        </activation-config>
               </jms-jca-provider>