Monday, February 2, 2009

JMS Reliability

This article revisited the JMS reliability and looked at the API provided parameters and their implications.

The JMS provides APIs to specify reliability for message producers and message consumers. The reliability consists of two separate contracts:
  • the contract between a producer and the messaging provider.
  • the contract between a consumer and the messaging provider.
The two contracts are essentially independent to each other. A message producer has no control over how a message is consumed and acknowledged. Similarly, a message consumer has no control over how messages are produced to a destination from which they are consumed.

To achieve end-to-end reliability, an application should be aware of both contracts and choose an appropriate configuration fits the application. The end-to-end reliability means the same message is produced exactly once and be received by a consumer exactly once.

1. Producing message reliably.

A message producer can specify the following parameters when producing a message to a destination. These parameters can affect message reliability if not used properly.
  • time-to-live
  • delivery-mode
  • message-priority
1.1 Time-To-Live.

The API Javadoc says as follows for the MessageProducer's setTimeToLive() API.

"Sets the default length of time in milliseconds from its dispatch time that a produced message should be retained by the message system."

For time-to-live to work reliably, a messaging provider may require to synchronize the clock among the messaging server and the messaging client runtime (applications). The implementation is vendor dependent and a vendor may choose not to synchronize the clock and assume this is a user's responsibility.

Applications should always use the default time-to-live value (0, never expire) if clock synchronization can not be guaranteed. Messages could be expired unexpected if clocks are not synchronized between client(s) and the messaging server(s).

1.2 Message Priority

Below is quoted from JMS API JavaDoc.

"The JMS API defines ten levels of priority value, with 0 as the lowest priority and 9 as the highest. Clients should consider priorities 0-4 as gradations of normal priority and priorities 5-9 as gradations of expedited priority. Priority is set to 4 by default."

In practice, the message priority should be treated as a hint only. Setting a high priority for a message may not guarantee the message be delivered before a lower priority message sent earlier. There are many factors may affect this. For example, a previous sent message (with lower priority) may already in transition to be delivered to a consumer. A high priority message produced at a later time may not be jump ahead and deliver to a consumer in a predictable way. The behavior is vendor dependent and should be used with caution.

1.3 Delivery Mode.

An application should produce non-persistent messages only if messages are allowed to be lost when a system failed (hardware or software).

An application should use a transacted session to produce persistent messages for maximum reliability. When Session.commit() is called, a messaging provider SHOULD sync the produced messages to its persistent repository to avoid message loss should a system failure occurred. It is consider a messaging provider's bug if a sync operation is not enforced when commit() returned successfully.

2. Consuming message reliably.

This section assumes that messages were produced reliably to a destination as discussed in the above section.

Message consumption reliability are controlled by the session acknowledge mode or if a transacted session is used.

A message lost is defined as follows.

"A message was produced reliably to a destination as per JMS specification (such as sending a persistent message to a queue in a transacted session) but was never seen by the message consumer attached to the same destination."

The reliability for various session acknowledge modes are discussed as follows.

2.1 asynchronous consumption (message listener) with auto-acknowledge session.

At most one message can be redelivered when a system failure occurred. No messages can be lost when a system failure occurred.

2.2 synchronous consumption with auto-acknowledge session.

According to the JMS reference implementation, at most one message can be lost when a system failure occurred.

2.3 dups-ok-acknowledge.

Multiple messages could be redelivered when a system failure occurred. At most one message could be lost for a synchronous receive consumer.

2.4 client-acknowledge session.

Messages consumed but not acknowledged are re-delivered when a system failure occurred. No messages can be lost when a system failure occurred.

2.5 transacted session.

Message consumed but not committed are re-delivered when a system failure occurred. No messages can be lost when a system failure occurred.

For a standard JMS implementation, transacted session and client-acknowledged session could have the same reliability. But when applications are deployed in a system with a highly-available feature, a transacted session could receive a better reliability due to the possibility that the provider may implement a 2-phase commit protocol for a transacted session. In this case, there would be less possibility for any message redelivery in a transacted session.

No comments:

Post a Comment