Распределение нагрузки Spring JMS с одним производителем и одним Concumer
Я так долго исследовал балансировку нагрузки JMS. Мы можем создать несколько производителей и несколько потребителей для балансировки нагрузки JMS-сообщений. Но я хочу понять, как мы можем сбалансировать JMS-сообщения с одним производителем и одним потребителем. Я не могу добавить больше зависимостей в мой проект, как Apache Camel.
@Configuration
@EnableJms
@ComponentScan({"com.jmsloadbalance.jms"})
@Bean
public class JmsConfig {
public JmsTemplate getJmsTemplate() {
JmsTemplate template = new JmsTemplate();
template.setConnectionFactory(connectionFactory());
template.setDefaultDestination(new ActiveMQQueue("default.topic");
template.setExplicitQosEnabled(true);
template.setDeliveryPersistent(false);
template.setTimeToLive(60000);
template.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);
template.setMessageConverter(getMessageConverter());
return template;
}
@Bean
public DefaultJmsListenerContainerFactory defaultJmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setPubSubDomain(false);
factory.setDestinationResolver(new DynamicDestinationResolver());
factory.setConcurrency("1");
factory.setMessageConverter(getMessageConverter());
return factory;
}
private ActiveMQConnectionFactory connectionFactory() {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
factory.setBrokerURL("vm://localhost");
return factory;
}
private MessageConverter getMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTypeIdPropertyName("JMSType");
return converter;
}
}
Это мой класс JmsConfig, где я не могу вносить большие изменения в конфигурацию, например, вводить больше JMSTemplate или больше ConnectionFactory. Мой продюсер выглядит ниже
@Service("accountJmsProducer")
public class AccountJmsProducer {
private static Logger LOG = Logger.getLogger(AccountJmsProducer.class);
@Autowired
private JmsTemplate template;
private Destination destination;
public Account create(Account account) {
if (this.destination == null) {
this.destination = new ActiveMQQueue("account.create");
}
template.convertAndSend(destination, account);
return null;
}
}
Мой потребитель выглядит так:
@Service("accountJmsConsumer")
public class AccountJmsConsumer {
private static final Logger LOG = Logger.getLogger(AccountJmsConsumer.class);
@Autowired
@Qualifier("accountService")
private AccountService accountService;
private Account lastReceived;
@JmsListener(containerFactory = "defaultJmsListenerContainerFactory", destination = "account.create")
public Account create(Account account) {
LOG.warn("Received " + account);
setLastReceived(account);
return accountService.create(account);
}
public synchronized Account getLastReceived() {
return lastReceived;
}
public synchronized void setLastReceived(Account lastReceived) {
this.lastReceived = lastReceived;
}
}
1 ответ
Непонятно, что вы подразумеваете под балансировкой нагрузки, когда есть один потребитель, но на основании вашего комментария к моему комментарию на ваш вопрос:
Пока пункт назначения является очередью (а не темой), и это подразумевается, поскольку у вас есть factory.setPubSubDomain(false)
тогда это будет просто работать. Это часть контракта JMS. Если в одной очереди несколько потребителей, сообщения будут распределены между этими потребителями; только один потребитель получит конкретное сообщение.
Если доставка не удалась, она может быть или не быть доставлена тому же потребителю.
Большинство брокеров (включая ActiveMQ) предлагают какой-то механизм предварительной выборки. IIRC, с ActiveMQ это 1000 по умолчанию. Если у вас меньше сообщений, чем один, то один потребитель может быть бездействующим; если так, уменьшите предварительную выборку, чтобы настроить распределение.