Amey Jadiye opened SPR-13586 and commented

Spring provides classes for jms connection optimisation, however both SingleConnectionFactory and CachingConnectionFactory able to maintain only 1 TCP connection under the hood, Spring should have a PooledConnectionFactory which can pool multiple TCP connection and multiple session/consumer/producers under that, which can be better for throughPut and high load system.


No further details from SPR-13586

Comment From: spring-projects-issues

Juergen Hoeller commented

This is currently not on the roadmap for inclusion in Spring proper, since most JMS providers/drivers and all application servers ship a PooledConnectionFactory variant of their own which is then able to use internal contracts for optimized pool processing, in particular when it comes to managing XA transactions.

The sweet spot for Spring's CachingConnectionFactory is exactly that it reuses a single JMS Connection and that it is based on generic JMS contracts, without any support for XA transactions but full support for native JMS transactions and all JMS acknowledge modes. This is a fine choice for many scenarios, and as far as we know, not provided anywhere else.

Juergen

Comment From: spring-projects-issues

Amey Jadiye commented

CachingConnectionFactory is best what its made for, i wish its functionality could be extended by caching multiple TCP connection, Yes agree many JMS providers provides PooledConnectionFactory but not all, adding pooling multiple conneciton will be a best combination for standalone application which only uses spring and not on JEE servers.

For performance many JMS application are not being deployed on EE servers and choose to have onyl org.springframework.jms.listener.DefaultMessageListenerContainer which is light waight and in this senario i also expect a PooledConnectionFactory which can give a better throughput.

Comment From: spring-projects-issues

Juergen Hoeller commented

Note that DefaultMessageListenerContainer doesn't suggest a pooled ConnectionFactory to begin with, since it internally has to hold on to one shared JMS Connection per listener container and manages the Session instances etc itself. A fully pooled ConnectionFactory doesn't really add any value there, since we'd have to borrow a Connection for the entire lifetime of each DefaultMessageListenerContainer, with the pooling effectively being in vain.

All in all, CachingConnectionFactory (or a fully pooled variant thereof) is primarily designed for JmsTemplate usage or other code that temporarily borrows a JMS Connection.

Juergen

Comment From: spring-projects-issues

Amey Jadiye commented

So in case if 1 jvm process is containing 10 DefaultMessageListenerContainer, creating 10 CachingConnectionFactory one per each doesnt looks like the optimal way, and all time they all are not working may be only 3 are working some times all of them are working, there has to be a shared and pooled connection in this case.

Holding one connection for life time is not so good, also the containers are having diffrent threads and they are running async and may require multiple connection at a time else they will chock on high load ,what do you think ?

In case we set CACHE_NONE = 0 PooledConnectionFactory will be much benifitial rather DefaultMessageListenerContainer manage its own caching, and it will be optimal as well. and yes for JmsTemplate its better option.

Comment From: spring-projects-issues

Juergen Hoeller commented

In fact, I would not recommend a CachingConnectionFactory for use with DefaultMessageListenerContainer at all, and I would not recommend CACHE_NONE either (unless you have to work with an externally provided XA connection pool). A DefaultMessageListenerContainer is most efficient if it internally shares a JMS Connection and caches the Session / @MessageConsumer for each listener invoker. Since with native JMS, in order to be notified of an incoming message, there has to be an actively registered consumer against a session and therefore an underlying connection, it's a lot of internal re-registration effort otherwise - in particular if no new message came in to begin with.

From that perspective, I don't see the benefit of using a pooled connection factory over DefaultMessageListenerContainer's default CACHE_CONSUMER mode. If you're forced to use a pooled connection factory for XA purposes or for application server monitoring, then so be it, but I don't see why you would take that option without such a need.

Which JMS provider are you working with, BTW? Have you seen any concrete runtime indications where DefaultMessageListenerContainer runs into a bottleneck that's caused by its locally managed JMS Connection?

Juergen

Comment From: spring-projects-issues

Amey Jadiye commented

This need a long explaination, let me collection some data/code/benchmarking result and get back to you!

Comment From: spring-projects-issues

Amey Jadiye commented

I did few throughput tests on the CachingConnectionFactory, to check you need 1 mysql server and 1 activemq server for this test https://github.com/ameyjadiye/mq-fury

there are 2 DefaultMessageListenerContainer one is inserting random string in database and sending it to other listener, other listener is getting that message and checking whether its present in database, this test is just to check that always the transaction commit happening for mysql first then jms as well as how many messages are flowing between listeners.

Now here i tested the application with 2 configuration.

Wrapping vender’s ActiveMQConnectionFactory in CachingConnectionFactory

Here I can see that only one TCP connection is getting established with netstat -ap | grep 61616 no matter how many container threads I’m using, with increasing concurrency

Using direct vendors ActiveMQConnectionFactory

This create big chaos as application is establishing lot many connection for each message sending and receiving, which I don’t want, but because of lot of simultaneous connections I can see lot of performance improvement in application

Though this test is made on ActiveMq and activemq may have some vendor specific connection factory, actually in production I’m using solace mq which is not giving any PooledConnectionFactory and all the connections should be managed at application side, again just to remind I am using DefaultMessageListenerContainer directly and not in any Application server.

The solution is to have PooledConnectionfactory which can have many parallel connection but in controlled manner.