2 Best Practices for Application Design

Learn about the design options for WebLogic Server JMS, application behaviors to be considered during the design process, and the recommended design patterns.

Message Design

Learn how to design messages to improve messaging performance.

Serializing Application Objects

The CPU cost of serializing Java objects can be significant. This expense, in turn, affects JMS Object messages. You can offset some of this cost by having application objects implement the java.io.Externalizable interface, but there still will be significant overhead in marshalling the class descriptor. To avoid the cost of having to write the class descriptors of additional objects embedded in an Object message, have these objects implement Externalizable, and call readExternal and writeExternal on them directly. For example, call obj.writeExternal(stream) rather than the stream.writeObject(obj). Using Bytes and Stream messages is generally a preferred practice.

Serializing Strings

Serializing text can add CPU and memory overhead. A Java String's memory footprint depends on its content and the JVM's representation, while its serialized size depends on the encoding. In addition, the introduction of string-based messages often implies an expensive parse step in the application in order to process the String into something the application can make direct use of. Bytes, Stream, Map and Object messages are therefore sometimes preferable to Text and XML messages. Similarly, it is preferable to avoid the use of strings in message properties, especially if they are large.

Server-side Serialization

Delivery mode alone does not determine where serialization costs occur. Both clients and servers can perform serialization when messages cross JVM boundaries. The server also serializes message data for persistent storage and can serialize nonpersistent messages for paging. The cost depends on the message type, representation, and delivery path.

Selection

Selectors add evaluation work. Put data needed by standard JMS selectors in user-defined message properties or supported JMS header fields; standard selectors do not inspect the message body. Choose property types that match the selector expressions, and evaluate selector performance with representative message backlogs and consumer counts.

Message Compression

Compressing large messages in a JMS application can improve performance.

Compressing a message body can reduce the bytes transmitted and, when compressed data is retained, its memory or storage footprint. The benefit depends on the payload, compression method, and delivery path. Compression and decompression consume CPU on the clients or servers that perform them. WebLogic's automatic compression can run in a producer JVM or in a server JVM when messages are sent to a remote consumer.

Measure compression with representative messages and workloads. Small or already compressed payloads may provide little benefit or become larger after compression. For application-managed compression, Java provides the java.util.zip package.

For information about using JMS connection factories to specify the automatic compression of messages that exceed a specified threshold size, see Compressing Messages in the Tuning Performance of Oracle WebLogic Server.

Message Properties and Message Header Fields

Store application payload in the message body. Use small user-defined properties for selection or routing metadata, and use standard JMS header fields only for their documented purposes.

Large property values add memory, serialization, and copying costs. Paging can reduce memory use, but it does not eliminate all per-message memory overhead. Keep headers and properties small even when paging is enabled.

See Message Header Fields and Message Property Fields.

Message Ordering

Use Message Unit-of-Order when ordered processing is required for messages that share a Unit-of-Order within a destination. Applications must submit messages in the intended order; processing follows the feature's acknowledgement and transaction rules.

The advantages of Message Unit-of-Order over Ordered Redelivery are:

  • Ease of configuration.

    • Does not require a custom connection factory for asynchronous receivers, such as setting the MessagesMaximum to 1 when using message-driven beans (MDBs).

    • Simple configuration when using distributed destinations.

  • Preserves message order during processing delays.

  • Preserves message order during transaction rollback or session recovery.

Oracle recommends applications that use Ordered Redelivery upgrade to Message Unit-of-Order. See Using the Message Unit-of-Order.

Topics Vs. Queues

Choose queues or topics according to whether consumers should share the work of receiving messages or receive independent copies through subscriptions.

A queue distributes deliveries among eligible consumers. Selection depends on message selectors, consumer capacity, and applicable ordering constraints; applications must not rely on a fixed round-robin order.

A topic delivers a copy to each eligible subscription. An unshared subscription can have at most one active consumer, while a shared subscription can distribute its messages among multiple consumers. A durable subscription can retain messages while it is inactive; a nondurable subscription does not provide that offline-retention guarantee.

When the existing durable subscription can be removed, recreating it with the same identity but a different selector replaces the subscription and discards its retained messages. Close its consumers and complete outstanding transactions before attempting the change; the absence of active consumers alone does not establish that removal is permitted. Creating a queue consumer with a different selector does not delete unmatched messages from the queue.

For more information about configuring JMS queues and topics, see Queue and Topic Destination Resources in Administering JMS Resources for Oracle WebLogic Server.

Asynchronous Vs. Synchronous Consumers

