Appendix A. Optimizing Performance of JMS Single- and Multiple-Resource Transactions
Abstract
There are many ways you can optimize the performance of JMS transactions—both single-source transactions that use the resource's internal transaction manager and multiple-resource transactions that use an external XA transaction manager.
Optimization tips for all JMS transactions
These tips apply to both single- and multiple-resource transactions:
- When working with Spring JMS/
camel-jms
, use a pooling-enabled Connection Factory, such as ActiveMQ’sPooledConnectionFactory
, to prevent clients from reopening JMS connections to the broker for each message consumed. - When using
camel-jms
to do local transactions through an external transaction manager, configure the transaction manager to use a pooling-enabled Connection Factory. - ActiveMQ’s
PooledConnectionFactory
eagerly fills the internal connection pool, the size of which is bound by the maxConnections property setting.Each call toPooledConnectionFactory.createConnection()
creates and adds a new connection to the pool until maxConnections is reached, regardless of the number of connections in use. Once maxConnections is reached, the pool hands out only connections it recycles. So different JMS sessions (in different threads) can potentially share the same JMS connection, which the JMS specification specifically allows.NoteThePooledConnectionFactory
also pools JMS sessions, but the session pool behaves differently than the connection pool. The session pool creates new sessions only when there are no free sessions in it. - A
camel-jms
consumer configuration needs only one JMS connection from the connection pool, regardless of the setting of the concurrentConsumers property. As multiple camel routes can share the samePooledConnectionFactory
, you can configure the pool’s maxConnections property equal to the number of Camel routes sharing it.
Optimization tips for JMS XA transactions
These tips apply to multiple-resource transactions only:
- With XA transactions, you must use CACHE_NONE or CACHE_CONNECTION in
camel-jms
or plain Spring JMS configurations. As CACHE_CONSUMER is not supported in these configurations, you need to use a pooling-enabled JMS Connection Factory to avoid opening a new connection for every message consumed. - Configure a
prefetch
of1
on the ActiveMQ ConnectionFactory when not caching JMS consumers to eliminate any overhead generated by eager dispatch of messages to consumers. For example,failover:(tcp://localhost:61616)?jms.prefetchPolicy.all=1
- When working with JMS providers other than ActiveMQ, wrap the 3rd-party JMS drivers in the generic XA-aware JcaPooledConnectionFactory (for details, see Section 6.6, “Generic XA-Aware Connection Pool Library”). For example, to wrap a WebSphereMQ endpoint:
<bean id="FuseWmqXaConnectionFactory" class="org.apache.activemq.jms.pool.JcaPooledConnectionFactory"> <property name="connectionFactory" ref="WMQConnectionFactory"/> <property name="transactionManager" ref="transactionManager"/> <property name="maxConnections" value="5"/> <!-- note we set a unique name for the XA resource" --> <property name="name" value="ibm-wmq" /> </bean> <bean id="WMQConnectionFactory" class="com.ibm.mq.jms.MQXAConnectionFactory"> <property name="hostName" value="localhost" /> <property name="port" value="1414" /> <property name="queueManager" value="QM_VM" /> <property name="channel" value="TEST" /> <property name="transportType" value="1" /> </bean>
The wrapper provides the means for the Aries/Geronimo transaction manager to access and write the name of the participating WebSphereMQ resource to its HOWL recovery log file. This and other information stored in its recovery log file enables Aries to recover any pending transactions after a crash occurs. - Always declare a resource manager for each resource involved in an XA transaction. Without a resource manager, pending XA transactions cannot be recovered after a JBoss Fuse crash, resulting in lost messages.