Tuesday, March 4, 2014

ActiveMQ - Network of Brokers Explained - Part 3

Now that we have understood the basics of ActiveMQ network connector in part 1 and part 2 of this blog series, in this part 3, we will examine how ActiveMQ load balances consumers which connect to a network of brokers.

Introduction

Concurrent consumers are used when messages in a queue can be processed out of order and usually to improve message throughput. ActiveMQ broker dispatches messages in a round-robin fashion among the consumers in order to load balance message consumption across concurrent consumers unless the consumer is specified as exclusive. 

Let's see the following example where three consumers are concurrently processing messages from queue foo.bar. A producer enqueues 60 messages which are processed by three consumers (20 each) in a round robin fashion.

Start three concurrent consumers on queue foo.bar

Ashwinis-MacBook-Pro:example akuntamukkala$ pwd
/Users/akuntamukkala/apache-activemq-5.8.0/example


Ashwinis-MacBook-Pro:example akuntamukkala$ ant consumer -Durl=tcp://localhost:61616 -Dtopic=false -Dsubject=foo.bar -DparallelThreads=3 -Dmax=20

Produce 60 messages 

Ashwinis-MacBook-Pro:example akuntamukkala$ ant producer -Durl=tcp://localhost:61616 -Dtopic=false -Dsubject=foo.bar -Dmax=60

The following screenshot shows 3 consumers processing messages from queue foo.bar. 60 messages were enqueued and dequeued. 


As shown below 20 messages were processed by each of the consumers. 


The following excerpt from log shows that messages are divvied out among three consumers...

[java] [Thread-3] Received: 'Message: 1 sent at: Tue Mar 04 13:46:53 IST 2014  ...' (length 1000)
[java] [Thread-2] Received: 'Message: 0 sent at: Tue Mar 04 13:46:53 IST 2014  ...' (length 1000)
[java] [Thread-1] Received: 'Message: 2 sent at: Tue Mar 04 13:46:53 IST 2014  ...' (length 1000)
[java] [Thread-3] Received: 'Message: 4 sent at: Tue Mar 04 13:46:53 IST 2014  ...' (length 1000)
[java] [Thread-2] Received: 'Message: 3 sent at: Tue Mar 04 13:46:53 IST 2014  ...' (length 1000)
[java] [Thread-1] Received: 'Message: 5 sent at: Tue Mar 04 13:46:53 IST 2014  ...' (length 1000)
[java] [Thread-3] Received: 'Message: 7 sent at: Tue Mar 04 13:46:53 IST 2014  ...' (length 1000)
[java] [Thread-2] Received: 'Message: 6 sent at: Tue Mar 04 13:46:53 IST 2014  ...' (length 1000)
[java] [Thread-1] Received: 'Message: 8 sent at: Tue Mar 04 13:46:53 IST 2014  ...' (length 1000)

[java] [Thread-3] Received: 'Message: 10 sent at: Tue Mar 04 13:46:53 IST 2014 ...' (length 1000)

Now that we have seen how concurrent consumers work on a single broker, we will now examine how they work when consumers are spread across network of brokers. 

Local Vs Remote Consumers

Let's explore how ActiveMQ handles local and remote consumers with the help of a configuration shown in the figure below. 



Consumer-1 and Consumer-2 consume messages from queue foo.bar on Broker-1 and Broker-2 respectively. Broker-1 established a network connector to Broker-2 to forward queue messages. Producer enqueues messages into queue foo.bar on Broker-1

