LibraryPrintFeedback

Tuning Guide

Version 7.1

December 2012
Trademark Disclaimer
Third Party Acknowledgements

Updated: 07 Jan 2014

Table of Contents

1. General Tuning Techniques
Introduction to Performance Tuning
System Environment
Co-locating the Broker
Optimizing the Protocols
Message Encoding
Consumer Performance
Acknowledgment Modes
Reducing Context Switching
Prefetch Limit
Producer Performance
Async Sends
Flow Control
Threading Optimizations
Vertical Scaling
Horizontal Scaling
Integration with Spring and Camel
2. Persistent Messaging
Serializing to Disk
KahaDB Optimization
vmCursor on Destination
JMS Transactions

List of Figures

1.1. Broker Co-located with Producer
1.2. Default Consumer Threading Model
1.3. Optimized Consumer Threading Model
1.4. Consumer Prefetch Limit
1.5. Broker with Flow Control Enabled
1.6. Broker with Flow Control Disabled
1.7. Scaling with Multiple Brokers
2.1. Synchronous Dispatch through a Persistent Broker
2.2. Concurrent Store and Dispatch
2.3. KahaDB Architecture

List of Tables

1.1. OpenWire Parameters Affecting Performance

An obvious way to improve network performance is to eliminate one of the hops in the messaging application. With a standalone broker, at least two hops are required to route a message from producer to consumer: the producer-to-broker hop and the broker-to-consumer hop. On the other hand, by embedding the broker (either in the producer or in the consumer), it is possible to eliminate one of the hops, thereby halving the load on the network.

Figure 1.1 shows an example of a data feed that acts as a message producer, sending a high volume of messages through the broker. In this case, it makes perfect sense for the broker to be co-located with the data feed, so that messages can be sent directly to the consumers, without the need for an intermediate hop. The simplest way to create an embedded broker is to exploit Fuse MQ Enterprise's vm:// transport.


Fuse MQ Enterprise supports the following acknowledgment modes:

Session.AUTO_ACKNOWLEDGE

(Default) In this mode, the JMS session automatically acknowledges messages as soon as they are received. In particular, the JMS session acknowledges messages before dispatching them to the application layer. For example, if the consumer application calls MessageConsumer.receive(), the message has already been acknowledged before the call returns.

Session.CLIENT_ACKNOWLEDGE

In this mode, the client application code explicitly calls the Message.acknowledge() method to acknowledge the message. In Apache Camel, this acknowledges not just the message on which it is invoked, but also any other messages in the consumer that have already been completely processed.

Session.DUPS_OK_ACKNOWLEDGE

In this mode, the JMS session automatically acknowledges messages, but does so in a lazy manner. If JMS fails while this mode is used, some messages that were completely processed could remain unacknowledged. When JMS is restarted, these messages will be re-sent (duplicate messages).

This is one of the fastest acknowledgment modes, but the consumer must be able to cope with possible duplicate messages (for example, by detecting and discarding duplicates).

Session.SESSION_TRANSACTED

When using transactions, the session implicitly works in SESSION_TRANSACTED mode. The response to the transaction commit is then equivalent to message acknowledgment.

When JMS transactions are used to group multiple messages, transaction mode is very efficient. But avoid using a transaction to send a single message, because this incurs the extra overhead of committing or rolling back the transaction.

ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE

This non-standard mode is similar to CLIENT_ACKNOWLEDGE, except that it acknowledges only the message on which it is invoked. It does not flush acknowledgments for any other completed messages.

Figure 1.2 gives an overview of the default threading model on a consumer. The first thread layer is responsible for pulling messages directly from the transport layer, marshalling each message, and inserting the message into a queue inside a javax.jms.Session instance. The second thread layer consists of a pool of threads, where each thread is associated with a javax.jms.MessageConsumer instance. Each thread in this layer picks the relevant messages out of the session queue, inserting each message into a queue inside the javax.jms.MessageConsumer instance.


Figure 1.3 gives an overview of the optimized consumer threading model. This threading model can be enabled, only if there is no more than one session associated with the connection. In this case, it is possible to optimize away the session threading layer and the MessageConsumer threads can then pull messages directly from the transport layer.


By default, when flow control is disabled and the relevant memory limit is reached, the slow consumer's messages are backed up in a temporary file. An alternative strategy for coping with the excess messages, however, is simply to discard the slow consumer's messages when they exceed a certain limit (where the oldest messages are discarded first). This strategy avoids the overhead of writing to a temporary file.

For example, if the slow consumer is receiving a feed of real-time stock quotes, it might be acceptable to discard older, undelivered stock quotes, because the information becomes stale.

To enable discarding of messages, define a pending message limit strategy in the broker configuration. For example, to specify that the backlog of messages stored in the broker (not including the prefetched messages) cannot exceed 10 for any topics that match the PRICES.> pattern (that is, topic names prefixed by PRICES.), configure the broker as follows:

<beans ... >
  <broker ...>
    <!--  lets define the dispatch policy -->
    <destinationPolicy>
      <policyMap>
        <policyEntries>
          <policyEntry topic="PRICES.>">

            <!-- lets force old messages to be discarded for slow consumers -->
            <pendingMessageLimitStrategy>
              <constantPendingMessageLimitStrategy limit="10"/>
            </pendingMessageLimitStrategy>

          </policyEntry>
          ...
        </policyEntries>
      </policyMap>
    </destinationPolicy>
  </broker>
</beans>

For more details about how to configure pending message limit strategies, see http://activemq.apache.org/slow-consumer-handling.html.

You can optimize the performance of the KahaDB message store by modifying the following properties (set as attributes on the kahaDB element):

For more details about these KahaDB configuration properties, see Optimizing the Metadata Cache in Configuring Broker Persistence and Configuring the KahaDB Message Store in Configuring Broker Persistence.