Spring JMS Connections: performance considerations - performance

I have the need to send/receive messages towards/from different topics stored on a single JMS Server.
I would like to use JmsTemplate for sending and MessageListenerContainer for registering asyncronous listeners.
My configuration looks like this:
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">xxx</prop>
<prop key="java.naming.provider.url">yyy</prop>
</props>
</property>
</bean>
<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref ="jndiTemplate"/>
<property name="jndiName" value="TopicConnectionFactory"/>
</bean>
<bean id="singleConnectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<constructor-arg ref="connectionFactory"/>
</bean>
<bean id="tosJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="singleConnectionFactory"/>
<property name="destinationResolver" ref="destinationResolver"/>
<property name="pubSubDomain" value="true"/>
</bean>
As far as I understood, the singleConnectionFactory, returning always the same connection instance, helps reducing the overhead of creating and closing
a connection each time a jmsTemplate needs (for example) to send/receive a message (as it would be when using a normal ConnectionFactory).
My first question is: if I create multiple jmsTemplate(s), can they all share a ref to a singleConnectionFactory? Or do they have to receive a distinct instance each (singleConnectionFactory1, singleConnectionFactory2, etc)?
Reading the API for SingleConnectionFactory, I found this:
Note that Spring's message listener containers support the use of a shared Connection
within each listener container instance. Using SingleConnectionFactory in combination only really makes sense for sharing a single JMS Connection across multiple listener containers.
This sound a bit cryptic to me. As far as I know, it is possible to register only 1 Listener per MessageListenerContainer, so I don't understand to what extent is a connection shared.
Suppose I want to register N Listeners: I will need to repeat N times something like this:
<bean
class="org.springframework.jms.listener.SimpleMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destinationName" value="destX" />
<property name="messageListener" ref="listener1outOfN" />
</bean>
How many Connections are created in such case from connectionFactory? One for each ListenerContainer or just a pool of Connections? And what if I provide the SimpleMessageListenerContainer-s with a ref to singleConnectionFactory?
What is the best approach (from the point of view of the performances, of course) in this case?

if I create multiple jmsTemplate(s), can they all share a ref to a singleConnectionFactory?
Yes, this is fine. The javadoc for SingleConnectionFactory says:
According to the JMS Connection model, this is perfectly thread-safe (in contrast to e.g. JDBC).
JMS Connection objects are thread-safe, and can be used by multiple threads concurrenctly. So there's no need to use multiple SingleConnectionFactory beans.
As far as I know, it is possible to register only 1 Listener per MessageListenerContainer, so I don't understand to what extent is a connection shared.
This is true; however, each MessageListenerContainer can have multiple threads processing messages concurrently, all using the same MessageListener object. The MessageListenerContainer will use a single, shared Connection for all of these threads (unless configured to do otherwise).
Note that Spring's message listener containers support the use of a shared Connection within each listener container instance. Using SingleConnectionFactory in combination only really makes sense for sharing a single JMS Connection across multiple listener containers.
In other words, if all you have is a single MessageListenerContainer, then SingleConnectionFactory is unnecessary, since the single connection is managed internally to MessageListenerContainer. if you have multiple listener containers, and want them all to share a connection, then SingleConnectionFactory is required. Also, if you want to share a connection between listening and sending, as you do, then SingleConnectionFactory is also necessary.

Related

How to create multiple listeners in ActiveMQ using spring JMS