Let's see this in action

  • Edit Broker-1's configuration /Users/akuntamukkala/apache-activemq-5.8.0/bridge-demo/broker-1/conf/activemq.xml and open a network connector to Broker-2 and restart Broker-1 and Broker-2

        <networkConnectors>
                <networkConnector
                        name="T:broker1->broker2"
                        uri="static:(tcp://localhost:61626)"
                        duplex="false"
                        decreaseNetworkConsumerPriority="false"
                        networkTTL="2"
                        dynamicOnly="true">
                        <excludedDestinations>
                                <queue physicalName="&gt;" />
                        </excludedDestinations>
                </networkConnector>
                <networkConnector
                        name="Q:broker1->broker2"
                        uri="static:(tcp://localhost:61626)"
                        duplex="false"
                        decreaseNetworkConsumerPriority="false"
                        networkTTL="2"
                        dynamicOnly="true">
                        <excludedDestinations>
                                <topic physicalName="&gt;" />
                        </excludedDestinations>
                </networkConnector>
        </networkConnectors>
  • Start local consumer, Consumer-1

Ashwinis-MacBook-Pro:example akuntamukkala$ ant consumer -Durl=tcp://localhost:61616 -Dtopic=false -Dsubject=foo.bar 
  • Start remote consumer, Consumer-2

Ashwinis-MacBook-Pro:example akuntamukkala$ ant consumer -Durl=tcp://localhost:61626 -Dtopic=false -Dsubject=foo.bar
  • Start producer on Broker-1 to enqueue 100 messages
Ashwinis-MacBook-Pro:example akuntamukkala$ ant producer -Durl=tcp://localhost:61616 -Dtopic=false -Dsubject=foo.bar -Dmax=100

Screenshot showing Broker-1's queues:


Let's look at the consumers to see how the messages have been divvied out.


As you may notice, ActiveMQ broker dispatches the messages equally to local consumer over the remote consumer giving them the same priority. 

The remote consumer, Consumer-2 is only broker 1 hop away which is less than configured networkTTL value of 2.

This leads to suboptimal routes especially when brokers are connected such that multiple routes are possible between producers and consumers. It is preferable to dispatch to local consumers over remote consumers in order to ensure shortest path between producers and consumers. 

ActiveMQ provides a way to configure the priority between local consumer and remote consumer using the property decreaseNetworkConsumerPriority on the network connector.

By default, this value is false and hence the local and remote brokers were treated alike. 

If we repeat the above steps after changing the decreaseNetworkConsumerPriority="true" 
then we find that local consumer, Consumer-1 is given preference over remote consumer, Consumer-2 which is 1 broker hop away. 


ActiveMQ intelligently figures out shortest path in a network of brokers between message producers and consumers. 

Please read the following link to gain further understanding of optimal routing by ActiveMQ.
This concludes part 3 of this series where we saw how to differentiate local and remote consumers to assist ActiveMQ determine most optimal path between message producers and consumers. 

As always your comments are very welcome. 

Stay tuned for part 4 where we will go over load balancing remote concurrent consumers...

Friday, February 28, 2014

ActiveMQ - Network of Brokers Explained - Part 2


In this blog we will see how duplex network connectors work.

In the previous part 1 we created a network connector from broker-1 and broker-2. We were able to see how messages for queue "foo.bar" on broker-1 were forwarded queue "foo.bar" on broker-2 when there was a consumer on broker-2 for queue "foo.bar"

Let's try doing the reverse by producing messages into broker-2's queue foo.bar and consume from broker-1's queue "foo.bar"

Ashwinis-MacBook-Pro:example akuntamukkala$ ant producer -Durl=tcp://localhost:61626 -Dtopic=false -Ddurable=true -Dsubject=foo.bar -Dmax=100

Ashwinis-MacBook-Pro:example akuntamukkala$ ant consumer -Durl=tcp://localhost:61616 -Dtopic=false -Dsubject=foo.bar


In the previous blog post, we had enqueued/dequeued 100 messages. Hence the #messages enqueued now shows as 200 here. 

As shown above, 100 new messages are enqueued on foo.bar queue on broker-2 but there are no consumers though there is a network connector for all queues from broker-1 to broker-2. 

The reason is that a network connector unless specified as "duplex" is unidirectional from the source to the destination broker. 

