【问题标题】:Set maximum consumer count jms solace设置最大消费者数量 jms solace
【发布时间】:2019-04-26 01:55:07
【问题描述】:

我正在尝试使用 solace 作为代理设置带有 jms 的主题端点的最大消费者计数,因此为了增加负载,可以在 cloudfoundry 中启动应用程序的多个实例,并且多个订阅者可以消费同一主题的消息.

我尝试了以下设置的多种组合(setConcurrency(), setConcurrentConsumers(), setMaxConcurrentConsumers(),(20 作为任意高数字)。从文档来看,我肯定需要使用 setMaxConcurrentConsumers() 并将其设置为适当的高值。

当我部署应用程序时,会创建主题端点,但是当我查看 solace 管理界面时,最大消费者计数始终为 1(可以在此处看到:Queues -> Topic Endpoints -> select endpoint -> Configured Limit),即使它应该是 20 . 所以第二个消费者是无法连接的。我不想每次部署应用时都手动设置。

import javax.jms.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.listener.DefaultMessageListenerContainer;

@Configuration
public class ProducerConfiguration {

    private static final Log logger = LogFactory.getLog(SolaceController.class);

    @Value("${durable_subscription}")
    private String subscriptionName;

    @Value("${topic_name}")
    private String topic_name;

    @Autowired
    private ConnectionFactory connectionFactory;

    @Bean
    public JmsTemplate jmsTemplate() {
        CachingConnectionFactory ccf = new CachingConnectionFactory(connectionFactory);
        JmsTemplate jmst = new JmsTemplate(ccf);
        jmst.setPubSubDomain(true);
        return jmst;
    }

    @Bean
    public Session configureSession(ConnectionFactory connectionFactory) throws JMSException {
        return connectionFactory.createConnection().createSession(false, Session.AUTO_ACKNOWLEDGE);
    }


    private TextMessage lastReceivedMessage;

    public class SimpleMessageListener implements MessageListener {
        @Override
        public void onMessage(Message message) {

            if (message instanceof TextMessage) {
                lastReceivedMessage = (TextMessage) message;
                try {
                    logger.info("Received message : " + lastReceivedMessage.getText());
                } catch (JMSException e) {
                    logger.error("Error getting text of the received TextMessage: " + e);
                }
            } else {
                logger.error("Received message that was not a TextMessage: " + message);
            }
        }
    }

    @Bean
    public DefaultMessageListenerContainer orderMessageListenerContainer() {

        DefaultMessageListenerContainer lc = new DefaultMessageListenerContainer();
        lc.setConnectionFactory(connectionFactory);
        lc.setDestinationName(topic_name);
        lc.setMessageListener(new SimpleMessageListener());
        lc.setDurableSubscriptionName(subscriptionName);
        lc.setPubSubDomain(true);

        //tried multiple combinations here, also setting only setMaxConcurrentConsumers
        lc.setConcurrency("2-20");
        lc.setConcurrentConsumers(20);
        lc.setMaxConcurrentConsumers(20);

        lc.setSubscriptionDurable(true);
        lc.initialize();
        lc.start();
        return lc;
    }
}

【问题讨论】:

  • 如果你注释掉 setSubscriptionDurable(true) 会改变吗?也许您总是使用相同的订阅名称,而 Solace 不喜欢这样?
  • 刚刚试了一下。在两个应用程序实例的情况下,创建了四个主题端点(同一个主题),这对我来说很好。在日志输出中也没有订阅者无法连接的错误。当然,所有这些都是非持久的,但我需要持久订阅,绝对没有办法解决它。不得丢失任何消息。

标签: java spring jms solace


【解决方案1】:

我认为对于您的用例,您的消费者被队列卡住了。见https://solace.com/blog/topic-subscription-queues/

"... 而多个消费者可以绑定到队列 持久端点仅限于单个主题订阅。队列允许多个主题订阅以及主题通配符。”

如果您不想更改发布者,可以尝试“队列上的主题订阅”。也就是说,可以将队列配置为侦听某个主题。然后您的消费者将从该队列中获取消息。

【讨论】:

  • 所以在四处挖掘之后,我发现这是一个特定于慰藉的功能,因此需要一个特定于慰藉的会话来订阅一个主题的队列......但我正在尝试尽可能与经纪人无关,因此我可以稍后在必要时轻松切换它。不幸的是,我没有在问题中包含这个要求。
  • 是的,与经纪人无关是个好主意。毕竟这是 JMS。那么如何使用队列呢?
  • 但是,如果我有一个消息生产者发布了一些消息并且不想关心将它准确地放在哪个队列中呢?他只想发布它,声明它是关于什么的(主题),订阅这个主题的人就可以抓住它。我说的是一个相当复杂的多服务系统的基础。我认为队列不适合该用例。还是你?
  • 好吧,那么使用非持久主题和事务怎么样?此外,通过交易的出版物和消费,您不会冒丢失消息的风险。
  • 好的,谢谢您的建议。我已经尝试过了,如果我有两个实例,则以两个主题端点结束,并且消息将发送到两个实例,这不是我想要的,我只需要一个实例来接收消息。
【解决方案2】:

您需要创建一个非独占队列/端点。

默认情况下,您创建的队列是独占队列/端点,这意味着任何时候只有一个订阅者可以绑定到它。

创建此类队列/端点的最简单方法是通过 Solace CLI。

要在您的 JMS 程序中创建非独占队列,您必须像这样进入 Solace 特定的 JMS 实现:

    if (queueName != null) {
        EndpointProperties props = new EndpointProperties();
        props.setAccessType(EndpointProperties.ACCESSTYPE_NONEXCLUSIVE);

        try {
            ((SolConnection)connection).getProperties().getJCSMPSession()
                .provision(JCSMPFactory.onlyInstance().createQueue(queueName), props, 0L);
        } catch (Exception e) {
            e.printStackTrace();
        }

        queue = session.createQueue(queueName);
    }

【讨论】:

  • 感谢您的回答。正如问题中所述,一个非常重要的要求是一切都应该以编程方式发生,因此不应涉及 CLI 设置。
  • 我通过进入 JCSMP 创建了一个非排他队列...我将更新上面的答案。
  • 嗨大卫,非常感谢你回来!您能否提供一个完整的代码示例,用于让这个 sn-p 运行?更具体地说:如何将这个新创建的队列连接到我使用问题中的代码创建的主题。另外,我不确定您将哪个 connection 投射到第 6 行中的 SolConnection
猜你喜欢
  • 1970-01-01
  • 2013-12-29
  • 2013-04-16
  • 1970-01-01
  • 2012-07-05
  • 1970-01-01
  • 2011-06-04
  • 2011-10-24
  • 1970-01-01
相关资源
最近更新 更多