In general, asynchronous (onMessage) consumers perform and scale better than synchronous consumers.

  • Asynchronous consumers create less network traffic. Messages are pushed unidirectionally, and are pipelined to the message listener. Pipelining supports the aggregation of multiple messages into a single network call.

    Note:

    • In WebLogic Server, your synchronous consumers can also use the same efficient behavior as asynchronous consumers by enabling the Prefetch Mode for Synchronous Consumers option on JMS connection factories, as described in Use Prefetch Mode to Create a Synchronous Message Pipeline.

    • WebLogic Server JMS does not support synchronous and asynchronous consumers on the same session.

  • Asynchronous consumers use fewer threads. An asynchronous consumer does not use a thread while it is inactive. A synchronous consumer consumes a thread for the duration of its receive call. As a result, a thread can remain idle for long periods, especially if the call specifies a blocking timeout.

  • For application code that runs on a server, it is almost always best to use asynchronous consumers, typically through MDBs. The use of asynchronous consumers prevents the application code from doing a blocking operation on the server. A blocking operation, in turn, idles a server-side thread; it can even cause deadlocks. Deadlocks occur when blocking operations consume all threads. When no threads remain to handle the operations required to unblock the blocking operation itself, that operation never stops blocking.

For more information, see Receiving Messages Asynchronously using the Classic API and Receiving Messages Synchronously Using the Classic API.

Persistent Vs. Non Persistent Messages

Choose the delivery mode according to the application's failure-recovery requirements.

Use persistent delivery when messages need the provider-failure protection defined by the JMS contract. Nonpersistent delivery can reduce storage I/O but can lose messages on provider failure. Evaluate performance together with the required recovery guarantees; persistent-store write policies also affect those guarantees.

Determine the effective delivery mode as follows:

  1. For the classic API, a newly created MessageProducer receives its initial delivery mode from the connection factory. The default connection-factory value is Persistent. Calling MessageProducer.setDeliveryMode() changes the producer's setting. A delivery-mode argument on an individual send() or legacy publish() call overrides that setting for the call.

  2. For the simplified API, a newly created JMSProducer uses DeliveryMode.PERSISTENT. Use JMSProducer.setDeliveryMode() to change its setting before sending.

  3. The destination's delivery-mode override can force incoming messages to Persistent or Non-Persistent. The default, No-Delivery, leaves the producer's choice unchanged.

  4. When the JMS server's StoreEnabled setting is true, it uses its configured persistent store or, where supported, the hosting WebLogic Server instance's default store. When StoreEnabled is false, persistent sends are rejected unless AllowsPersistentDowngrade is true. If downgrading is allowed, the effective delivery mode becomes nonpersistent.

The DeliveryMode interface defines PERSISTENT and NON_PERSISTENT. The constant Message.DEFAULT_DELIVERY_MODE equals DeliveryMode.PERSISTENT; it does not mean “inherit the connection-factory setting.”

Temporary destinations and nondurable topic subscriptions do not retain messages durably across a JMS server restart. This storage behavior does not itself change the message's JMSDeliveryMode header. Topic messages are retained for eligible subscriptions according to their lifetime, acknowledgement, transaction, expiration, and delivery-mode rules.

To retain durable-subscription metadata across JMS server restarts, keep persistence enabled on the JMS server and use a supported persistent-store configuration, even when the subscription receives only nonpersistent messages.

Note:

Do not infer message delivery mode from persistent-store file growth alone. A store also contains durable-subscription metadata and other persistent service state, and its file size can reflect allocation and reuse.

Deferring Acknowledges and Commits

Processing messages in bounded batches before acknowledging or committing can reduce completion overhead when the application can tolerate batch redelivery after a failure.

Use CLIENT_ACKNOWLEDGE for explicit acknowledgement of non-transacted receives. With the default AcknowledgePolicy of All, acknowledging one message acknowledges all unacknowledged messages consumed by that session. Ensure that all messages covered by the acknowledgement have been processed successfully. For a locally transacted session, use Session.commit() to complete the batch; rollback can cause its received messages to be delivered again. When JTA or a container controls the transaction, use that transaction's completion rules.

Bound each batch by both message count and elapsed time so that a final partial batch can complete. A synchronous consumer on a dedicated session can use a finite receive timeout to detect that no further message has arrived before the batch deadline. Complete the batch on the thread that owns the session, and measure the throughput, latency, memory and redelivery tradeoffs with representative traffic.

Do not use synchronous receives, including receiveNoWait(), on a session with registered message listeners. Do not have a timer thread acknowledge or commit a listener's session. For listener-based processing, select an acknowledgement or transaction boundary that completes successfully processed work without depending on another message arriving.

Acknowledgement Optimization for Nondurable Subscribers

WebLogic JMS can reduce acknowledgement traffic for eligible non-transacted, nondurable topic consumers by maintaining recovery information and handling acknowledgements on the client.

