James Selvakumar
James Selvakumar

Reputation: 2839

What is the correct way to throttle ActiveMQ producers who send persistent messages in batches to a queue?

I have a producer which sends persistent messages in batches to a queue leveraging JMS transaction.

I have tested and found that Producer Flow Control is applied when using a batch size of 1. I could see my producer being throttled as per the memory limit I have configured for the queue. Here's my Producer Flow Control configuration:

<policyEntry queue="foo" optimizedDispatch="true"
     producerFlowControl="true" memoryLimit="1mb">
</policyEntry>

The number of pending messages in the queue are in control which I see as the evidence for Producer Flow Control in action.

However, when the batch size is increased to 2, I found that this memory limit is not respected and the producer is NOT THROTTLED at all. The evidence being the number of pending messages in the queue continue to increase till it hits the storeUsage limit configured.

I understand this might be because the messages are sent in asynchronous fashion when the batch size is more than 1 even though I haven't explicitly set useAsyncSend to true.

ActiveMQ's Producer Flow Control documentation mentions that to throttle asynchronous publishers, we need to configure Producer Window Size in the producer which shall force the Producer to wait for acknowledgement once the window limit is reached.

However, when I configured Producer Window Size in my producer and attempted to send messages in batches, an exception is thrown and no messages were sent.

This makes me think and ask this question, "Is it possible to configure Producer Window Size while sending persistent messages in batches?".

If not, then what is the correct way to throttle the producers who send persistent messages in batches?

Upvotes: 3

Views: 2178

Answers (2)

James Selvakumar
James Selvakumar

Reputation: 2839

I found this problem in v5.8.0 but found this to be resolved in v5.9.0 and above. From v5.9.0 onwards I found PFC is applied out of the box even for producers who send messages asynchronously. Since batch send (where batch size > 1) is essentially an asynchronous operation, this applies there as well. But the PFC wiki was confusing as it mentions that one should configure ProducerWindowSize for async producers if PFC were to be applied. However, I tested and verified that this was not needed. I basically configured a per-destination limit of 1mb and sent messages in batches (with batch size of 100).

My producer was throttled out of the box without any additional configuration. The number of pending messages in the queue didn't increase and was under control.

With a simple Camel consumer consuming the messages (and appending them to a file), I found that with v5.8.0 (where I faced the problem), I could send 100k messages with the payload being 2k in 36 seconds. But most of them ended up as Pending messages.

But with v5.9.0, it took 176 seconds to send the same set of messages testifying the role played by PFC. And the number of pending messages never increased beyond 1000 in my case.

I also tested with v5.10.0 and v5.12.0 (the latest version at the time of writing) which worked as expected.

So if you are facing this problem, chances are that you are running ActiveMQ v5.8.0 or earlier. Simply upgrading to the latest version should solve this problem.

I thank the immensely helpful ActiveMQ mailing list folks for all their suggestions and help.

Thanks @Petter for your answer too. Sorry I didn't mention the version I was using in my question, otherwise I believe you could have spotted the problem straight away.

Upvotes: 0

Petter Nordlander
Petter Nordlander

Reputation: 22279

There is not really a way to throttle "max msgs per second" or similar. What you would do is to enable producer flow control and vm cursor, then set the memory limit on that queue (or possibly all queues if you wish) to some reasonable level.

You can decide in the configuration if the producer should hang or throw an exception if the queue memory limit has been reached.

<policyEntry queue="MY.BATCH.QUEUE" memoryLimit="100mb" producerFlowControl="true">
  <pendingQueuePolicy>
    <vmQueueCursor/>
  </pendingQueuePolicy>
</policyEntry>

Upvotes: 2

Related Questions