ActiveMQ Artemis - Spring Boot Throttling - spring-boot

Set up - ActiveMQ Artemis 2.14.0 and Spring Boot.
Problem statement: I want to achieve throttling in terms of reading / limiting the messages to be read from ActiveMQ.
This can be achieved by configuring the consumerMaxRate during the start time and that works fine too. I want to change this parameter on the fly to increase / decrease the rate of consumption without stopping my application. I have tried by re-initializing the beans, setting the activemqconnectionfactories again but somehow the connection is maintained with the initial value only.
Any suggestion would be helpful.
I have tried searching the documentation but it only says about the parameter but with no examples.

The consumerMaxRate cannot be changed while the connection to the broker is active. You'd need to close the connection, set a new consumerMaxRate, and then create a connection with the new configuration.

Related

Performance issues with ActiveMQ Artemis and Spring JmsTemplate

While doing some load tests with the ActiveMQ Artemis broker and my Spring Boot application I am getting into performance issues.
What I am doing is, sending e.g. 12,000 messages per second to the broker with JMSeter and the application receives them and saves them to a DB. That works fine. But when I extend my application by a filter mechanism, which forwards events after saving to DB, back to the broker using jmsTemplate.send(destination, messageCreator) it goes very slow.
I first used ActiveMQ 5.x and there this mechanism works fine. There you could configure the ActiveMQConnectionFactory with setAsyncSend(true) to tune performance. For the ActiveMQ Artemis ConnectionFactory implementation there is no such a possibility. Is there another way to tune performance like in ActiveMQ 5.x?
I am using Apache ActiveMQ Artemis 2.16.0 (but also tried 2.15.0), artemis-jms-client 2.6.4, and Spring Boot 1.5.16.RELEASE.
The first thing to note is that you need to be very careful when using Spring's JmsTemplate to send messages as it employs a well-known anti-pattern that can really kill performance. It will actually create a new JMS connection, session, and producer for every message it sends. I recommend you use a connection pool like this one which is based on the ActiveMQ 5.x connection pool implementation but now supports JMS 2. For additional details about the danger of using JmsTemplate see the ActiveMQ documentation. This is also discussed in an article from Pivotal (i.e. the "owners" of Spring).
The second point here is that you can tune if persistent JMS messages are sent synchronously or not using the blockOnDurableSend URL property, e.g.:
tcp://localhost:61616?blockOnDurableSend=false
This will ensure that persistent JMS messages are sent asynchronously. This is discussed further in the ActiveMQ Artemis documentation.

How should you handle the retry of sending a JMS message from your application to ActiveMQ if the ActiveMQ server is down?

So using JMS and ActiveMQ, I can be sure that my message sent from my Spring Boot application using JmsTemplate will reach it's destination application even if that destination application is down at the time I send the message to ActiveMQ. As when the destination application starts up, it grabs the message from the queue. Great!
However.
What happens if my Spring Boot application tries to send a JMS message to a queue on the ActiveMQ server, but the ActiveMQ server is down at that point or the network is down and I get a connection refused exception?
What is the recommended way to make sure my application keeps trying to re-sends the message to ActiveMQ until it is successful? Is this something I have to develop into my application myself? Are there any nifty Spring tools or annotations which do this for me? Any advice on best practice or how I should be handling this scenario?
You can try Spring-Retry. Has lots of fine grain controls for it:
http://www.baeldung.com/spring-retry
https://github.com/spring-projects/spring-retry
If it is critical that you don't lose this message, you will want to save it to some alternative persistent store (e.g. filesystem, local mq server) along with whatever retry code you come up with. But for those occasional network glitches or a very temporary mq shutdown/restart, Spring-Retry alone should do the trick.
Couple of approaches I can think of
1. You can set up another ActiveMq as fallback. In your code you don't have to do anything, just change your broker url from
activemq.broker.url=tcp://amq01.blah.blah.com:61616
to
activemq.broker.url=failover:(tcp://amq01.blah.blah.com:61616,tcp://amq02.blah.blah.com:61616)?randomize=false
The rest is automatically taken care of. i.e. when one of them is down, the messages are sent to other.
Another approach is to send to a internal queue (like seda, direct) when activemq is down and read from there.
Adding failover to the url is one appropriate way.
And another reasonable way is to making sure activemq always online , as activemq has the master-slave mode(http://activemq.apache.org/masterslave.html) to get high availability.

Spring JMS - IBM MQ has open input count issue

We are using Spring JMS to connect IBM MQ in that the MQ open input count keep on increase.is there any solution can we reduce the open input count. we are using concurrent connection as 1 only.
The IBM MQ connection handle behaves differently with Spring configuration. If you are using the CachingConnectionFactory that spring provides, please read my answer in the below thread.
JMS connections exhausted using WebSphere MQ
Please add more details to better understand the issue. The Apache camel will dynamically scale up and down the open input counts based on the load. Hope this helps!
That is a clear indication of your code not closing the queue you have opened. Close the consumer(s) you have created.

Is it possible for Spring-XD to listen to more than one JMS broker at a time?

I've managed to get Spring Xd working for a scenario where I have data coming in from one JMS broker.
I potentially am facing a scenario where data ingestion could happen from different sources thereby needing me to connect to different brokers.
Based on my current understanding, I'm not quite sure how to do this as there exists a JMS config file which allows you to setup only one broker.
Is there a workaround to this?
At the moment, you would have to create a separate jms-[provider]-infrastructure-context.xml for each broker (in modules/common), say call the provider activemq2.
Then use --provider=activemq2 in the module definition.
(I recently used this technique to test sonicmq and hornetq providers).

How to control number of messages ActiveMQ is processing asynchronously?

I'm new to ActiveMQ. I'm using it (and Apache Camel) for batch processing that ends up communicating with web services.
My question is how does ActiveMQ control how asynchronous it really is? In other words, if it can process 20 messages at the same time but the bottleneck is the web services on the other end, how can I control that? Can I slow ActiveMQ down?
Thanks!
if you're using apache camel 2.4+, you can use the throttler with camel to control message flow to endpoints - you can change the limit dynamically as of camel 2.8 - hope it helps.
The Camel throttler would be a good solution. It does however keep the messages in memory in the Camel application at the time. However it allows to react precisely.
Another alternative is the throttling in-flight route policy you can configure on the Camel ActiveMQ JMS consumer. That policy can be configured with a upper/lower water mark settings. Then the policy will automatic suspend/resume the AMQ consumer accordingly. You can extend this logic and use your custom metrics instead.
You can read about this policy here: http://camel.apache.org/routepolicy
This approach would then not keep any messages in memory, as it will control on the AMQ consumer side to suspend/resume it to "throttle" the flow.
You could also set a pre-fetch limit, preventing AMQ from dispatching messages on a specific transport to its consumers based on the amount of message_delivered responses it gets back from the client. Here is a reference

Resources