Lukas Eder
Lukas Eder

Reputation: 220797

JMS performance

I'm having a bit of trouble with understanding JMS from a performance perspective. We have this very straightforward code in our application:

QueueConnection connection = null;
QueueSession session = null;
QueueSender sender = null;
TextMessage msg = null;

try {
  // The JNDIHelper uses InitialContext to look up things
  QueueConnectionFactory qcf = JNDIHelper.lookupFactory();
  Queue destQueue = JNDIHelper.lookupQueue();

  // These objects are created for every message, which is quite slow
  connection = qcf.createQueueConnection();
  session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
  sender = session.createSender(destQueue);

  // This is the actual message
  msg = session.createTextMessage(xmlMsg);
  sender.setTimeToLive(0);
  sender.send(msg);
} 
finally {

  // Close all objects again
  JMSUtilities.safeClose(sender);
  JMSUtilities.safeClose(session);
  JMSUtilities.safeClose(connection);
}

The code is correct, but probably some of the above artefacts could be reused for several messages. These are our configurations:

My questions

Upvotes: 20

Views: 10561

Answers (3)

SpaceTrucker
SpaceTrucker

Reputation: 13556

Here are some relevant parts of the jms spec:

section 2.8 Multithreading

JMS Object          Supports Concurrent Use
Destination         YES
ConnectionFactory   YES
Connection          YES [1]
Session             NO
MessageProducer     NO
MessageConsumer     NO

section 4.4.14 Serial Execution of Client Code

JMS does not cause concurrent execution of client code unless a client explicitly requests it. One way this is done is to define that a session serializes all asynchronous delivery of messages

So as already mentioned reuse as much as possible. Reuse the ConnectionFactory, Connection and Destinations for all Threads. For each Thread reuse consumers and producers.

If you are reusing a JMS connection beware, that the JMS Provider will multiplex different sessions on that connections. So even if it is safe to reuse connections it might be faster to create a connection for every session you need.

  1. as of jakarta messaging 3.0 (or possibly earlier) with some restrictions, see jakarta messaging 3.0 spec

Upvotes: 16

lzap
lzap

Reputation: 17174

Define "to share".

If you mean to share among different threads this is very dangerous. You can safely share QueueConnectionFactory object as well as the JMS Connection object. You must not share Session, Sender/Consumer or Message objects. Thats the way how TIBCO EMS works I am not sure about IBM platform but I guess this is very same.

If you can be sure your "send" method is not called by different threads you can encapulate this into a MySender class with Connection, Session and Sender member variables. But watch out! Do properly close the resources on exit. Thats what Heiko Rupp recommends. Somthing like this:

class MySender {
    private QueueConnection connection = null;
    private QueueSession session = null;
    private QueueSender sender = null;

    public MySender(...) { /* initialize conn/sess/sender */ }

    public send(String xmlMsg) { /* sender.send(session.createTextMessage(xmlMsg)) */ }

    public close() { /* close all resources */ }
}

Regarding performance. There is no much room for improvement in JMS standard. Keep messages small and optimize server setting. Use durable destinations only when you need it etc. Read documentation for your platform. But on the client side there is not much room. Some platforms offers additional features to JMS that allows some extra performance gain (batch sends etc) but it depends on the platform. I dont know IBM.

Upvotes: 3

Heiko Rupp
Heiko Rupp

Reputation: 30934

The only thing you need to create again and again is the msg itself - if you are sending to the same queue.

So yes, you can remember the Connection, Session and Sender.

Upvotes: 10

Related Questions