Application design decisions can have a significant effect on overall messaging performance. In general, the more reliable the delivery of messages, the more overhead and bandwidth are required to achieve it. The trade-off between reliability and performance is a significant design consideration. You can maximize performance and throughput by choosing to produce and consume non-persistent messages. On the other hand, you can maximize reliability by producing and consuming persistent messages using a transacted session. Between these extremes are a number of options, depending on the needs of your application. This section describes how these options or factors affect performance. They include the following:
Table 3–5 summarizes how application design factors affect messaging performance. The table shows two scenarios (a high reliability, low performance scenario and a high performance, low reliability scenario) and the choice of application design factors that characterizes each. Between these extremes, there are many choices and trade-offs that affect both reliability and performance.
Table 3–5 Comparison of High Reliability and High Performance Scenarios
Application DesignFactor |
High ReliabilityLow Performance Scenario |
High PerformanceLow Reliability Scenario |
---|---|---|
Delivery mode |
Persistent messages |
Non-persistent messages |
Use of transactions |
Transacted sessions |
No transactions |
Acknowledgement mode |
AUTO_ACKNOWLEDGE or CLIENT_ACKNOWLEDGE |
DUPS_OK_ACKNOWLEDGE |
Durable/non-durable subscriptions |
Durable subscriptions |
Non-durable subscriptions |
Use of selectors |
Message filtering |
No message filtering |
Message size |
Small messages |
Large messages |
Message body type |
Complex body types |
Simple body types |
In the discussion that follows, performance data was generated on a two-CPU, 1002 Mhz, Solaris 8 system, using file-based persistence. The performance test first warmed up the Message Queue broker, allowing the Just-In-Time compiler to optimize the system and the persistent database to be primed.
Once the broker was warmed up, a single producer and a single consumer were created, and messages were produced for 30 seconds. The time required for the consumer to receive all produced messages was recorded, and a throughput rate (messages per second) was calculated. This scenario was repeated for different combinations of the application design factors shown in Factors Affecting Performance.
Persistent messages guarantee message delivery in case of message server failure. The broker stores these message in a persistent store until all intended consumers acknowledge they have consumed the message.
Broker processing of persistent messages is slower than for non-persistent messages for the following reasons:
A broker must reliably store a persistent message so that it will not be lost should the broker fail.
The broker must confirm receipt of each persistent message it receives. Delivery to the broker is guaranteed once the method producing the message returns without an exception.
Depending on the client acknowledgment mode, the broker might need to confirm a consuming client’s acknowledgement of a persistent message.
The differences in performance for persistent and non-persistent modes can be significant--about 25% faster for non-persistent messages.
A transaction guarantees that all messages produced in a transacted session and all messages consumed in a transacted session will be either processed or not processed (rolled back) as a unit. The C-API supports local transactions. In general the overhead of transaction processing dwarfs all other differentiators.
A message produced or acknowledged in a transacted session is slower than in a non-transacted session for the following reasons:
Additional information must be stored with each produced message.
In some situations, messages in a transaction are stored when normally they would not be. For example, a persistent message delivered to a topic destination with no subscriptions would normally be deleted, however, at the time the transaction is begun, information about subscriptions is not available.
Information on the consumption and acknowledgement of messages within a transaction must be stored and processed when the transaction is committed.
Other than using transactions, you can ensure reliable delivery by having the client acknowledge receiving a message. If a session is closed without the client acknowledging the message or if the message server fails before the acknowledgment is processed, the broker redelivers that message, setting the MQ_REDELIVERED_HEADER_PROPERTY message header.
For a non-transacted session, the client can choose one of three acknowledgement modes, each of which has its own performance characteristics:
AUTO_ACKNOWLEDGE. The system automatically acknowledges a message once the consumer has processed it. This mode guarantees at most one redelivered message after a provider failure.
CLIENT_ACKNOWLEDGE. The application controls the point at which messages are acknowledged. All messages that have been received in the same session up to the message where the acknowledge function is called upon are acknowledged. If the message server fails while processing a set of acknowledgments, one or more messages in that group might be redelivered.
Note that this behavior models the JMS 1.0.2 specification rather than the JMS 1.1 specification
(Using CLIENT_ACKNOWLEDGE mode is similar to using transactions, except there is no guarantee that all acknowledgments will be processed together if a provider fails during processing.)
DUPS_OK_ACKNOWLEDGE. This mode instructs the system to acknowledge messages in a lazy manner. Multiple messages can be redelivered after a provider failure.
Performance is impacted by acknowledgement mode for the following reasons:
Extra control messages between broker and client are required in AUTO_ACKNOWLEDGE and CLIENT_ACKNOWLEDGE modes. The additional control messages add processing overhead and can interfere with JMS payload messages, causing processing delays.
In AUTO_ACKNOWLEDGE and CLIENT_ACKNOWLEDGE modes, the client must wait until the broker confirms that it has processed the client’s acknowledgment before the client can consume more messages. (This broker confirmation guarantees that the broker will not inadvertently redeliver these messages.)
The Message Queue persistent store must be updated with the acknowledgement information for all persistent messages received by consumers, thereby decreasing performance.
In general, our tests show about a 7% difference in performance between pesistent and nonpersistent messages, no matter which acknowledgment mode is used. That is, while persistence is a significant factor affecting performance, acknowledgment mode is not.
Subscribers to a topic destination have either durable or non-durable subscriptions. Durable subscriptions provide increased reliability at the cost of slower throughput for the following reasons:
The Message Queue message server must persistently store the list of messages assigned to each durable subscription so that should a message server fail, the list is available after recovery.
Persistent messages for durable subscriptions are stored persistently, so that should a message server fail, the messages can still be delivered after recovery, when the corresponding consumer becomes active. By contrast, persistent messages for non-durable subscriptions are not stored persistently (should a message server fail, the corresponding consumer connection is lost and the message would never be delivered).
For nonpersistent messages, performance is about the same for durable and non durable subscriptions. For persistent messages, performance is about 20% lower for durable subscriptions than for nondurable subscriptions.
Application developers can have the messaging provider sort messages according to criteria specified in the message selector associated with a consumer and deliver to that consumer only those messages whose property value matches the message selector. For example, if an application creates a subscriber to the topic WidgetOrders and specifies the expression NumberOfOrders >1000 for the message selector, messages with a NumberOfOrders property value of 1001 or more are delivered to that subscriber.
Creating consumers with selectors lowers performance (as compared to using multiple destinations) because additional processing is required to handle each message. When a selector is used, it must be parsed so that it can be matched against future messages. Additionally, the message properties of each message must be retrieved and compared against the selector as each message is routed. However, using selectors provides more flexibility in a messaging application and may lower resource requirements at the expense of speed.
In our tests, performance results were affected by the use of selectors only in the case of nondurable subscribers, which ran about 33% faster without selectors. For durable subscribers and for queue consumers, performance was not affected by the use of selectors. For more information on using selectors, see Using Selectors Efficiently
Message size affects performance because more data must be passed from producing client to broker and from broker to consuming client, and because for persistent messages a larger message must be stored.
However, by batching smaller messages into a single message, the routing and processing of individual messages can be minimized, providing an overall performance gain. In this case, information about the state of individual messages is lost.
In our tests we compared performance for persistent and non-persistent 1k, 10k, and 100k messages. We found that 100k messages were processed two to three times faster than 10k messages, and 10k messages were processed five to six times faster than 1k messages. For both persistent and non-persistent messages, the size of the message affected the processing rate much more than its delivery mode. For 1k messages, non-persistent messages were almost twice as fast; for 10k messages, non-persistent messages were about 33% faster; for 100k messages, non persistent messages were about 5% faster. In our tests all messages were sent to a queue destination and used the AUTO_ACKNOWLEDGE acknowledgement mode.
The C API supports three message types:
MQ_BYTES_MESSAGE, which contains a set of bytes in a format determined by the application
MQ_TEXT_MESSAGE, which is a simple MQString
MQ_MESSAGE, which contains a header and properties but no body
Since performance varies with the complexity of the data, text messages are slightly more expensive to send than byte messages, and messages that have no body are the fastest.