Skip to content

Toro Cloud Dev Center


Tuning ActiveMQ

A messaging system is vital for processes to communicate to other processes reliably. From storage, routing, and monitoring, there needs to be systematic management of messages. To address these matters and to implement its Message Oriented Middleware (MOM) architecture, Martini makes use of ActiveMQ, an enterprise-grade message broker. ActiveMQ enables decoupled communication among applications, making it easy to build seamless applications.

Learn more about how Martini uses ActiveMQ here!

Martini uses ActiveMQ by default when logging transactions to Monitor and Tracker.

Different applications will have different requirements. Some systems will benefit more from an increase in speed over reliability; others, vice versa. This page will look at how ActiveMQ can be tuned to suit your application needs. It will discuss configuration properties, their benefits, and trade-offs. For this reason, it is also important that you analyze how your organization uses Martini and ActiveMQ before making adjustments.

Overridden properties

Martini has already tuned ActiveMQ to achieve a balance between speed, reliability, and throughput. These adjustments are visible in the instance .properties file, particularly <martini-home>\conf\application.properties. Below are the properties set for optimization:

Maximum message redelivery

  • Name: activemq.maximum-redeliveries
  • Default Value: 5

Messages in ActiveMQ are redelivered in certain situations. This property specifies how many times a message should be redelivered before it goes to the Dead Letter Queue (DLQ). If you want to ensure the redelivery of messages, consider using a different acknowledgement mode.

Message redelivery delay

  • Name: activemq.maximum-redelivery-delay
  • Default Value: 5000 (milliseconds)

Redelivery delay refers to the time interval between message re-deliveries. You should consider the message throughput when configuring this property because a clog up on system memory may occur when too many messages are held for too long.

Asynchronous sending

  • Name: activemq.send-asynchronously
  • Default Value: true

When publishing a message, the broker needs to send back a receipt to the publisher stating that message has been received successfully. This process adds significant overhead to the system when done synchronously. By default, this is configured to be asynchronous which tells the publisher not to wait for broker receipts. However, there might be cases of message loss since publishers will blindly publish messages to the broker. If your application is mission-critical or you just cannot afford to lose messages, consider setting this to false instead.

Optimized acknowledgement

  • Name: activemq.optimize-acknowledge
  • Default Value: true

ActiveMQ can process acknowledgement receipts in batches by setting this property to true. If the batch limit is not reached after 300 milliseconds, collected messages are also acknowledged. Depending on your use case, this configuration may affect the performance of your Martini instance.

Topic advisories

  • Name: activemq.watch-topic-advisories
  • Default Value: false

ActiveMQ automatically creates topics prefixed with ActiveMq.Advisory. for its advisory message feature. This is mainly to provide information regarding the behavior of its components. Martini has this disabled by default for performance reasons. You need to set this to true if you want to build a network of brokers because advisory topics are required for multiple broker communication.

Queue or topic memory optimization

  • Name: activemq.cursor-memory-high-water-mark
  • Default Value: 25

This property refers to the percentage (%) threshold applied to the total allocated JVM memory which, when exceeded, will cause the destination’s cursor to either block or be written to disk while waiting to be processed. Improper configuration may lead to out of memory exceptions as the embedded ActiveMQ instance may also consume Martini Runtime's share of allocated JVM memory. This property should be set only for embedded Active MQ instances.

Further tuning

Aside from the configurations made out-of-the-box by Martini, you can further refine your ActiveMQ instance by:

Optimizing threads

Each destination will warrant a dedicated thread assigned by ActiveMQ. If you have a large number of destinations, expect a large amount of memory usage due to memory consumed by these threads. You can configure ActiveMQ to use a thread pool instead by adding -Dorg.apache.activemq.UseDedicatedTaskRunner=false in the start up script of the JVM that's running ActiveMQ (either Martini if it's embedded or the ActiveMQ script if using a dedicated instance).

As of ActiveMQ 5.6, the use of a dedicated task runner is disabled by default

Thus, depending on the version used, you may not have to pass the -Dorg.apache.activemq.UseDedicatedTaskRunner=<value> argument.

Using NIO transport

ActiveMQ uses TCP transport by default for communication. There is another transport type called NIO transport which uses a different API that can help speed up and scale the broker. NIO is a server side option only. Using this on the client side will make the configuration fallback to TCP. See this document for more information on how to use NIO instead.

Tuning the ActiveMQ instance

Another factor that can affect the messaging system performance is the ActiveMQ instance itself. Make sure the memory allocation, disk allocation, JVM, persistence configuration, and other settings are adjusted to suit your needs. You can learn how to further tune ActiveMQ here.

Tuning other Martini components

To further increase the performance of Martini's messaging system, you may want to tune other components as well. Most of them impact the messaging system's performance so it's a good idea to learn how to tune them. As an example, you can tune Tracker to adjust how messages are logged or the JVM to increase the overall performance.

Load balancing

If your application needs to process huge amounts of messages, you can opt to distribute the workload over multiple Martini instances. This process is known as load balancing. Load balancing works by connecting multiple instances to a single queue. Messages are then delivered with only one instance retrieving one message from the broker at a time.

To allow load balancing, you need to configure these application properties:

  • jms.configuration-file

    If you are using a remote ActiveMQ, change this to remote-activemq.

  • activemq.uri

    The URL used to connect to the broker. Ensure that your instances are connecting to the same broker.

  • activemq.username

    The username used when connecting to ActiveMQ. This is set to guest by default.

  • activemq.password

    The password used when connecting to ActiveMQ. This is set to guest by default.

  • jms.destination-prefix

    The destination name prefix. Ensure that your instances have the same prefix so that they share the same destinations. You can leave this blank to use non-prefixed destination names.

  • jms.client-id

    Used by the broker to uniquely identify the application. Ensure that your instances have different client IDs to allow them to be connected to the same broker.

Here's an example configuration:

  • In our first instance of Martini, we have:

    1
    2
    3
    4
    jms.configuration-file=remote-activemq
    activemq.uri=failover:(tcp://0.0.0.0:61616?closeAsync=false&wireFormat.maxInactivityDuration=0)
    jms.destination-prefix=cluster1
    jms.client-id=instance1
    
  • In our second instance of Martini, we have:

    1
    2
    3
    4
    jms.configuration-file=remote-activemq
    activemq.uri=failover:(tcp://0.0.0.0:61616?closeAsync=false&wireFormat.maxInactivityDuration=0)
    jms.destination-prefix=cluster1
    jms.client-id=instance2
    

After everything has been configured, you may now (re-)start your instances. If you are using a remote ActiveMQ instance, you can verify that your instances share the same destinations by accessing the ActiveMQ web console. Go to Queues and you should see the destinations shared by your instances. To verify that your instances are connected, click one of the destinations, then View Consumers. You should now see a connection entry for each of your instances similar to:

ActiveMQ load-balanced connections