This optimization depends on the consumer and destination settings; it is not used for every nondurable subscription. Redelivery delay, redelivery limits and shared-subscription configuration can affect eligibility. The optimization does not change the application's acknowledgement-mode contract.

Measure throughput and client memory use with representative message sizes, subscriber counts and processing rates. Retained message data and buffered deliveries contribute to heap use and garbage-collection work. Size the client heap and message buffers from those measurements, and verify the result under sustained load and slow-consumer conditions.

Alternative Qualities of Service, Multicast and No-Acknowledge

WebLogic JMS provides alternative qualities of service (QOS) extensions that can help performance.

Using MULTICAST_NO_ACKNOWLEDGE

WLSession.MULTICAST_NO_ACKNOWLEDGE is a WebLogic acknowledgement mode for non-transacted, nondurable subscribers to a topic configured for multicast. Receive these messages asynchronously with a message listener; synchronous receives are not supported in this mode. Multicast can reduce the number of message copies sent by the server when many subscribers receive the same data, but performance and scalability depend on the network and subscriber workload.

Note:

Each multicast session schedules a long-running client socket reader. Account for this thread demand, together with message-listener work, when sizing the JMS client's execution resources.

Multicast delivery can lose messages because of network congestion or client overrun, and duplicate delivery is possible. Session.recover() cannot recover multicast messages, and Message.acknowledge() does not acknowledge them. Use this mode only when the application can tolerate missing and duplicate messages.

Using NO_ACKNOWLEDGE

WLSession.NO_ACKNOWLEDGE is a WebLogic acknowledgement mode for non-transacted sessions. The server does not retain delivered messages for later client acknowledgement, and Session.recover() cannot recover them. This can reduce acknowledgement traffic, but messages can be lost or delivered more than once if delivery fails.

Note:

Closing an asynchronous consumer can discard unprocessed messages already in its client pipeline. In this mode, the server does not retain those messages for redelivery.

A smaller connection-factory MessagesMaximum value can limit the number of buffered messages exposed to loss when a consumer closes or a failure occurs. Measure the throughput tradeoff; reducing the buffer does not make this acknowledgement mode reliable.

Use Sessions from One Thread at a Time

Use a separate Session for each thread that performs messaging concurrently. A session and its producers and consumers must be used serially.

Once a connection is started, a session with registered message listeners is controlled by the message-delivery thread, including between callbacks. The permitted concurrent Session.close() and MessageConsumer.close() operations are exceptions. Adding producers to the same session does not provide additional concurrent execution. Avoid concurrent modification of a Message, and do not reuse a message before an asynchronous send completes. See Threading restrictions on a session and Asynchronous send in the Jakarta Messaging 3.1 specification.

Using the JMSXUserID Property

For ordinary send operations, WebLogic JMS can attach the authenticated sending user's name as the JMSXUserID message property. The connection factory's AttachJMSXUserId setting requests this behavior; the destination's AttachSender setting determines whether to support that request, always attach the name, or never attach it.

Consider the following points when using the JMSXUserID property in your application.

  • JMSXUserID is an optional JMS-defined property. Its population and forwarding rules are provider-specific; do not assume that other providers use the WebLogic rules described here.

  • For an ordinary send, WebLogic JMS derives the value from the authenticated subject used for that send operation. Depending on the client's security configuration, this can be the calling thread's subject or a subject associated with the connection.

  • For an ordinary send, WebLogic JMS clears or replaces an application-supplied JMSXUserID. Setting the message property directly does not select the authenticated identity that WebLogic attaches.

  • JMSXUserID is message metadata, not a cryptographic signature. A TLS-enabled transport such as t3s protects data on that transport connection; it does not establish end-to-end message-origin verification across forwarding intermediaries.

  • WebLogic JMS Store-and-Forward forwarding clears the source message's JMSXUserID before forwarding it.

  • WebLogic Messaging Bridge does not preserve the original sender's identity in JMSXUserID, even when Preserve Message Properties is enabled. Depending on the bridge and target configuration, JMSXUserID can be absent or identify the bridge's authenticated sending user. This applies to both same-domain and cross-domain configurations.

  • The WebLogic WLMessageProducer.forward() extension can preserve a received message's JMSXUserID, subject to the target destination's AttachSender policy. A target configured with AttachSender=Never removes the value.

    Note:

    The JMSXUserID property interoperability behavior for WebLogic JMS clients prior to 9.0 is undetermined.

Performance and Tuning

Implement the performance tuning features available with WebLogic JMS and get the most out of your applications.

See Tuning WebLogic JMS in Tuning Performance of Oracle WebLogic Server.