Let's change the following attribute highlighted in yellow in /Users/akuntamukkala/apache-activemq-5.8.0/bridge-demo/broker-1/conf/activemq.xml configuration file for broker-1.

     <networkConnectors>
         <networkConnector 
            name="T:broker1->broker2" 
            uri="static:(tcp://localhost:61626)" 
            duplex="false" 
            decreaseNetworkConsumerPriority="true" 
            networkTTL="2" 
            dynamicOnly="true">
            <excludedDestinations>
                  <queue physicalName="&gt;" />
            </excludedDestinations>
         </networkConnector>
         <networkConnector 
            name="Q:broker1->broker2" 
            uri="static:(tcp://localhost:61626)" 
            duplex="true" 
            decreaseNetworkConsumerPriority="true" 
            networkTTL="2" 
            dynamicOnly="true">
            <excludedDestinations>
                  <topic physicalName="&gt;" />
            </excludedDestinations>
         </networkConnector>
     </networkConnectors>

Let's restart the brokers and connect to the brokers using jConsole.

Here is broker-1 jConsole MBean tab screenshot which shows the following:
  1. Q:broker1->broker2 network connector is duplex.
  2. There is now a dynamic producer into broker-1 from broker-2 because the
    Q:broker1->broker2 network connector is "duplex".

Here is broker-2 jConsole MBean tab screenshot which shows the following:
  1. Duplex network connector from broker-2 to broker-1
  2. Two dynamic message producers from broker-1 to broker-2
    1. Please note that "Q:broker1->broker2" network connector shows as duplex as configured in activemq.xml 

Let's see this in action

  1. Producer 100 messages into broker-2
Ashwinis-MacBook-Pro:example akuntamukkala$ ant producer -Durl=tcp://localhost:61626 -Dtopic=false -Ddurable=true -Dsubject=foo.bar -Dmax=100

Screenshot of queues in broker-2: http://localhost:9161/admin/queues.jsp

    2.  Create a consumer on foo.bar on broker-1

Ashwinis-MacBook-Pro:example akuntamukkala$ ant consumer -Durl=tcp://localhost:61616 -Dtopic=false -Dsubject=foo.bar

The following screenshot from broker-2 shows that all the 100 messages have been dequeued by a consumer (dynamically forwarded to broker-1).

http://localhost:9161/admin/queues.jsp
The following screenshot shows the details of this dynamic consumer on broker-2's foo.bar queue.

http://localhost:9161/admin/queueConsumers.jsp?JMSDestination=foo.bar


The following screenshot shows that the 100 messages which were dynamically moved from broker-2's foo.bar queue to broker-1's foo.bar queue have been successfully consumed by the consumer which we created in step #2


This concludes part 2 of this series where we saw how duplex network connectors work. 

As always your comments are very welcome. 

Stay tuned for part 3 where we will go over load balancing consumers on local/remote brokers...

Monday, February 24, 2014

ActiveMQ - Network of Brokers Explained

Objective

This 7 part blog series is to share about how to create network of ActiveMQ brokers in order to achieve high availability and scalability.

Why network of brokers?


ActiveMQ message broker is a core component of messaging infrastructure in an enterprise. It needs to be highly available and dynamically scalable to facilitate communication between dynamic heterogeneous distributed applications which have varying capacity needs. 

Scaling enterprise applications on commodity hardware is a rage nowadays. ActiveMQ caters to that very well by being able to create a network of brokers to share the load. 

Many times applications running across geographically distributed data centers need to coordinate messages. Running message producers and consumers across geographic regions/data centers can be architected better using network of brokers.  

ActiveMQ uses transport connectors over which it communicates with message producers and consumers. However, in order to facilitate broker to broker communication, ActiveMQ uses network connectors. 

A network connector is a bridge between two brokers which allows on-demand message forwarding. 

In other words, if Broker B1 initiates a network connector to Broker B2 then the messages on a channel (queue/topic) on B1 get forwarded to B2 if there is at least one consumer on B2 for the same channel. If the network connector was configured to be duplex, the messages get forwarded from B2 to B1 on demand. 

