Spring boot 读兔子mq的速度非常慢
我有一个作业,它必须从Spring boot 读兔子mq的速度非常慢,spring-boot,rabbitmq,spring-batch,spring-rabbit,Spring Boot,Rabbitmq,Spring Batch,Spring Rabbit,我有一个作业,它必须从rabbitmq队列读取数据并将其写入数据存储。目前我正在使用AmqpItemReader从队列中读取消息 我读取的数据是Json格式的,我的ItemProcessor所做的就是将Json序列化为java对象 我的单线程解决方案的性能非常低。我只能以每秒12毫秒的速度消费。我将有大约1000万条记录需要处理。因此,我尝试将其更改为多线程步骤,但仍然无法看到吞吐量的显著提高(约为每秒50毫秒) 我将如何加快我的工作。我开始怀疑我走的路线不对。如能对此有所了解,将不胜感激。提前
rabbitmq
队列读取数据并将其写入数据存储。目前我正在使用AmqpItemReader
从队列中读取消息
我读取的数据是Json格式的,我的ItemProcessor
所做的就是将Json
序列化为java对象
我的单线程解决方案的性能非常低。我只能以每秒12毫秒的速度消费。我将有大约1000万条记录需要处理。因此,我尝试将其更改为多线程步骤,但仍然无法看到吞吐量的显著提高(约为每秒50毫秒)
我将如何加快我的工作。我开始怀疑我走的路线不对。如能对此有所了解,将不胜感激。提前谢谢
编辑:包括代码/配置,以进一步明确我要实现的目标。
Rabbit服务器配置:
AWS上的3节点群集,每个群集具有0.5 Gig内存
信息详情:
每个有效负载大约为1千字节JSON
我正在我的开发机器(Macintosh)上运行spring批处理作业
系统配置:
Processor Name: Intel Core i7
Processor Speed: 2.5 GHz
Number of Processors: 1
Total Number of Cores: 4
L2 Cache (per Core): 256 KB
L3 Cache: 6 MB
Memory: 16 GB
我的项目阅读器:
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.batch.item.amqp.AmqpItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class RabbitMQItemReader extends AmqpItemReader<Message> {
private final Logger logger = LoggerFactory.getLogger(RabbitMQItemReader.class);
@Autowired
private final RabbitTemplate template;
public RabbitMQItemReader(RabbitTemplate rabbitTemplate) throws IOException {
super(rabbitTemplate);
template = rabbitTemplate;
}
@Override
public Message read() {
return template.receive();
}
}
如果其他配置/代码有帮助,请告诉我,我也很乐意与大家分享。嗯,
amqpmetplate.receive()
肯定非常慢。它基于Channel.basicGet()
,它的性能不如长寿BasicConsumer
。我建议放弃AmqpItemReader
,转而使用Spring AMQ提供的MessageListenerContainer
预回迁您已经写了一个很好的投诉-但是,为了让任何人帮助您,如果您至少提供一些技术细节,可能会很好。这可能包括机器配置、兔子配置、消息大小、,以及任何其他相关细节。@我添加了配置和一点代码(如果有帮助的话)。我需要在这里澄清一些事情-基本上,Basic.Get在协议级别发送与Basic.Deliver相同的数据-因此,如果速度较慢,这一定是客户端实现的产物。实际上,拉取消息要比推送消息明智得多,除非您只是将RMQ用作一个奇特的路由器。AmqpItemReader
基于rabbitmplate.receive()
。打开频道
,创建默认消费者
,执行basicConsume()
,等待交付
并按倒序关闭所有内容。因此,是的,从技术上讲,我们也是这样做的,但是在ListenerContainer
的情况下,我们经常这样做。通过rabbitmplate.receive()
我们为每个调用打开和关闭资源。这就是性能瓶颈所在。好吧,这不是Basic.Get
,但如果连接保持打开状态,这是一个很好的实现。通道
只是添加到协议中的一个整数,因此在此实现中,与Basic.Get
相比,将有一个额外的数据包通过线路发送,其代价是不需要轮询服务器。我不明白为什么这会非常昂贵,但我可以看到吞吐量可能会受到限制。消费者可能是一个更好的选择,但也有。@ArtemBilan感谢您的回复。有没有什么例子可以让我看看这条路线?我仍然希望使用现有的ItemProcessor和ItemWriter。我遇到的所有示例都有自己的tasklet来执行工作。我是否可以使用SpringBatch与MessageListenerContainer一起提供的面向块的处理能力?是的,这是一个想法,但我不知道(目前)如何实现这个解决方案。我们可以使用类似于ItemStream
的东西,并使用所提到的Channel.basicGet()
执行RabbitOperations.execute()
。这样,我们将在ItemStream.open()
中打开一个频道
,直到ItemStream.open()。但是需要弄清楚课堂上的流程应该是怎样的。。。
private Step step() throws Exception {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(100);
executor.setMaxPoolSize(100);
executor.setThreadNamePrefix("SThread");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return stepBuilderFactory.get("queueToCassandraStep")
.<Message, Vendor>chunk(100)
.reader(itemReader)
.listener(new QueueReaderListener<>())
.processor(asyncItemProcessor())
.writer(asyncItemWriter())
.taskExecutor(executor)
.build();
}
import lombok.Setter;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties("art.com.service.product.config.rabbitmq")
public class RabbitConfig {
@Setter
private String host;
@Setter
private Integer port;
@Setter
private String username;
@Setter
private String password;
@Setter
private String exchangeName;
@Setter
private String queueName;
@Bean
ConnectionFactory rabbitConnectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host);
connectionFactory.setPort(port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
return connectionFactory;
}
@Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
@Bean
RabbitTemplate rabbitTemplate(ConnectionFactory rabbitConnectionFactory,
MessageConverter jsonMessageConverter) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitConnectionFactory);
rabbitTemplate.setQueue(queueName);
rabbitTemplate.setExchange(exchangeName);
rabbitTemplate.setMessageConverter(jsonMessageConverter);
return rabbitTemplate;
}
}