Announcement Announcement Module
Collapse
No announcement yet.
JdbcMessageStore addMessageToGroup and removeMessageFromGroup performance Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • JdbcMessageStore addMessageToGroup and removeMessageFromGroup performance

    Hi,

    I have implemented a scenario using Spring Integration 2.0.1 that utilizes a queue channel backed by a persistent message store, using the Spring provided JdbcMessageStore implementation with an Oracle database.

    Below is an overview of my implementation:
    1) JMS event driven adapter consuming from a WebLogic JMS queue, delivering the message onto a direct channel.
    2) Content based router (xpath router) that will route to one of two possible direct channels (A or B).
    3) Xpath splitter consuming from channel A, splits the single message into multiple and sends each message onto the database persisted queue channel.
    For the purpose of describing the problem, the alternate path on the B channel is not relevant.
    4) Consumer will read messages from the queue channel and perform necessary action.

    Below is the relevant part of the application context:
    Code:
    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
            <property name="jndiTemplate" ref="jndiTemplate"/>
            <property name="jndiName" value="${jndi.db.msg.store.datasource}"/>
            <property name="expectedType" value="javax.sql.DataSource"/>
        </bean
    
        <bean id="oracleLobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler"/>
    
        <int-jdbc:message-store id="messageStore" region="${jdbc.message.store.region}" data-source="dataSource" lob-handler="oracleLobHandler"/>
    
        <int:channel id="downStreamChannel">
            <int:queue message-store="messageStore"/>
        </int:channel>
    During performance testing where a single message is broken down into over 2000 individual messages that will be persisted on the queue channel, I have noticed a gradual increase in time taken to perform the database insert. After digging into the code through the debugger, I extracted the following call stack:
    Code:
    org.springframework.jms.listener.DefaultMessageListenerContainer#0-1@9, prio=5, in group 'Pooled Threads', status: 'RUNNING'
    	  at org.springframework.integration.jdbc.JdbcMessageStore.	(JdbcMessageStore.java:295)
    	  at org.springframework.integration.store.MessageGroupQueue.offer(MessageGroupQueue.java:86)
    	  at org.springframework.integration.store.MessageGroupQueue.put(MessageGroupQueue.java:176)
    	  at org.springframework.integration.store.MessageGroupQueue.put(MessageGroupQueue.java:37)
    	  at org.springframework.integration.channel.QueueChannel.doSend(QueueChannel.java:79)
    	  at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:157)
    	  ...
    	  at org.springframework.integration.core.MessagingTemplate.doSend(MessagingTemplate.java:288)
    	  at org.springframework.integration.core.MessagingTemplate.send(MessagingTemplate.java:149)
    	  at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.sendMessage(AbstractReplyProducingMessageHandler.java:176)
    	  at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.sendReplyMessage(AbstractReplyProducingMessageHandler.java:160)
    	  at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.produceReply(AbstractReplyProducingMessageHandler.java:125)
    	  at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleResult(AbstractReplyProducingMessageHandler.java:115)
    	  at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:101)
    	  at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
    	  at org.springframework.integration.monitor.SimpleMessageHandlerMetrics.handleMessage(SimpleMessageHandlerMetrics.java:108)
    	  ...
    	  at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:947)
    	  at java.lang.Thread.run(Thread.java:662)
    Stepping through the call stack I was able to identify that the increasing lag was in the addMessageToGroup call in the JdbcMessageStore.
    Code:
    	public MessageGroup addMessageToGroup(Object groupId, Message<?> message) {
    
    		final long createdDate = System.currentTimeMillis();
    		final String messageId = getKey(message.getHeaders().getId());
    		final String groupKey = getKey(groupId);
    		final byte[] messageBytes = serializer.convert(message);
    
    		jdbcTemplate.update(getQuery(CREATE_MESSAGE_IN_GROUP), new PreparedStatementSetter() {
    			public void setValues(PreparedStatement ps) throws SQLException {
    				logger.debug("Inserting message with id key=" + messageId + " and created date=" + createdDate);
    				ps.setString(1, messageId);
    				ps.setString(2, region);
    				ps.setTimestamp(3, new Timestamp(createdDate));
    				ps.setString(4, groupKey);
    				lobHandler.getLobCreator().setBlobAsBytes(ps, 5, messageBytes);
    			}
    		});
    
    		return getMessageGroup(groupId);
    
    	}
    The reason for the lag as highlighted above is that after every insert, the full set of persisted messages is fetched and returned. As over 2000 inserts are performed in sequence, the amount of data coming back and being processed increases each iteration, thus causing the whole process to gradually slow down. On average, it resulted in individual inserts being processed at around 345 milliseconds per request. Reviewing the usages of the addMessageToGroup method, I am guessing this was done for use by correlating handlers, however in other cases like the MessageGroupQueue handler it is an unnecessary step that affects performance.

    I've also noticed that the same approach is taken with the removeMessageFromGroup method.

    Can someone please elaborate on the reasoning for this design decision and whether it would be better to perform the fetch only when required?

    Thanks,
    Luka

  • #2
    Can you please upgrade to 2.2.M2. I understand that you may not officially rely on the milestone build but there were some significant improvements doen to the JdbcMessageStore to address the exact issue you are describing. And another user has already validated it so it would be nice to get another validation from you.
    Please let us know.
    Thanks

    Comment

    Working...
    X