I have a use case where I want to create multiple listeners(6) in an application. I want to subscribe to multiple destinations(6 topics). All the subscription are durable. I am using separate default message listener container(DMLC) for each listener and using different client id but I am confused about how connection factory should be used.
Should I use single ActiveMQ pooled connection factory with maxConnection specified to 6. OR should I use different pooled connection factory for each listener ?
Is there any harm is using pooledConnectionFactory with maxConnection for durable subscriber?
Source code:
Connection Factory:
<bean id="jmsFactory" class="org.apache.activemq.pool.PooledConnectionFactory"
destroy-method="stop">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL">
<value>${jms.broker.url}</value>
</property>
</bean>
</property>
<property name="maxConnections" value="6" />
and my listener is using it as: (I have 6 similar listeners similar to this using different destinations and client ID)
<bean id="listenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer"
<property name="connectionFactory" ref="jmsFactory" />
<property name="destination" ref="topic_pnlCompleteTopic" />
<property name="durableSubscriptionName" value="FAGCompletion" />
<property name="pubSubDomain" value="true" />
<property name="subscriptionDurable" value="${jms.fagsListener.durable}" />
<property name="clientId" value="${jms.fagsListener.clientId}" />
<property name="messageListener" ref="pnlMessageListener" />
<property name="messageSelector" value="JMSType = 'FAG Completion'" />
</bean>
That sounds all fine to me as long as you're not using this connection factory for something else. There is no reason to limit the number of connections to 6, you can put a higher number if you want and it will be only used if necessary. ConnectionFactory is typically the thing that you share for your whole app. See it as a kind of DataSource for JMS access
You listeners will typically only use one session each, since you are using topics. There is no reason to specify a limit on your pool, or to use multiple pools. You typically use one pooled connection factory for your application unless you see a real reason to limit or split it up into different pools.

Publish subscribe implementation with Spring JMS