This is very interesting because it is now possible for brokers to communicate with each other dynamically. 
In this 7 part blog series, we will look into the following topics to gain understanding of this very powerful ActiveMQ feature:
    1. Network Connector Basics - Part 1
    2. Duplex network connectors - Part 2 
    3. Load balancing consumers on local/remote brokers - Part 3
    4. Load-balance consumers/subscribers on remote brokers  
      1. Queue: Load balance remote concurrent consumers - Part 4
      2. Topic: Load Balance Durable Subscriptions on Remote Brokers - Part 5
    5. Store/Forward messages and consumer failover  - Part 6
      1. How to prevent stuck  messages
    6. Virtual Destinations - Part 7
To give credit where it is due, the following URLs have helped me in creating this blog post series. 
  1. Advanced Messaging with ActiveMQ by Dejan Bosanac [Slides 32-36] 
  2. Understanding ActiveMQ Broker Networks by Jakub Korab 

Prerequisites

  1. ActiveMQ 5.8.0 – To create broker instances
  2. Apache Ant – To run ActiveMQ sample producer and consumers for demo.
We will use multiple ActiveMQ broker instances on the same machine for the ease of demonstration.

Network Connector Basics - Part 1

The following diagram shows how a network connector functions. It bridges two brokers and is used to forward messages from Broker-1 to Broker-2 on demand if established by Broker-1 to Broker-2. 

A network connector can be duplex so messages could be forwarded in the opposite direction; from Broker-2 to Broker-1, once there is a consumer on Broker-1 for a channel which exists in Broker-2. More on this in Part 2

Setup network connector between broker-1 and broker-2

  • Create two broker instances, say broker-1 and broker-2
Ashwinis-MacBook-Pro:bin akuntamukkala$ pwd
/Users/akuntamukkala/apache-activemq-5.8.0/bin
Ashwinis-MacBook-Pro:bin akuntamukkala$ ./activemq-admin create ../bridge-demo/broker-1

Ashwinis-MacBook-Pro:bin akuntamukkala$ ./activemq-admin create ../bridge-demo/broker-2

