Monday, October 6, 2014

JMS performance tuning with WSO2 ESB

Overview

WSO2 ESB can be configured as both a producer and consumer for a JMS broker[1]. As an example ESB can listen to JMS queue(Apache ActiveMQ) consume messages and send them to back end service. It can also be act as JMS producer which can send messages to JMS queue. In this post I am discussing about JMS performance tuning with WSO2 ESB. Performance of JMS service over HTTP can be reduced due to messages are being served by a single threaded JMS listener. There are few ways to address that. These are the steps to tune Performance. 

Preparations


At first You need to follow [2] for optimal ESB and OS level performance.  
Memory configurations are based on your system capability.As an example if you have more than 4GB RAM still you can increase parameters like this. 
-Xms4096m -Xmx4096m -XX:MaxPermSize=2048m 

JMS listener performance 


Step 1 

We can increase the JMS listener performance through concurrent consumers. Please note concurrent consumers are only applicable to JMS queues not for JMS Topics 

Add the following configuration to the Queue Connection Factory properties in JMSListener configuration in axis2.xml. 

<parameter name="transport.jms.ConcurrentConsumers" locked="false">50</parameter> 
<parameter name="transport.jms.MaxConcurrentConsumers" locked="false">50</parameter> 

Step 2

Then another way of improving performance is by adding caching. To enable caching add following parameter to the Queue Connection Factory properties. 

<parameter name="transport.jms.CacheLevel">consumer</parameter> 

Preferred values for the cache level are none, auto, connection, session and consumer. "consumer" is the highest level which provides maximum performance. So after adding concurrency consumers and cache level your complete configuration would look like as given below. 

   <transportReceiver name="jms" class="org.apache.axis2.transport.jms.JMSListener"> 
        <parameter name="myTopicConnectionFactory" locked="false"> 
        <parameter name="java.naming.factory.initial" locked="false">org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter> 
        <parameter name="java.naming.provider.url" locked="false">tcp://localhost:61616&lt;/parameter> 
        <parameter name="transport.jms.ConnectionFactoryJNDIName" locked="false">TopicConnectionFactory</parameter> 
<parameter name="transport.jms.ConnectionFactoryType" locked="false">topic</parameter> 

        </parameter> 

        <parameter name="myQueueConnectionFactory" locked="false"> 
        <parameter name="java.naming.factory.initial" locked="false">org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter> 
        <parameter name="java.naming.provider.url" locked="false">tcp://localhost:61616&lt;/parameter> 
        <parameter name="transport.jms.ConnectionFactoryJNDIName" locked="false">QueueConnectionFactory</parameter> 
<parameter name="transport.jms.ConnectionFactoryType" locked="false">queue</parameter> 
<parameter name="transport.jms.ConcurrentConsumers" locked="false">50</parameter> 
<parameter name="transport.jms.MaxConcurrentConsumers" locked="false">50</parameter> 
<parameter name="transport.jms.CacheLevel">consumer</parameter> 
        </parameter> 

        <parameter name="default" locked="false"> 
        <parameter name="java.naming.factory.initial" locked="false">org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter> 
        <parameter name="java.naming.provider.url" locked="false">tcp://localhost:61616&lt;/parameter> 
        <parameter name="transport.jms.ConnectionFactoryJNDIName" locked="false">QueueConnectionFactory</parameter> 
<parameter name="transport.jms.ConnectionFactoryType" locked="false">queue</parameter> 
  <parameter name="transport.jms.ConcurrentConsumers" locked="false">50</parameter> 
          <parameter name="transport.jms.MaxConcurrentConsumers" locked="false">50</parameter> 
<parameter name="transport.jms.CacheLevel">consumer</parameter> 
        </parameter> 

    </transportReceiver> 

I have enable security as you can see additional parameter as follows in my axis2.xml .So You can remove those if you haven't enable security in ActiveMQ. 

        <parameter name="transport.jms.UserName">system</parameter> 
     <parameter name="transport.jms.Password">manager</parameter> 
     <parameter name="java.naming.security.principal">JMSUSERID</parameter> 
     <parameter name="java.naming.security.credentials">manager</parameter> 

JMS Sender performance


Additionally to further optimize the performance of JMSSender you can just add , 

<parameter name="transport.jms.CacheLevel">producer</parameter> 

Make sure to add JMS destination which is a mandatory parameter when adding "producer" cache level. 
ex. 
<parameter name="transport.jms.Destination" locked="false">dynamicQueues/SimpleStockQuoteService</parameter> 

Then your new configuration for JMSSender would look like as given bellow, 

   <transportSender name="jms" class="org.apache.axis2.transport.jms.JMSSender">
<parameter name="myQueueConnectionFactory" locked="false"> 
              <parameter name="java.naming.factory.initial" locked="false">org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter> 
              <parameter name="java.naming.provider.url" locked="false">tcp://localhost:61616&lt;/parameter> 
              <parameter name="transport.jms.ConnectionFactoryJNDIName" locked="false">QueueConnectionFactory</parameter> 
              <parameter name="transport.jms.ConnectionFactoryType" locked="false">queue</parameter> 
            <parameter name="transport.jms.Destination" locked="false">dynamicQueues/SimpleStockQuoteService</parameter> 
              <parameter name="transport.jms.DestinationType" locked="false">queue</parameter> 
<parameter name="transport.jms.ReplyDestination" locked="false">dynamicQueues/SimpleStockQuoteServiceReply</parameter> 
              <parameter name="transport.jms.CacheLevel" locked="false">producer</parameter> 
      </parameter> 
</transportSender> 

You need to specify Connection Factory in your endpoint as follows. 

    <endpoint> 
         <address uri="jms:/?transport.jms.ConnectionFactory=myQueueConnectionFactory"/> 
      </endpoint> 

Preferred values for the cache level are none, auto, connection, session and producer. Maximum cache level is “producer”. 
In case you have multiple queues, setting up default Connection Factory won't work. Because all the JMS endpoints will share the same destination queue. So what you need to do is to define connection factory per JMS endpoint basis in axis2.xml and make use of that JMS connection factory definition in the JMS endpoint as follows. 

    <endpoint> 
         <address uri="jms:/?transport.jms.ConnectionFactory=myQueueConnectionFactory1"/> 
      </endpoint> 
<endpoint> 
         <address uri="jms:/?transport.jms.ConnectionFactory=myQueueConnectionFactory2"/> 
      </endpoint> 

[1]https://docs.wso2.com/display/ESB481/Java+Message+Service+%28JMS%29+Support
[2]https://docs.wso2.com/display/ESB481/Performance+Tuning  

No comments :

Post a Comment