I have a JMS queue implementation with JmsTemplate. I want to have more than one listener when a message is put in the queue, i.e. I want to use topic instead of queue.
I have configuration without JMS namespacing. What are the changes that need to be made to have multiple listeners listen on a topic when someone sends a message in a topic.
I guess you are probably using DefaultMessageListenerContainer. Just to be sure, you want that several individual components receive the same message (i.e. you don't want to process messages in parallel).
Assuming I got this right and component A and compoent B should receive the same message, you simply create two DefaultMessageListenerContainer instance on the same topic and you set the pubSubDomain property to true. Make sure you haven't set any concurrency on the listener container, or better yet, set the concurrency to 1 to make that explicit.
This would give something like
<bean id="listener1"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="pubSubDomain" value="true"/>
<property name="concurrency" value="1"/>
<property name="destinationName=" value="...."/> <!-- topic name -->
<property name="messageListener" ref="...."/>
</bean>
Then you should create a similar bean for the second component.

Spring + JMS + ActiveMQ without dependency on ActiveMQ

I'm trying to build a MQ producer that sends a message to an ActiveMQ queue. The thing is that I don't want the implementation to be specific for ActiveMQ. I actually am doing the ActiveMQ sending in dev environment, and in production the application server will use something else. I'm planning to use Maven to create 2 profiles that will filter resources based on the given profile.
I started playing with JNDI, but I'm stuck... I tried a lot of options, but none are viable.
For now, my spring config xml is like this:
<jee:jndi-lookup id="mqConnectionFactory" jndi-name="java:comp/env/jms/mqConnectionFactory" />
<bean id="jmsJndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">org.apache.activemq.jndi.ActiveMQInitialContextFactory</prop>
<prop key="java.naming.provider.url">vm://localhost</prop>
</props>
</property>
</bean>
<bean id="ismeJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="defaultDestination" ref="ismeJmsDestination"/>
<property name="connectionFactory" ref="mqConnectionFactory"/>
</bean>
<bean id="ismeJmsDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jmsJndiTemplate"/>
<property name="jndiName" value="dynamicQueues/FOO.BAR"/>
</bean>
mqConnectionFactory cannot be found because I didn't add it in JNDI. I don't know how to add it actually, as this is not a webapp, so no context.xml.
Can someone help me in the right direction?
Whatever broker implementation you chose, you need to have the corresponding client library in your classpath. The JMS API is just an API, you need an actual implementation to connect to the broker of your choice.
Say you want to connect to ActiveMQ in development and to whatever JMS implementation in production. You can isolate those two config in separate profiles and make the activeMQ dependency an optional dependency in Maven.

Synchronous Spring ActiveMQ receiver

My app is a Spring based application. I'm using activemq as a broker. I manage in my app two different queues receiving messages.
For each queue, my app's aim is to listen to messages sent on the broker, then proceed the message (read it, performs database actions from informations coming to this message etc.), and then treat the next message (so the treatment is synchronous, I want to proceed messages in the order of their arrival).
My actual design is this one :
I create a thread
<bean id="pollThread" class="my.app.receiver" init-method="start" destroy-method="interrupt">
</bean>
run() method of the thread call in a while(true) loop a method which does :
This thread create a connection to active mq and block with receive
After receiving, i close the connection and treat the message (database stuff and so)
Treatment done, end of method
and then the treatment restart (listening with receive, treatment etc.)
My question is : is there any manner to design it better ? My only mandatory process is to proceed message in the order of arrival and do the treatment before handling the next message.
I've read a lot of thing about JMSTemplate and so on but i'm lost whith all the information.
Actually my best guess is too create a PooledConnectionFactory (because we will use only ActiveMQ and CachingConnectionFactory seems to have limitations that matters in our architecture) and to limit it to one concurrentConsumer. Then to use the MessageListener interface to proceed my message.
Thanks
You can use the Message Driven POJO infrastructure provided by the Spring framework. It will do the polling on the destination and recover in case of failures of the broker, etc.
You can change your code (say YourMessageListener) to implement MessageListener. Then the following config can get you started
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="messageListener" class="org.foo.YourMessageListener"/>
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://your-server:61616"/>
</bean>
<bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue/yourQueue"/>
</bean>
<bean id="jmsContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destination"/>
<property name="concurrency" value="1"/>
<property name="messageListener" ref="messageListener"/>
</bean>
</beans>
The important setting is the concurrency element which limits the number of threads that are can simultaneously handle messages on that destination. By setting it to one, only one thread consumes a message at a time.
See the documentation for more details

No new consumers on activemq queue after a while

Since a month we have a reoccurring issue with activemq and spring. After a some time (between a day and a week) we have no more consumers and no new ones get started and the queue starts to fill up.
This setup ran for over a year, without any issues and as far as we can see nothing relevant has been changed.
An other queue we use also started to show the same behavior, but less frequent.
from the activemq webconsole ( as you can see lots of pending messages and no consumers)
Name ↑ Number Of Pending Messages Number Of Consumers Messages Enqueued Messages Dequeued Views Operations
queue.readresult 19595 0 40747 76651 Browse Active Consumers
contents of our bundle-context.xml
<!-- JMS -->
<bean id="jmsConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
<property name="maxConnections" value="5" />
<property name="maximumActive" value="5" />
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL">
<value>tcp://localhost:61616</value>
</property>
</bean>
</property>
</bean>
<bean id="ResultMessageConverter" class="com.bla.ResultMessageConverter" />
<jms:listener-container connection-factory="jmsConnectionFactory" destination-resolver="jmsDestinationResolver"
concurrency="2" prefetch="10" acknowledge="auto" cache="none" message-converter="ResultMessageConverter">
<jms:listener destination="queue.readresult" ref="ReaderRequestManager" method="handleReaderResult" />
</jms:listener-container>
There are no exception in any of the logs. Does anyone knows of a reason why after a while no new consumers could be started.
Thanks
I've run into issues before where "consumers stop consuming," but haven't seen consumers stop existing. You may be running out of memory and/or connections in the pool. Do you have to restart ActiveMQ to fix the problem or just your application?
Here are a couple suggestions:
Set the queue prefetch to 0
Add "useKeepAlive=false" on the connection string
Increase the memory limits for the queues
I can see no obvious reason in the config provided why it should fail. So you need to resort to classic trouble shooting.
Try to set logging to debug and recreate the issue. Then you should be able to see more and you might be able to detect the root cause of it.
Also, check out the JMS exception listener and try to attach it your implementation of it to get a grasp of the real problem.
http://docs.oracle.com/javaee/6/api/javax/jms/ExceptionListener.html

Resources