Java Spring AMQP手动容器异常缓慢
使用Spring AMQP DSL并手动创建Java Spring AMQP手动容器异常缓慢,java,spring,spring-amqp,spring-rabbit,Java,Spring,Spring Amqp,Spring Rabbit,使用Spring AMQP DSL并手动创建MessageListenerContainer时,其吞吐量比使用@RabbitListener方法慢得多。据我所知,在使用@RabbitListener时,容器是由BeanPostProcessor创建的,我所做的应该是相同的,但由于某些原因不是这样的。我在下面添加了这两种方法来说明我的意思 我的方法的吞吐量非常慢,使用下面的配置时大约为30/s,而使用注释时,吞吐量非常快。我做错了什么 应用程序属性 spring.rabbitmq.listener
MessageListenerContainer
时,其吞吐量比使用@RabbitListener
方法慢得多。据我所知,在使用@RabbitListener
时,容器是由BeanPostProcessor
创建的,我所做的应该是相同的,但由于某些原因不是这样的。我在下面添加了这两种方法来说明我的意思
我的方法的吞吐量非常慢,使用下面的配置时大约为30/s,而使用注释时,吞吐量非常快。我做错了什么
应用程序属性
spring.rabbitmq.listener.type=direct
spring.rabbitmq.listener.direct.default-requeue-rejected=false
spring.rabbitmq.listener.direct.consumers-per-queue=50
spring.rabbitmq.listener.direct.prefetch=10
DemoConfiguration.java
@Configuration
@EnableRabbit
public class DemoConfiguration {
@Bean
// manually creating the container, VERY slow
public DirectMessageListenerContainer container(final DirectRabbitListenerContainerFactory containerFactory) {
final DirectMessageListenerContainer listenerContainer = containerFactory.createListenerContainer();
listenerContainer.setQueueNames("in_queue"); // has 2.000 messages before starting the application
listenerContainer.setListenerId("listener_in_queue");
return listenerContainer;
}
@Bean
public IntegrationFlow demoFlow(final DirectMessageListenerContainer container) {
return IntegrationFlows.from(Amqp.inboundGateway(container))
// EXTREMELY slow
.nullChannel();
}
// this is working very fast, 1000 messages per second
/*@RabbitListener(queues = "in_queue")
public void consume() {
}*/
}
编辑
问题是您正在使用入站网关,而使用者线程正在等待答复(默认情况下为1秒),而答复永远不会到达 改用
Amqp.inboundAdapter
(或将网关上的replyTimeout
设置为零)
预编辑
我还不知道为什么,但问题似乎出在Spring集成中,而不是容器中:
@SpringBootApplication
public class So54365437Application {
private static final Logger logger = LoggerFactory.getLogger(So54365437Application.class);
public static void main(String[] args) {
SpringApplication.run(So54365437Application.class, args).close();
}
private final AtomicInteger lCount = new AtomicInteger();
private final AtomicInteger mCount = new AtomicInteger();
private final AtomicInteger iCount = new AtomicInteger();
private final AtomicLong t0 = new AtomicLong();
@RabbitListener(queues = "foo")
public void listener(Integer in) {
int n = lCount.incrementAndGet();
if (n % 100 == 0) {
logger.info("listener @" + n);
}
if (n == 2000) {
logger.info("listener done @" + rate());
}
}
@Bean
public DirectMessageListenerContainer container(final DirectRabbitListenerContainerFactory containerFactory) {
final DirectMessageListenerContainer listenerContainer = containerFactory.createListenerContainer();
listenerContainer.setQueueNames("bar");
listenerContainer.setAutoStartup(false);
listenerContainer.setMessageListener(m -> {
int n = mCount.incrementAndGet();
if (n % 100 == 0) {
logger.info("manual @" + n);
}
if (n == 2000) {
logger.info("manual done @" + rate());
}
});
return listenerContainer;
}
@Bean
public DirectMessageListenerContainer integrationContainer(final DirectRabbitListenerContainerFactory containerFactory) {
final DirectMessageListenerContainer listenerContainer = containerFactory.createListenerContainer();
listenerContainer.setQueueNames("baz");
listenerContainer.setAutoStartup(false);
return listenerContainer;
}
@Bean
public IntegrationFlow demoFlow(final DirectMessageListenerContainer integrationContainer) {
return IntegrationFlows.from(Amqp.inboundGateway(integrationContainer).autoStartup(false))
.handle(p -> {
int n = iCount.incrementAndGet();
if (n % 100 == 0) {
logger.info("integration @" + n);
}
if (n == 2000) {
logger.info("integration done @" + rate());
}
})
.get();
}
private String rate() {
return "" + 2000000.0 / ((System.currentTimeMillis() - t0.get())) + "/sec";
}
@Bean
public ApplicationRunner runner(RabbitTemplate template, RabbitListenerEndpointRegistry registry,
DirectMessageListenerContainer container, DirectMessageListenerContainer integrationContainer) {
return args -> {
IntStream.range(0, 2000)
.forEach(i -> {
switch(args.getSourceArgs()[1]) {
case "listener":
template.convertAndSend("foo", i);
break;
case "manual":
template.convertAndSend("bar", i);
break;
case "integration":
template.convertAndSend("baz", i);
break;
}
});
logger.info("All sent; starting container");
t0.set(System.currentTimeMillis());
switch(args.getSourceArgs()[1]) {
case "listener":
registry.start();
break;
case "manual":
container.start();
break;
case "integration":
integrationContainer.start();
break;
}
System.in.read();
};
}
}
及
我已经放置了一个断点,我可以看到我的容器配置了正确的
预取计数。我相信这是正确的,在RabbitAnnotationDrivenConfiguration
中有一个directRabbitListenerContainerFactoryConfigurer
bean,它将属性复制到DirectRabbitListenerContainerFactory
中我用h来创建我的容器。这不是正确的使用方法吗?哦,对不起,我没有注意到你用工厂来创建容器。是的,这是正确的。在这种情况下,我不知道发生了什么;侦听器的容器应该与BPP创建的容器相同。我会看看是否可以复制。问题似乎是要进入Spring集成-尚不确定原因-请参阅我的编辑;我打开了一个。问题是您使用的是网关而不是通道适配器;网关将等待最长1秒(默认情况下)以获得配置中永远不会出现的答复。
listener done @10309.278350515464/sec
manual done @11111.111111111111/sec
integration done @15.578629236413487/sec