How do I distribute JMS Listener Connections to ActiveMQ Network of Brokers using Spring Boot JMS? - spring

Our JMS Listener application connects to an ActiveMQ network of brokers through a load balancer, which we are told distributes connections amongst brokers in a round-robin fashion. Our spring boot application is creating a connection via the load balancer, which in turn feeds the connection to one of the brokers amongst the network of brokers. If a message is published to the brokers then it would be a lot quicker if the message was on the broker that the JMS listener connection lived on. However, the likelihood of that occurring is slim unless we can distribute the connections across the brokers.
I've tried increasing the concurrency in the DefaultJmsListenerContainerFactory, but that didn't do the trick. I was thinking about somehow extending the AbstractJmsListenerContainerFactory, and somehow create a Map of DefaultMessageListenerContainer instances but it looks like the createListenerContainer will only return an instance of whatever is parameterized in the AbstractJmsListenerContainerFactory and we cannot parameterize it with an instance of Map.
We are using Spring Boot 1.5.14.RELEASE.
== UPDATE ==
I've been playing around with the classes above, and it seems like it is inherent in Spring JMS that a Jms Listener be associated with a Single Message Listener Container, which in turn is associated with a single (potentially shared) connection.
For any folks that have JMS Application Listeners that are connecting to a load balanced network of brokers, are you creating a single connection that is connecting to a single broker, and if so, do you experience significant performance degradation as a result of the network of brokers having to move any inbound messages to a broker with consumers?

Related

Avoid multiple listens to ActiveMQ topic with Spring Boot microservice instances

We have configured our ActiveMQ message broker as a Spring Boot project and there's another Spring Boot application (let's call it service-A) that has a listener configured to listen to some topics using #JmsListener annotation. It's a Spring Cloud microservice appilcation.
The problem:
It is possible that service-A can have multiple instances running.
If we have 2 instances running, then any message coming on topic gets listened to twice.
How can we avoid every instance listening to the topic?
We want to make sure that the topic is listened to only once no matte the number of service-A instances.
Is it possible to run the microservice in a cluster mode or something similar? I also checked out ActiveMQ virtual destinations but not too sure if that's the solution to the problem.
We have also thought of an approach where we can decide who's the leader node from the multiple instances, but that's the last resort and we are looking for a cleaner approach.
Any useful pointers, references are welcome.
What you really want is a shared topic subscription which was added in JMS 2. Unfortunately ActiveMQ 5.x doesn't support JMS 2. However, ActiveMQ Artemis does.
ActiveMQ Artemis is the next generation broker from ActiveMQ. It supports most of the same features as ActiveMQ 5.x (including full support for OpenWire clients) as well as many other features that 5.x doesn't support (e.g. JMS 2, shared-nothing high-availability using replication, last-value queues, ring queues, metrics plugins for integration with tools like Prometheus, duplicate message detection, etc.). Furthermore, ActiveMQ Artemis is built on a high-performance, non-blocking core which means scalability is much better as well.

Wildfly JMS server master and slave behavior

I'm looking for the easiest way to build a Wildfly cluster with JMS load balancing for a development platform. Messages will be produced by the Wildfly servers themselves.
I wonder how works the ActiveMQ Artemis JMS server embedded in Wildfly in a cluster deployment. I see on this site that a Wildfly node can declare its JMS server as master or slave.
I also read here that a MDB can use an "in-vm-connector" connector.
I'm not sure that I understand how a JMS cluster works with a master and a slave JMS server with "in-vm-connector". Will the MDB instances in the Wildfly node with the slave JMS server receive messages? Will the JMS cluster provide load balancing or will there be only one active JMS server at the same time?
In ActiveMQ Artemis (i.e. the JMS broker embedded into WildFly) clustering (which provides things like message load balancing) and high-availability (which provides redundancy for the integrity of the message data) are separate concepts. The master/slave configuration you mentioned is for high-availability. This configuration doesn't provide message load balancing since only one of the brokers is alive at any given point in time.
If you want configure a master/slave pair it's recommended that you separate those servers from the servers that actually process the messages since it doesn't make sense to have MDBs running on a server which doesn't have a live broker (i.e. a slave) since they won't receive any messages.

