i created a simple producer consumer simulation based on spring, jms and activemq, i'm trying to reach high performance from both sides, producers and consumers,
Connection settings :
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
<property name="connectionFactory" ref="connectionFactory" />
</bean>
<amq:connectionFactory id="amqConnectionFactory" brokerURL="failover:(tcp://${broker.url}:61616)" />
<bean id="connectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="amqConnectionFactory" />
</bean>
<amq:queue id="queue" physicalName="queue" />
<beans:bean id="jsonMessageConverter" class="XXXXX.converter.JsonMessageConverter" />
Consumer settings :
<jms:listener-container concurrency="10"
acknowledge="auto" prefetch="1" message-converter="jsonMessageConverter" transaction-manager="transactionManager"
>
<jms:listener id="queueListener_1" destination="ooIntegrationQueue"
ref="myMessageListenerAdapter" />
</jms:listener-container>
<beans:bean id="myMessageListenerAdapter"
class="org.springframework.jms.listener.adapter.MessageListenerAdapter" >
<beans:property name="delegate" ref="consumer"/>
</beans:bean>
<beans:bean id="consumer" class="XXX.ConsumerImpl"/>
Producer settings :
<beans:bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="connectionFactory" p:messageConverter-ref="jsonMessageConverter"
p:defaultDestination-ref="ooIntegrationQueue" p:sessionTransacted="true" />
starting with the consumer, i managed to consume about 25 messages per second, which is extremely slow, i discovered the bottleneck to be the fact that i am using transactions, after googling for a bit, and playing with the configs, i found out that after autowiring the DefaultMessageListenerContainer and changing the cachelevel to
listenerContainer.setCacheLevelName("CACHE_SESSION")
my performance increases to about 1500 messages per second while still having transactions.
my problem is now with the producer which is still stuck at about 25 operations per sec, my producer test is simple :
int numOfMessages = getNumberOfMessages();
double startTime = System.currentTimeMillis();
for (int i = 1; i <= numOfMessages; i++) {
jmsTemplate.convertAndSend("HelloWorld" + i);
}
double endTime = System.currentTimeMillis();
double totalTime=(endTime-startTime)/1000;
System.out.println("Time - "+totalTime+" seconds");
System.out.println("EPS - "+numOfMessages/totalTime);
i'm wondering how to reach similiar performances with the producer, since it now bottlenecks the entire system.
What is the default delivery mode for ActiveMQ? is it a persistent queue? if so, how is it configured? how remote is the broker? These answers will determine the basic cost of sending to queue by answering how long it takes the server to ack the send (i.e. network RTT + potential cost of persisting the message to disk synchronously).
The other possibility is that you're actually creating a new connection, session and messageproducer on every send. This is pretty costly to say the least. It will be worth confirming whether this is happening (e.g. add debug logging to spring, check amq admin console for connection churn) or not as a basic sanity check. By the looks of it
CachingConnectionFactory
should cache a single session and messageproducer by default andconvertAndSend
should close the session it obtains after sending which results in a returning that cached session to the pool. This should mean it is relatively quick (spring jms goes through an awful lot of code just to send a message) to get the cached session on the next send.Try to change acknowledge method to from AUTO to CLIENT_ACKNOWLEDGE. For more information look to the Specification.
JMSTemplate does a walk of ConnectionFactiory -> Connection -> Session -> MessageProducer, closing each object after each send. To get around this, wrap your amqConnectionFactory bean with a org.apache.activemq.pool.PooledConnectionFactory, and use that under the template rather than a CachingConnectionFactory.
Sorry if this answer comes to late to help the original poster. I recently investigated
JmsTemplate
performance. Even with the same delivery and acknowledgment modes, nativeJMS
code seemed much faster thanJmsTemplate
. The problem turned out to be thatActiveMQ
normally defaults to async sending, but when you useJmsTemplate
it instead uses sync sending. This dramatically reduces performance. You can setActiveMQConnectionFactory
'suseAsyncSend
property totrue
to force async sending. More details here: JmsTemplate is not evil