Monday 26 October 2009

JMS: Reliable and robust applications - Part 2



1. Introduction
This post explains how to use features of the JMS API to achieve the level of reliability and performance your application requires. All this content is taken from my summaries based on the specification.

2.     Basic Reliability Mechanisms

2.1 Controlling Message Acknowledgment
Until a JMS message has been acknowledged, it is not considered to be successfully consumed; this ordinarily takes place in three steps.

1. The client receives the message.
2. The client processes the message.
3. The message is acknowledged. Acknowledgment is initiated either by the JMS provider or by the client, depending on the session acknowledgment mode.

Let’s pay attention in the following:
      
QueueSession createQueueSession(boolean transacted, int acknowledgeMode)                               
         throws JMSException
TopicSession createTopicSession(boolean transacted, int acknowledgeMode)
          throws JMSException


If the first parameter is true, the session is transacted and the acknowledgment happens automatically when a transaction is committed. If a transaction is rolled back, all consumed messages are redelivered.

If the first parameter is false, the session is nontransacted and the value in the parameter acknowledgeMode indicates whether the consumer or the client will acknowledge any messages it receives, ignored if the session is transacted.

Session.AUTO_ACKNOWLEDGE. The session automatically acknowledges a client’s receipt of a message either when the client has successfully returned from a call to receive or when the MessageListener it has called to process the message returns successfully. A synchronous receive in an AUTO_ACKNOWLEDGE session is the exception to the rule that message consumption is a three-stage process. In this case, the receipt and acknowledgment take place in one step, followed by the processing of the message.

Session.CLIENT_ACKNOWLEDGE. A client acknowledges a message by calling the message’s acknowledge method. In this mode, acknowledgment takes place on the session level: Acknowledging a consumed message automatically acknowledges the receipt of all messages that have been consumed by its session. For example, if a message consumer consumes ten messages and then acknowledges the fifth message delivered, all ten messages are acknowledged.

Session.DUPS_OK_ACKNOWLEDGE. This option instructs the session to lazily acknowledge the delivery of messages. This is likely to result in the delivery of some duplicate messages if the JMS provider fails, so it should be used only by consumers that can tolerate duplicate messages. This option can reduce session overhead by minimizing the work the session does to prevent duplicates.

If messages have been received but not acknowledged when a QueueSession terminates, the JMS provider retains them and redelivers them when a consumer next accesses the queue. The provider also retains unacknowledged messages for a terminated TopicSession with a durable TopicSubscriber. Unacknowledged messages for a nondurable TopicSubscriber are dropped when the session is closed.

2.2  Specifying Message Persistence
The JMS API supports two delivery modes for messages to specify whether messages are lost if the JMS provider fails. These delivery modes are fields of the javax.jms.DeliveryMode interface.

• The PERSISTENT delivery mode (by default), instructs the JMS provider to take extra care to ensure that a message is not lost in transit in case of a JMS provider failure. A message sent with this delivery mode is logged to stable storage when it is sent.

• The NON_PERSISTENT delivery mode does not require the JMS provider to store the message or otherwise guarantee that it is not lost if the provider fails. This mode may improve performance and reduce storage overhead, but you should use it only if your application can afford to miss messages.
      
2.3 Setting Message Priority Levels
You can use message priority levels (0 lowest to 9 highest, 4 default) to instruct the JMS provider to deliver urgent messages first. You can set the priority level in either of two ways.

2.4 Allowing Messages to Expire
By default, a message never expires. If a message will become obsolete after a certain period, however, you may want to set an expiration time. You can do this in either of two ways.

2.5 Creating Temporary Destinations
The JMS API enables you to create destinations:

QueueSession.createTemporaryQueue

TopicSession.createTemporary

They last only for the duration of the connection in which they are created. The only message consumers that can consume from a temporary destination are those created by the same connection that created the destination. Any message producer can send to the temporary destination. If you close the connection that a temporary destination belongs to, the destination is closed and its contents lost.

You can use temporary destinations to implement a simple request/reply mechanism (see JMSReplyTo, JMSCorrelationID, JMSMessageID).

3.     Advanced Reliability Mechanisms

3.1 Creating Durable Subscriptions
To make sure that a pub/sub application receives all published messages, use PERSISTENT delivery mode for the publishers. In addition, use durable subscriptions for the subscribers.

The TopicSession.createSubscriber method creates a nondurable subscriber and can receive only messages that are published while it is active.







The TopicSession.createDurableSubscriber method creates a durable subscriber. A durable subscription can have only one active subscriber at a time.








A durable subscriber registers a durable subscription with a unique identity that is retained by the JMS provider. Subsequent subscriber objects with the same identity resume the subscription in the state in which it was left by the previous subscriber. If a durable subscription has no active subscriber, the JMS provider retains the subscription’s messages until they are received by the subscription or until they expire.
You establish the unique identity of a durable subscriber by setting the following:

• A client ID for the connection
• A topic and a subscription name for the subscriber

With a durable subscriber, the subscriber can be closed and recreated, but the subscription continues to exist and to hold messages until the application calls the unsubscribe method.

3.2 Using JMS API Local Transactions
You can group a series of operations together into an atomic unit of work called a transaction. If any one of the operations fails, the transaction can be rolled back, and the operations can be attempted again from the beginning. If all the operations succeed, the transaction can be committed.

In a JMS client, you can use local transactions to group message sends and receives. The JMS API Session interface provides commit and rollback methods that you can use in a JMS client. A transaction commit means that all produced messages are sent and all consumed messages are acknowledged. A transaction rollback means that all produced messages are destroyed and all consumed messages are recovered and redelivered unless they have expired.

A transacted session is always involved in a transaction. As soon as the commit or the rollback method is called, one transaction ends and another transaction begins. Closing a transacted session rolls back its transaction in progress, including any pending sends and receives.






In an Enterprise JavaBeans component, you cannot use the Session.commit and Session.rollback methods. Instead, you use distributed transactions.

You can combine several sends and receives in a single JMS API local transaction. If you do so, you need to be careful about the order of the operations. You will have no problems if the transaction consists of all sends or all receives or if the receives come before the sends. But if you try to use a request-reply mechanism, whereby you send a message and then try to receive a reply to the sent message in the same transaction, the program will hang, because the send cannot take place until the transaction is committed. Because a message sent during a transaction is not actually sent until the transaction is committed, the transaction cannot contain any receives that depend on that message’s having been sent.

It is also important to note that the production and the consumption of a message cannot both be part of the same transaction. The reason is that the transactions take place between the clients and the JMS provider, which intervenes between the production and the consumption of the message.

Another way of putting this is that the act of producing and/or consuming messages in a session can be transactional, but the act of producing and consuming a specific message across different sessions cannot be transactional.

Because the commit and the rollback methods for local transactions are associated with the session, you cannot combine queue and topic operations in a single transaction.
You can, however, receive from one queue and send to another queue in the same transaction, assuming that you use the same Queue-Session to create the QueueReceiver and the QueueSender. You can pass a client program’s session to a message listener’s constructor function and use it to create a message producer, so that you can use the same session for receives and sends in asynchronous message consumers.

3 comments:

  1. nene, y en cuanto a las implementaciones? ActiveMQ ? MQ series de IBM ?

    ya te podrías currar unas comparativas de rendimiento, no? :D

    ReplyDelete
  2. I have no time mate!
    Ummm Why dont you do that?

    ReplyDelete
  3. I would like, but my time is not for implementing that stuf. I need time to work out my books.

    But a work I think I am going to do a comparsion between Eclipselink and hibernate with JPA1.

    And offffff course, I would like to share it with you mates!!

    regards from home.

    ReplyDelete