将Spring JMSTemplate / ActiveMQ与请求/响应一起使用,而不阻塞队列中的其他消息

时间:2017-04-19 00:44:36

标签: spring jms activemq jmstemplate

我们为特定用例实现了分布式请求/响应类型架构,我们希望等待响应。我们使用的JMS代理是ActiveMq,代码使用Spring连接在一起。

我们看到的问题是,如果将一堆请求发送到同一目的地,任何请求(例如,需要花费大量时间才能完成),则会阻止其后的请求消息。使用者使用的SessionAwareMessageListener接口仅支持onMessage()方法。在这里实现并行性的最佳方法是什么,即如果特定请求需要很长时间,队列中的其他消息不应被阻止?

有这个SO帖子,但它没有回答我的问题。 JMS: Can we get multiple messages from queue in OnMessage() withtout commit or rollback

由于

相关的代码片段(为简洁起见,删除了异常处理等)

生产者

public class MyJmsProducer {

private ProcessingResponse sendMessage(final Serializable serializable) {
    //send JMS request and wait for response
    return jmsMessagingTemplate.convertSendAndReceive(destination, serializable, ProcessingResponse.class); //this operation seems to be blocking + sync
   }
}

听众(消费者)

public class MyJmsListener
    implements SessionAwareMessageListener<Message>, NotificationHandler<Task> {

@Override
public void onMessage(Message message, Session session)
        throws JMSException {
    ProcessingRequest processingRequest = (ProcessingRequest) ((ObjectMessage) message).getObject();

    // handle the request here (THIS COULD TAKE A WHILE)
    handleRequest(processingRequest);


    // done handling the request, now create a response message
    final ObjectMessage responseMessage = new ActiveMQObjectMessage();
    responseMessage.setJMSCorrelationID(message.getJMSCorrelationID());
    responseMessage.setObject(processingResponse);

    // Message sent back to the replyTo address of the income message.
    final MessageProducer producer = session.createProducer(message.getJMSReplyTo());
    producer.send(responseMessage);

  }
}

1 个答案:

答案 0 :(得分:2)

您可以使用DMLC的ConcurrentConsumers来提高消息的消费速度并解决消费者缓慢的问题:

@Bean
public DefaultMessageListenerContainer dmlc() {
    DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
    dmlc.setMaxConcurrentConsumers(10);
    dmlc.setConcurrentConsumers(5);
    return dmlc;
}

您需要将prefetchPolicy调整为Concurrent Consumers:

persistent queues (default value: 1000)
non-persistent queues (default value: 1000)
persistent topics (default value: 100)
non-persistent topics (default value: Short.MAX_VALUE - 1)

将所有消息分派给第一个连接的使用者,当另一个消息连接到同一目标时,他不接收消息,因此要更改此行为,您需要将prefetchPolicy设置为低于默认值的值。例如,将此jms.prefetchPolicy.queuePrefetch=1添加到a​​ctivemq.xml中的uri配置中,或者将其设置在客户端URL上,如下所示

@Bean
public ConnectionFactory connectionFactory() {
    ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
            "tcp://localhost:61616?jms.prefetchPolicy.queuePrefetch=1");
    return connectionFactory;
}
  

建议使用较大的预取值以获得较高的高性能   消息卷。但是,对于较低的消息量,每个消息量   消息需要很长时间才能处理,预取应该设置为1。   这可确保消费者一次只处理一条消息。   但是,将预取限制指定为零将导致使用者   一次一个地轮询消息,而不是消息   推向消费者。

查看http://activemq.apache.org/what-is-the-prefetch-limit-for.html

并且

http://activemq.apache.org/destination-options.html