Since we will be running both brokers on the same machine, let's configure broker-2 such that there are no port conflicts. 

  • Edit /Users/akuntamukkala/apache-activemq-5.8.0/bridge-demo/broker-2/conf/activemq.xml

    1. Change transport connector to 61626 from 61616
    2. Change AMQP port from 5672 to 6672 (won't be using it for this blog)
  • Edit /Users/akuntamukkala/apache-activemq-5.8.0/bridge-demo/broker-2/conf/jetty.xml

    1. Change web console port to 9161 from 8161
  • Configure Network Connector from broker-1 to broker-2
    Add the following XML snippet to 
    /Users/akuntamukkala/apache-activemq-5.8.0/bridge-demo/broker-1/conf/activemq.xml
     <networkConnectors>
         <networkConnector 
            name="T:broker1->broker2" 
            uri="static:(tcp://localhost:61626)" 
            duplex="false" 
            decreaseNetworkConsumerPriority="true" 
            networkTTL="2" 
            dynamicOnly="true">
            <excludedDestinations>
                  <queue physicalName="&gt;" />
            </excludedDestinations>
         </networkConnector>
         <networkConnector 
            name="Q:broker1->broker2" 
            uri="static:(tcp://localhost:61626)" 
            duplex="false" 
            decreaseNetworkConsumerPriority="true" 
            networkTTL="2" 
            dynamicOnly="true">
            <excludedDestinations>
                  <topic physicalName="&gt;" />
            </excludedDestinations>
         </networkConnector>
     </networkConnectors>

The above XML snippet configures two network connectors "T:broker1->broker2" (only topics as queues are excluded) and "Q:broker1->broker2"  (only queues as topics are excluded). This allows for nice separation between network connectors used for topics and queues. 

The name can be arbitrary although I prefer to specify the [type]:[source broker]->[destination broker].

The URI attribute specifies how to connect to broker-2
  • Start broker-2
Ashwinis-MacBook-Pro:bin akuntamukkala$ pwd
/Users/akuntamukkala/apache-activemq-5.8.0/bridge-demo/broker-2/bin

Ashwinis-MacBook-Pro:bin akuntamukkala$ ./broker-2 console
  • Start broker-1
Ashwinis-MacBook-Pro:bin akuntamukkala$ pwd
/Users/akuntamukkala/apache-activemq-5.8.0/bridge-demo/broker-1/bin

Ashwinis-MacBook-Pro:bin akuntamukkala$ ./broker-1 console

Logs on broker-1 show 2 network connectors being established with broker-2

 INFO | Establishing network connection from vm://broker-1?async=false&network=true to tcp://localhost:61626
 INFO | Connector vm://broker-1 Started
 INFO | Establishing network connection from vm://broker-1?async=false&network=true to tcp://localhost:61626
 INFO | Network connection between vm://broker-1#24 and tcp://localhost/127.0.0.1:61626@52132(broker-2) has been established.
 INFO | Network connection between vm://broker-1#26 and tcp://localhost/127.0.0.1:61626@52133(broker-2) has been established.

Web Console on broker-1 @ http://localhost:8161/admin/connections.jsp shows the two network connectors established to broker-2



The same on broker-2 does not show any network connectors since no network connectors were initiated by broker-2

Let's see this in action

Let's produce 100 persistent messages on a queue called "foo.bar" on broker-1. 

Ashwinis-MacBook-Pro:example akuntamukkala$ pwd
/Users/akuntamukkala/apache-activemq-5.8.0/example
Ashwinis-MacBook-Pro:example akuntamukkala$ ant producer -Durl=tcp://localhost:61616 -Dtopic=false -Ddurable=true -Dsubject=foo.bar -Dmax=100

broker-1 web console shows that 100 messages have been enqueued in queue "foo.bar"

http://localhost:8161/admin/queues.jsp

Let's start a consumer on a queue called "foo.bar" on broker-2. The important thing to note here is that the destination name "foo.bar" should match exactly. 

Ashwinis-MacBook-Pro:example akuntamukkala$ ant consumer -Durl=tcp://localhost:61626 -Dtopic=false -Dsubject=foo.bar 

We find that all the 100 messages from broker-1's foo.bar queue get forwarded to broker-2's foo.bar queue consumer. 

broker-1 admin console at http://localhost:8161/admin/queues.jsp


broker-2 admin console @ http://localhost:9161/admin/queues.jsp shows that the consumer we had started has consumed all 100 messages which were forwarded on-demand from broker-1 

broker-2 consumer details on foo.bar queue


broker-1 admin console shows that all 100 messages have been dequeued [forwarded to broker-2 via the network connector]. 


broker-1 consumer details on "foo.bar" queue shows that the consumer is created on demand: [name of connector]_[destination broker]_inbound_[source broker]


Thus we have seen the basics of network connector in ActiveMQ. 

As always, please feel to comment about anything that can be improved. Your inputs are welcome!

Stay tuned for Part 2...

Wednesday, January 1, 2014

Temp, Store and Memory Percent Usage in ActiveMQ

In order to effectively use ActiveMQ, it is very important to understand how ActiveMQ manages memory and disk resources to handle non-persistent and persistent messages. 
ActiveMQ has three key parameters which need to be kept under check. 



  1. Temp Percent Usage
    1. This is the % of assigned disk storage that has been used up to spool non-persistent messages
    2. Non persistent messages are those that don't survive broker restart 
  2. Store Percent Usage
    1. This is the % of assigned disk space that has been used up to store persistent messages
  3. Memory Percent Usage
    1. This is the % of assigned memory of the broker that has been used up to keep track of destinations, cache messages etc. This value needs to be lesser than -Xmx  (Max JVM heap size)
This blog attempts to clarify how store,temp and memory % usage of a single node ActiveMQ broker instance are calculated. We are using ActiveMQ version 5.8.0 for this explanation. 

Once we gain clarity on how ActiveMQ operates these values, we can fine tune ActiveMQ using key configuration settings in order to handle the following use cases. 
  1. Large number of destinations (queues/topics)
    • The destinations could be created/deleted as needed
  2. Slow consumers
    • This is huge issue when consumers are unable to keep up with the rate at which messages are being produced. 
  3. Message Burst
    • Rapid influx of large number of messages with huge payload size for a brief period of time
  4. Inappropriate Resource utilization
    • Few destinations chewing up resources causing others to starve

Scaling Strategies


If you are interested to know how ActiveMQ can be scaled horizontally, please refer to a slide deck created by Bosanac Dejan. You can find it here 

It contains different ActiveMQ topologies which can be used effectively to meet volume throughput in addition to various parameters to tune ActiveMQ. I found it extremely useful.


Let's dig right in...


The following XML snippet is taken from configuration activemq.xml. The values specified for memoryUsage, storeUsage and tempUsage are for discussion purposes only. 

         <systemUsage>
            <systemUsage>
                <memoryUsage>
                    <memoryUsage limit="256 mb"/>
                </memoryUsage>
                <storeUsage>
                    <storeUsage limit="512 mb"/>
                </storeUsage>
                <tempUsage>
                    <tempUsage limit="256 mb"/>
                </tempUsage>
            </systemUsage>
          </systemUsage>

  1. Memory Usage 
    1. 256MB of JVM memory is available for the broker. Not to be confused with -Xmx parameter.
  2. Store Usage: 
    1. This is the disk space used by persistent messages (using KahaDB)
  3. Temp Usage: 
    1. This is the disk space used by non-persistent message, assuming we are using default KahaDB. ActiveMQ spools non-persistent messages to disk in order to prevent broker running out of memory

Understanding Temp Usage


Broker availability is critical for message infrastructure. Hence producer flow control is a protection mechanism that prevents a runaway producer from pumping non-persistent messages into a destination when there are no consumers or when consumer(s) is unable to keep up with the rate at which messages are being produced into the destination.


Let’s take an example of producing non-persistent messages having 1MB payload size into a destination “foo.bar” in a local broker instance


C:\apache-activemq-5.8.0\example>ant producer -Durl=tcp://localhost:61616 -Dtopic=false -Dsubject=foo.bar -Ddurable=false -DmessageSize=1048576

The producer eventually hangs as temp % usage hits 100%





Since the messages are non-persistent, they are going to be stored in tmp_storage on the disk



ActiveMQ provides mechanism to tune memory usage per destination. Here we have a generic policy for all queues where producer flow control is enabled and destination memory limit is 100MB (again this is only for illustration purposes).

<policyEntry queue=">" optimizedDispatch="true" producerFlowControl="true" cursorMemoryHighWaterMark="30" memoryLimit="100 mb" > 

The temp % usage is calculated as follows:


(Size of the tmp_storage folder / temp usage memory limit ) * 100 
So in our case: 
265,025,856/(256*1024*1024) * 100 = 99.8 ~ 100% as shown in the broker console. 

The following log message shows up in activemq.log

 INFO | Usage(default:temp:queue://foo.bar:temp) percentUsage=99%, usage=268535808, limit=268435456, percentUsageMinDelta=1%;Parent:Usage(default:temp
) percentUsage=100%, usage=268535808, limit=268435456, percentUsageMinDelta=1%: Temp Store is Full (99% of 268435456). Stopping producer (ID:AKUNTAMU-
1-61270-1388528939599-1:1:1:1) to prevent flooding queue://foo.bar. See http://activemq.apache.org/producer-flow-control.html for more info (blocking

for: 1421s)

