Sun ONE Message Queue, Version 3.0.1 Developer's Guide |
The performance of JMS clients depends both on the inherent design of these applications and on the features and capabilities of the Sun ONE Message Queue (MQ) client runtime.
This chapter describes how the MQ client runtime supports the messaging capabilities of JMS clients, with special emphasis on properties and behaviors that you can configure to improve performance and message throughput.
The chapter covers the following topics:
- message production and consumption
- configurable properties of the MQ client runtime
- factors that affect performance
Message Production and Consumption
The MQ client runtime provides JMS clients with an interface to the MQ message serverit supplies these clients with all the JMS programming objects introduced in "The JMS Programming Model". It supports all operations needed for clients to send messages to destinations and to receive messages from such destinations.
This section provides a high level description of how the MQ client runtime supports message production and consumption. Figure 4-1 illustrates how message production and consumption involve an interaction between clients and the MQ client runtime, while message delivery involves an interaction between the MQ client runtime and the MQ message server.
Figure 4-1    Messaging Operations
Once a client has created a connection to a broker, created a session as a single-threaded context for message delivery, and created the MessageProducer and MessageConsumer objects needed to access particular destinations in a message server, production (sending) and consumption (receiving) of messages can proceed.
Message Production
In message production, a message is created by the client, and sent over a connection to a destination on a broker. If the message delivery mode of the MessageProducer object has been set to persistent (guaranteed delivery, once and only once), the client thread blocks until the broker acknowledges that the message was delivered to its destination and stored in the broker's persistent data store. If the message is not persistent, no broker acknowledgement message (referred to as "Ack" in property names) is returned by the broker, and the client thread does not block.
In the case of persistent messages, to increase throughput, you can set the connection to not require broker acknowledgement (see imqAckOnProduce property, Table 4-7), but this eliminates the guarantee that persistent messages are reliably delivered.
Message Consumption
Message consumption is more complex than production. Messages arriving at a destination on a broker are delivered over a connection to the MQ client runtime under the following conditions:
- the client has set up a consumer for the given destination
- the selection criteria for the consumer, if any, match that of messages arriving at the given destination
- the connection has been told to start delivery of messages.
Messages delivered over the connection are distributed to the appropriate MQ sessions where they are queued up to be consumed by the appropriate MessageConsumer objects, as shown in Figure 4-2.
Figure 4-2    Message Delivery to MQ Client Runtime
Note Because the flow of messages delivered to the client runtime is metered at the connection level (see "Message flow metering"), a large number of messages delivered to one session can adversely affect the delivery of messages to other sessions on the same connection. Hence, message consumers that are expected to have very different message throughput levels should use different connections.
Messages are fetched off each session queue one at a time (a session is single threaded) and consumed either synchronously (by a client thread invoking the receive method) or asynchronously (by the session thread invoking the onMessage method of a MessageListener object).
When a broker delivers messages to the client runtime, it marks the messages accordingly, but does not really know if they have been consumed. Therefore, the broker waits for the client to acknowledge receipt of a message before deleting the message from the broker's destination. If a connection fails, and another connection is subsequently established, the broker will re-deliver all previously delivered but unacknowledged messages, marking them with a Redeliver flag.
In accordance with the JMS specification, there are three acknowledgment options that a client developer can set for a client session:
- AUTO_ACKNOWLEDGE: the session automatically acknowledges each message consumed by the client.
- CLIENT_ACKNOWLEDGE: the client explicitly acknowledges after one or more messages have been consumed. This option gives the client the most control. This acknowledgement takes place by invoking the acknowledge() method of a message object, causing the session to acknowledge all messages that have been consumed by the session up to that point in time. (This could include messages consumed asynchronously by many different message listeners in the session, independent of the order in which they were consumed.)
- DUPS_OK_ACKNOWLEDGE: the session acknowledges after ten messages have been consumed (this value is not currently configurable) and doesn't guarantee that messages are delivered and consumed only once. Clients use this mode if they don't care if messages are processed more than once.
Each of the three acknowledgement options requires a different level of processing and bandwidth overhead. Automatic acknowledge consumes the most overhead and guarantees reliability on a message by message basis, while DUPS_OK_ACKNOWLEDGE consumes the least overhead, but allows for duplicate delivery of messages.
In the case of the AUTO_ACKNOWLEDGE or CLIENT_ACKNOWLEDGE options, the threads performing the acknowledgement, or committing a transaction, will block, waiting for the broker to return a control message acknowledging receipt of the client acknowledgement. This broker acknowledgement (referred to as "Ack" in property names) guarantees that the broker has deleted the corresponding persistent message and will not send it twicewhich could happen were the client or broker to fail, or the connection to fail, at the wrong time.
To increase throughput, you can set the connection to not require broker acknowledgement of client acknowledgements (see imqAckOnAcknowledge property, Table 4-5), but this eliminates the guarantee that persistent messages are reliably delivered.
MQ Client Runtime Configurable Properties
The MQ client runtime supports all the operations described in "Message Production and Consumption". It also provides a number of configurable properties that you can use to optimize resources, performance, and message throughput. These properties correspond to attributes of the ConnectionFactory object used to create physical connections between a JMS client and an MQ message server.
A ConnectionFactory object has no physical representation in a brokerit is used simply to enable the client to establish connections with a broker. The ConnectionFactory object is also used to specify behaviors of the connection and of the client runtime using the connection to access a broker. The ConnectionFactory object can also be used to manage MQ message server resources by overriding message header values set by clients.
If you wish to support distributed transactions (see "Local Transactions"), you need to use a special XAConnectionFactory object that supports distributed transactions.
ConnectionFactory administered objects are created by adminstrators or instantiated in the application, as described in Chapter 3, "Using Administered Objects."
By configuring a ConnectionFactory administered object, you specify the attribute values (the properties) common to all the connections that it produces. ConnectionFactory and XAConnectionFactory objects share the same set of attributes. These attributes are grouped into a number of categories, depending on the behaviors they affect:
- Connection specification
- Auto-reconnect behavior
- Client identification
- Message header overrides
- Reliability and flow control
- Queue browser behavior
- Application server support
- JMS-defined properties support
Each of these categories is discussed in the following sections with a description of the ConnectionFactory (or XAConnectionFactory) attributes each includes. The attribute values are set using MQ administration tools, as described in the MQ Administrator's Guide.
Connection Specification
Connections are specified by a broker's host name, the port number at which its Port Mapper resides (or at which a specific connection service resides), and the kind of connection service it supports. The behavior of a connection might require setting additional attribute values, depending on the connection type (the protocol used by the connection service).
The attributes that affect connection behavior are described in Table 4-1.
Auto-reconnect Behavior
MQ provides an automatic reconnect capability. If enabled, and if a connection fails, MQ maintains objects provided by the client runtime (sessions, message consumers, message producers, and so forth) while attempting to re-establish the connection. However, in circumstances where the client-side state cannot be fully restored on the broker upon reconnect (for example, when using transacted sessions or temporary destinationswhich exist only for the duration of a connection) , auto-reconnect does not take place, and the connection exception handler is called instead. In such cases, application code has to catch the exception, reconnect, and restore state.
The impact of auto-reconnect is different for message production and message consumption.
Message Production
During reconnect, producers cannot send messages. The production of messages (or any operation that involves communication with the message server) is blocked until the connection is re-established.
Message Consumption
Auto-reconnect is supported for AUTO_ACKNOWLEDGE and DUPS_OK_ACKNOWLEDGE sessions, but not for CLIENT_ACKNOWLEDGE sessions (JMS message ordering cannot be guaranteed). After the connection is re-established the broker will redeliver all unacknowledged messages it had previously delivered, marking them with a Redeliver flag. JMS application code can use this flag to determine if any message has already been consumed (but not yet acknowledged).
In the case of non-durable subscribers, however, some messages will not be received during a reconnect operation. This is because the message server does not hold messages for non-durable subscribers once their connections have been closed. Thus, any messages produced for these subscribers during a reconnect will not be delivered once the connection has been re-established.
The attributes that affect auto-connect behavior are described in Table 4-2.
Client Identification
Clients need to be identified to a broker both for authentication purposes and to keep track of durable subscriptions (see "Client Identifiers").
For authentication purposes MQ provides a default user name and password. These are a convenience for developers who do not wish to explicitly populate a user repository (see the MQ Administrator's Guide) to perform application testing.
To keep track of durable subscriptions, MQ uses a unique client identification (ClientID). If a durable subscriber is inactive at the time that messages are delivered to a topic destination, the broker retains messages for that subscriber and delivers them when the subscriber once again becomes active. The only way for the broker to identify the subscriber is through its ClientID.
There are a number of ways that the ClientID can be set for a connection. For example, application code can use the setClientID() method of a Connection object. The ClientID must be set before using the connection in any way; once the connection is used, the ClientID cannot be set or reset.
Setting the ClientID in application, however, is not optimal. Each user needs a unique identification: this implies some centralized coordination. MQ therefore provides a imqConfiguredClientID attribute on the ConnectionFactory object. This attribute can be used to provide a unique ClientID to each user. To use this feature, the value of imqConfiguredClientID is set as follows:
imqConfiguredClientID=${u}string
where the special reserved characters, ${u}, provide a unique user identification during the user authentication stage of establishing a connection, and string is a text value unique to the ConnectionFactory object. When used properly, the MQ message server will substitute u:username for the u, resulting in a user-specific ClientID.
The ${u} must be the first four characters of the attribute value. If anything other than "u" is encountered, it will result in an JMS exception upon connection creation. When ${} is used anywhere else in the attribute value, it is treated as plain text and no variable substitution is performed.
An additional attribute, imqDisableSetClientID, can be set to true to disallow clients that use the connection factory from changing the configured ClientID through the setClientID() method of the Connection object.
It is required that you set the client identifier whenever using durable subscriptions in deployed applications, either programmatically using the setClientID() method or using the imqConfiguredClientID attribute of the ConnectionFactory object.
The attributes that affect client identification are described in Table 4-3.
Message Header Overrides
An MQ administrator can override JMS message header fields that specify the persistence, lifetime, and priority of messages. Specifically, values in the following fields can be overridden (see "The Java XML Messaging (JAXM) Specification"):
- JMSDeliveryMode (message persistence/non-persistence)
- JMSExpiration (message lifetime)
- JMSPriority (message priorityan integer from 0 to 9)
The ability to override message header values gives an MQ administrator more control over the resources of an MQ message server. Overriding these fields, however, has the risk of interfering with application-specific requirements (for example, message persistence). So this capability should only be used in consultation with the appropriate application users or designers.
MQ allows message header overrides at the level of a connection: overrides apply to all messages produced in the context of a given connection, and are configured by setting attributes of the corresponding connection factory administered object. These attributes are described in Table 4-4.
Reliability And Flow Control
A number of attributes determine the use and flow of MQ control messages by the client runtime, especially broker acknowledgements (referred to as "Ack" in the attribute names).
The attributes that affect reliability and flow control are described in Table 4-5. For an extended discussion of these settings and the effect of various permutations, see "Managing Flow Control".
Queue Browser Behavior
The attributes that affect queue browsing for the client runtime are described in Table 4-6.
Application Server Support
The behavior of sessions running in an application server environment is affected by the attribute described in Table 4-7. For background see the JMS specification.
JMS-defined Properties Support
JMS-defined properties are property names reserved by JMS, and which a JMS provider can choose to support (see "The Java XML Messaging (JAXM) Specification"). These properties enhance client programming capabilities.
The JMS-defined properties supported by MQ are described in Table 4-8.
Performance Issues
This section describes ways that you can improve performance by managing message flow and controlling the proliferation of threads.
Managing Flow Control
Because of the mechanisms by which messages are delivered to and from a broker, and because of the MQ control messages used to assure reliable delivery, there are a number of factors that affect message flow and consumption. These include delivery mode, acknowledgement mode, message flow metering, message flow limits, and number of sessions. Although these factors are quite distinct, their interactions can complicate the task of balancing reliability with performance. Specifically, because JMS client messages and MQ control messages flow across the same connection between the client and the broker, you need to understand how to balance the requirement for reliability with the need for throughput.
Factors Affecting Performance
A number of factors can affect message flow--that is, the flow of messages from the broker to a client; this section describes these factors and the connection factory attributes that help manage flow control.
Delivery mode The delivery mode specifies whether a message is to be delivered at most once (non-persistent) or once and only once (persistent). These different reliability requirements imply different degrees of overhead. Specifically, the management of persistent messages requires greater use of broker control messages flowing across a connection.
Client acknowledgement mode The setting of this mode affects the number of client and broker acknowledgement messages passing over a connection:
- In the AUTO_ACKNOWLEDGE mode, a client acknowledgement and broker acknowledgement are required for each consumed message, and the delivery thread blocks waiting for the broker acknowledgement.
If you set this mode, it is possible that a message could be partially processed and lost if the system fails and the message consumer is a synchronous receiver. To avoid this, the client can use the CLIENT_ACKNOWLEDGE mode or a transacted session to guarantee no message is lost if the system fails.
- In the CLIENT_ACKNOWLEDGE mode client acknowledgements and broker acknowledgements are batched (rather than being sent one by one). This conserves connection bandwidth and generally reduces the overhead for broker acknowledgements.
- In the DUPS_OK_ACKNOWLEDGE mode, throughput is improved even further, because client acknowledgements are batched and because the client thread does not block (broker acknowledgements are not requested). However, in this case, the same message can be delivered and consumed more than once.
Message flow metering Because messages sent and received by JMS clients (JMS messages) and MQ control messages pass over the same client-broker connection, delays may occur in the delivery of control messages such as broker acknowledgements as these are held up by the delivery of JMS messages. To prevent this type of congestion, MQ meters the flow of JMS messages across connections: JMS messages are batched (as specified with the imqFlowControlCount property) so that only a set number are delivered; when the batch of messages has been delivered, delivery of JMS messages is suspended and pending control messages are delivered. Another batch of JMS messages is then delivered, followed by any pending control messages.
You can specify the number of messages allowed in a batch of JMS messages by setting the imqFlowControlCount property (Table 4-5). By default, this limit is set to 100 messages.Message flow limits MQ client runtime code can handle only a limited number of delivered JMS messages before encountering local resource limitations, such as memory. When this limit is approached, performance suffers. Hence, MQ lets you limit the number of messages queued up in sessions awaiting consumption by controlling the flow of JMS messages to the client.
You can specify the number of JMS messages the client runtime is prepared to hold before asking for more messages from the broker by setting the imqFlowControlLimit property (Table 4-5). By default this property is set to 1000. But, this limit is only checked if you also set the property imqFlowControlIsLimited to true. If you set both these properties appropriately, the client runtime will wait until the number of un-consumed messages drops below this limit before requesting that the delivery of JMS messages be resumed. Message delivery then continues until the threshold value is exceeded. So, to take an example, if imqFlowControlIsLimited is enabled, imqFlowControlLimit is set to 100, and imqFlowControlCount is set to 10, the broker will send messages to the client runtime in batches of ten messages until the total number of unconsumed messages handed to the client runtime totals 110. Then delivery will stop until the number of unconsumed messages dips below 100. When it does, another batch of ten messages is delivered.Impact of Flow Control Settings
Table 4-9 describes the effect of various settings for the connection factory attributes imqFlowControlIsLimited, imqFlowControlLimit, and imqFlowControlCount.Note particularly the difference between the first (default) case and the second case.
In short, you need to set imqFlowControlIsLimited to true if you want to protect the client runtime from message overrun. The maximum number of unconsumed messages the client runtime can hold is given by the sum of imqFlowControlLimit and imqFlowControlCount.
In balancing the requirements of throughput, memory use, and the timely processing of control messages, keep the following guidelines in mind:
- Large imqFlowControlLimit results in faster performance but greater use of client runtime memory.
- Small imqFlowControlLimit results in slower performance but less use of client runtime memory.
- Large imqFlowControlCount results in greater use of client runtime memory. Control messages may be delayed in reaching the client runtime.
- Small imqFlowControlCount results in less use of client runtime memory. Control messages are promptly delivered.
These points can be summarized by the following precepts:
- The value of imqFlowControlLimit should be determined by the size of the messages and by how much memory the client runtime can use.
- The value of imqFlowControlCount should be kept low if the client is doing operations that require many responses from the broker; for example, the client is using the CLIENT_ACKNOWLEDGE or AUTO_ACKNOWLEDGE modes, persistent messages, transactions, queue browsers, or if the client is adding or removing consumers. If, on the other hand, the client has only simple consumers on a connection using DUPS_OK mode, you can increase imqFlowControlCount without compromising performance.
Don't forget that the number of messages queued up in a session is a function of the number of message consumers using the session and the message load for each consumer. If a client is exhibiting delays in producing or consuming messages, you can normally improve performance by redesigning the application to distribute message producers and consumers among a larger number of sessions or to distribute sessions among a larger number of connections.
Managing Threads
The JMS specification mandates that only one thread can use a single session. Violating this requirement can result in a deadlocked client, and it is strongly recommended that you do not do so.
Each JMS session in MQ uses a thread to deliver messages to message consumers. If you create several message consumers in a session, messages are serially delivered to these consumers. If sharing a session amongst several message consumers causes some consumers to be starved of message flow due to excessive flow to other consumers, it might be necessary to separate the consumers into different sessions.
If you need to reduce the number of threads used, you can do so by having fewer connections and fewer sessions. If you want to share sessions among threads, you will need to write your own pooling mechanism. Sharing sessions might affect performance; this depends on the dynamics of your system. For a quick test, have all of your publishers and subscribers use the same static connection and static session, and see how the system behaves.
If you are running on Solaris, you may be able to run with the same number (or more) threads by using the following vm options with the client:
- Xss128K This decreases the meory size of the heap.
- xconcurrentIO This improves thread performance in the 1.3 VM.