Spring JMS messaging with JmsListener - how it scales?

I'm trying to use Spring JMS messaging with #JmsListener in a scalable way, but I'm not seeing it happening. I have a ConnectionFactory bean that returns a factory that connects to an Oracle Advanced Queue through JMS and a database DataSource pool.
The problem starts as every #JmsListener receiver connects again to JMS (and hence to the database pool). My understand is that I can have many #JmsListener methods, one for each service, but in this way it's doing I'm very limited.
The shared connection is turned on, but since each #JmsListener creates a different DefaultMessageListenerContainer, each one have a database connection.
If I also want the services to handle messages concurrently and set container.setConcurrency("3-5"), then it opens 3 * numberOfListeners connections.
If I use container.setCacheLevel(DefaultMessageListenerContainer.CACHE_NONE) then from each second every listener container connects and disconnects from the JMS/database.
I want something that connects one time (or more, if there is concurrent jobs to process) to JMS/database, not to connect count-of-listener times nor to connect-disconnect at each second for every listener.
You can use a SingleConnectionFactory to wrap the vendor factory and all containers will use the same connection.

How does a JMS consumer work on a broker CLUSTER of Oracle Message Queue?

We have an application running in a GlassFish 3.1.2.2 cluster (two instances) that writes its results to "the_output_queue".
GlassFish sets up Message Queue as an embedded broker cluster, which in turn has also two message broker instances corresponding directly to the two GlassFish instances.
Now I would like to consume results from the_output_queue with an external JMS client (think Android app).
I assumed that a broker cluster can somehow be accessed transparently by a JMS client, but I cannot get this to work. I only succeed in connecting a JMS client to one individual broker.
If I have one JMS client running, connected to one broker I get only half of the messages. The physical queue (the_output_queue) defined in the GlassFish Administration Console exists in both brokers and the messages get evenly distributed thanks to load balancing.
This text from the Oracle manuals sounds to me like every message should be available in all broker instances of the cluster, i.e. if only a single JMS consumer is running it should receive all messages irrespective of the broker instance it is connected to.
"The home broker is responsible for routing and delivering the messages to all consumers of the destination, whether these consumers are local (connected to the home broker) or remote (connected to other brokers in the cluster)."
Have I misunderstood this completely?
Can a JMS client access a Oracle Message Queue broker cluster transparently?
How would the connection string look?
Is there some "global cluster target" (instead of an individual broker) to which the JMS client can connect? Where could I find the connection details for the cluster?
Is there something special in the GlassFish setup I have to verify? The settings currently are (default setup created by jelastic.com, looks good to me):
JMS Availability:
JMS Service Type: Embedded
JMS Cluster Type: Conventional
JMS Configuration Store Type: Master Broker
JMS Message Store Type: File
GMS is enabled
Answer to the main question: Yes, a JMS client can connect to any instance of a cluster and GlassFish will replicate the messages. I have tested it on my PC.
The problem in Jelastic is discussed in this posting.

Spring JMS: Creating multiple connection to a queue

To process a large number of messages coming to a queue i need guarantee of at least one jms connection to be there at any time. I am using spring and spring allows to have multiple sessions on a single connection only. In case one and only connection fails, application will come to standstill till spring reconnects to the JMS bridge.
So how can i create more than one connection to a queue in Spring, also how can i do connection pooling here.
The answer to this depends on whether you are using Spring inside a J2EE container(jboss etc.) or in a standalone application.
Standalone - you'll find pooling connections to be a problem. Springs SingleConnectionFactory can be setup to renew the connection on an exception garaunteeing that at some point a connection will come online and start processing the queue again, but you'll still have the problem of waiting for that single connection to renew, plus depending on what messaging implementation your dealing with and how it does load balancing you may find yourself stuck with a connection to a single node in a cluster.
If you are running in a container you can rely on the containers connection factory which will be much more robust. JBoss Messaging in the container for instance will failover seamlessly to other nodes and handles pooling under the covers, but if your working in the container its usually easier to bail on JMS template which kind of sucks and use whatever that container provides.

Resources