tags:

views:

40

answers:

2

I have a JMS queue with a gazillion messages to be processed. I'm going to have a good few listeners that I'm implementing using spring-jms to read from this queue.

I'm getting a bit lost on the different ListenerContainers and their possible configurations. My requirements are:

  • Obviously asynchronous processing.
  • No need for transactions, I can afford losing some messages if something fails.
  • I need raw speed!
  • I'm using ActiveMQ as the broker.

Anybody has a suggestion on the ListenerContainer to use and a configuration in terms of number of JMS sessions, threads, etc.

Machine would have 8 cores, plenty of RAM.

+3  A: 

Unless you have a specific reason to do otherwise, you should use DefaultMessageListenerContainer. This is the most flexible in terms of performance and configuration. In contrast, SimpleMessageListenerContainer is a bit too simple to be of practical use.

I can't advise you on the number of concurrent consumers to set up, since that depends entirely on your setup.

skaffman
Edited the question to specify the machine that would be running it.
Iker Jimenez
@Iker: Start with 8 cores, then, benchmark it, then try increasing or decreasing that number to see if it improves things.
skaffman
+1  A: 

I would look into using Spring Integration. It makes setting up JMS based applications really easy.

    <bean id="commandQueue" class="org.apache.activemq.command.ActiveMQQueue">
            <constructor-arg value="queue.command"/>
    </bean>

    <jms:message-driven-channel-adapter
    id="jmsin" destination="commandQueue" channel="commandChannel" />

    <int:channel id="commandChannel" />

So in the XML chunk above, you create a "channel" which is an abstract queue concept. You define your JMS queue as normal, and then you just define an adapter.

    <service-activator input-channel="commandChannel" 
           ref="commandWatcher" method="processCommand">
    <poller task-executor="pool">
        <interval-trigger interval="100"/>
    </poller>
</service-activator>

<bean id="commandWatcher" class="foo.bar.Pojo" scope="prototype"/>

    <bean id="pool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
 <property name="corePoolSize" value="8" />   
     </beans:bean>

So, the code above just defines a 'service activator', which means that every 100ms, it's looking to see if there are messages on the queue. It then pulls that message and processes it on a threadpool by passing the message to a POJO. You define a simple method and it can take the payload as a String, or if you have it as a Serialized object, you can have it be that. If you need more semantics like headers, you can use annotations and get the headers as a Map.

This makes the JMS stuff about as painless as it gets...

jcalvert
How is this different from using DefaultMessageListenerContainer and setting concurrentConsumers and maxConcurrentConsumers to some sensible values?It looks to me that it is going to add more configuration complexity to end up doing a similar thing. I'm just trying to understand.
Iker Jimenez
I think it makes more sense constructed that way, but it's not terribly different. One thing that I particularly like is not dealing with MessageListenerAdapters.
jcalvert