Let's take another example...

Consider the following system usage configuration. We have reduced tempUsage to 50MB while keeping the same destination level policy.

        <systemUsage>
            <systemUsage>
                <memoryUsage>
                    <memoryUsage limit="256 mb"/>
                </memoryUsage>
                <storeUsage>
                    <storeUsage limit="512 mb"/>
                </storeUsage>
                <tempUsage>
                    <tempUsage limit="50 mb"/>
                </tempUsage>
            </systemUsage>

        </systemUsage>
   
In this case we find that temp usage balloons to 191%



temp_storage stops growing at close to 96MB and producer hangs..



Temp percent usage is 191% because (95.5MB / 50 MB)*100 where 95.5 MB is size of the folder and 50MB is temp usage limit. 

The destination has a limit of 100MB so the temp_storage didn't grow past it. It is sort of confusing which is caused by the fact that temp usage limit is less that per destination memory limit. 


Store Usage

Let’s repeat the same test with persistent messages.


The system usage is configured as follows:

         <systemUsage>
            <systemUsage>
                <memoryUsage>
                    <memoryUsage limit="256 mb"/>
                </memoryUsage>
                <storeUsage>
                    <storeUsage limit="512 mb"/>
                </storeUsage>
                <tempUsage>
                    <tempUsage limit="256 mb"/>
                </tempUsage>
            </systemUsage>

          </systemUsage>

