5

Im having a SpringBoot application which consume my custom serializable message from ActiveMQ Queue. So far it is worked, however, the consume rate is very poor, only 1 - 20 msg/sec.

@JmsListener(destination = "${channel.consumer.destination}", concurrency="${channel.consumer.maxConcurrency}")
public void receive(IMessage message) {
    processor.process(message);
}

The above is my channel consumer class's snippet, it has a processor instance (injected, autowired and inside it i have @Async service, so i can assume the main thread will be released as soon as message entering @Async method) and also it uses springboot activemq default conn factory which i set from application properties

# ACTIVEMQ (ActiveMQProperties)
spring.activemq.broker-url= tcp://localhost:61616?keepAlive=true
spring.activemq.in-memory=true
spring.activemq.pool.enabled=true
spring.activemq.pool.expiry-timeout=1
spring.activemq.pool.idle-timeout=30000
spring.activemq.pool.max-connections=50

Few things worth to inform:
1. I run everything (Eclipse, ActiveMQ, MYSQL) in my local laptop
2. Before this, i also tried using custom connection factory (default AMQ, pooling, and caching) equipped with custom threadpool task executor, but still getting same result. Below is a snapshot performance capture which i took and updating every 1 sec
3. I also notive in JVM Monitor that the used heap keep incrementing

My JVM Monitor Instance

Performance Counter Snapshot


I want to know:
1. Is there something wrong/missing from my steps?I can't even touch hundreds in my message rate
2. Annotated @JmsListener method will execute process async or sync?
3. If possible and supported, how to use traditional sync receive() with SpringBoot properly and ellegantly?

Thank You

Lynx777
  • 332
  • 1
  • 6
  • 17

1 Answers1

2

I'm just checking something similar. I have defined DefaultJmsListenerContainerFactory in my JMSConfiguration class (Spring configuration) like this:

@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(CachingConnectionFactory connectionFactory) {

    // settings made based on https://bsnyderblog.blogspot.sk/2010/05/tuning-jms-message-consumption-in.html
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(){
        @Override
        protected void initializeContainer(DefaultMessageListenerContainer container) {
            super.initializeContainer(container);
            container.setIdleConsumerLimit(5);
            container.setIdleTaskExecutionLimit(10);
        }
    };
    factory.setConnectionFactory(connectionFactory);
    factory.setConcurrency("10-50");
    factory.setCacheLevel(CACHE_CONSUMER);
    factory.setReceiveTimeout(5000L);
    factory.setDestinationResolver(new BeanFactoryDestinationResolver(beanFactory));
    return factory;
}

As you can see, I took those values from https://bsnyderblog.blogspot.sk/2010/05/tuning-jms-message-consumption-in.html. It's from 2010 but I could not find anything newer / better so far.

I have also defined Spring's CachingConnectionFactory Bean as a ConnectionFactory:

@Bean
public CachingConnectionFactory buildCachingConnectionFactory(@Value("${activemq.url}") String brokerUrl) {
    // settings based on https://bsnyderblog.blogspot.sk/2010/02/using-spring-jmstemplate-to-send-jms.html
    ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
    activeMQConnectionFactory.setBrokerURL(brokerUrl);
    CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(activeMQConnectionFactory);
    cachingConnectionFactory.setSessionCacheSize(10);
    return cachingConnectionFactory;
}

This setting will help JmsTemplate with sending.

So my answer to you is set the values of your connection pool like described in the link. Also I guess you can delete spring.activemq.in-memory=true because (based on documentation) in case you specify custom broker URL, "in-memory" property is ignored.

Let me know if this helped.

G.

gabriel
  • 270
  • 4
  • 14