Per destination policy is as follows:

<policyEntry queue=">" optimizedDispatch="true" producerFlowControl="true" cursorMemoryHighWaterMark="30" memoryLimit="100 mb" > 

Let's produce 1MB persistent messages into a queue named "foo.bar"

C:\apache-activemq-5.8.0\example>ant producer -Durl=tcp://localhost:61616 -Dtopic=false -Dsubject=foo.bar -Ddurable=true -DmessageSize=1048576

Producer hangs after 512 messages

The following log statement appears in broker log file


 INFO | Usage(default:store:queue://foo.bar:store) percentUsage=99%, usage=537210471, limit=536870912, percentUsageMinDelta=1%;Parent:Usage(default:st
ore) percentUsage=100%, usage=537210471, limit=536870912,percentUsageMinDelta=1%: Persistent store is Full, 100% of 536870912. Stopping producer (ID: AKUNTAMU-1-31754-1388571228628-1:1:1:1) to prevent flooding queue://foo.bar. See http://activemq.apache.org/producer-flow-control.html for more info (
blocking for: 155s)

Broker store usage is 100% as shown below.
Since the messages are persistent, they need to be saved onto the file system. Store usage limit is 512MB. 




The above screenshot shows the kahadb folder where persistent messages is 543 MB (512MB for the messages and other database related files)


Memory Usage


In the above example, the memory usage percentage is 11. How did that come about?


As per the destination policy, the memory allocated per destination is 100MB and the cursorMemoryHighWaterMark is specified to be 30. So 30% of 100MB is 30MB. Hence 30MB is used to store messages in memory for faster processing in addition to be being stored in the KahaDB. . 

The memory usage limit is configured to be 256MB. So 30MB is ~ 11% of 256

(30/256) * 100 ~ 11%

So if we were to have 9 such queues where similar situation was to occur then we would have exhausted broker memory usage as 11 % * 9 = 99% ~ 100% 

Memory usage is the amount of memory used by the broker for storing messages. Many a times, this can become a bottleneck as once this space is full, the broker will stall the producers.  There are trade-offs between fast processing and effective memory management. 

If we keep more messages in memory, the processing is faster. However the memory consumption will be very high. On the contrary, if messages are kept on the disk then processing will become slow.


Conclusion

We have seen in this blog how store, temp and memory usage work in ActiveMQ. % of store and temp usage cannot be configured per destination while % of memory usage can be because of  cursorMemoryHighWaterMark. 

Hope you found this information useful. The examples given here are for explanation purposes only and not meant to be production ready. You will need to do proper capacity planning and determine your broker topology for optimal configuration. Feel free to reach out if any comments! 

References