基于此示例设置我的架构:
设定:
我正在调查我的实施中导致速度减慢的瓶颈。因为我使用noAck重新排队失败的工人。为了在我的工作线程中均匀地启用它,我已将预取设置为1.查看此问题:RabbitMQ work queue is blocking consumers - 他们看到了我在下面的屏幕截图中看到的内容:
为了确保一次只为工作人员分配一条消息,我需要将预取设置为1,但是其他人说这会导致工作人员按顺序而不是并行工作。
在通道级别,Running实际意味着什么?我看到队列和连接正常运行,但各个通道(每个线程一个)都是空闲的。
编辑#1:关于将连接池传递给RabbitMQ连接的说明看起来很有希望。 https://www.rabbitmq.com/api-guide.html#consumer-thread-pool我正在使用Spring AMQP,但我认为可以使用类似的方法:
/**
* Configure a large thread pool for concurrent channels on the physical Connection
*/
@Bean
public org.springframework.amqp.rabbit.connection.CachingConnectionFactory rabbitConnectionFactory() {
logger.info("Configuring connection factory");
CachingConnectionFactory cf = new CachingConnectionFactory();
cf.setAddresses(this.rabbitMQProperties.getAddresses());
cf.setUsername(this.rabbitMQProperties.getUsername());
cf.setPassword(this.rabbitMQProperties.getPassword());
cf.setVirtualHost(this.rabbitMQProperties.getVirtualHost());
//configure a large thread pool for the connection thread
int threads = 30;
logger.info(String.format("Configuring thread pool with %d threads", threads));
ExecutorService connectionPool = Executors.newFixedThreadPool(threads);
cf.setExecutor(connectionPool);
logger.info(String.format("MQ cache mode: %s", cf.getCacheMode().toString()));
logger.info(String.format("MQ connection cache: %d", cf.getConnectionCacheSize()));
logger.info(String.format("MQ channel cache: %d", cf.getChannelCacheSize()));
return cf;
}
@Bean
AmqpTemplate rabbitTemplate(org.springframework.amqp.rabbit.connection.CachingConnectionFactory connectionFactory){
AmqpTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
return rabbitTemplate;
}
答案 0 :(得分:1)
在Spring AMQP中,单个物理TCP / IP连接的默认线程池默认为5个线程:
此外,在编写本文时,rabbitmq-client库默认为每个连接(5个线程)创建一个固定的线程池。使用大量连接时,应考虑在CachingConnectionFactory上设置自定义执行程序。然后,所有连接将使用相同的执行程序,并且可以共享其线程。执行程序的线程池应该是无限制的,或者为预期的利用率设置适当的(通常,每个连接至少有一个线程)。如果在每个连接上创建了多个通道,那么池大小将影响并发性,因此变量(或简单缓存)线程池执行器将是最合适的。
我能够通过更改分配给RabbitMQ连接池的线程数来复制它:
/**
* Expand the number of concurrent threads for a single RabbitMQ connection
* http://docs.spring.io/spring-amqp/reference/htmlsingle/
* Also, at the time of writing, the rabbitmq-client library creates a fixed thread pool for each connection (5 threads) by default.
* When using a large number of connections, you should consider setting a custom executor on the CachingConnectionFactory.
*/
@Bean(name="channelPool")
@Scope("singleton")
MigrationPool rabbitConnectionPool(){
int channels = 50;
logger.info(String.format("Configuring connection pool with %d threads", channels));
return new MigrationPool(channels, channels, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
/**
* Configure a large thread pool for concurrent channels on the physical Connection
*/
@Bean
public org.springframework.amqp.rabbit.connection.CachingConnectionFactory rabbitConnectionFactory(@Qualifier("channelPool") MigrationPool connectionPool) {
logger.info("Configuring connection factory");
CachingConnectionFactory cf = new CachingConnectionFactory();
cf.setAddresses(this.rabbitMQProperties.getAddresses());
cf.setUsername(this.rabbitMQProperties.getUsername());
cf.setPassword(this.rabbitMQProperties.getPassword());
cf.setVirtualHost(this.rabbitMQProperties.getVirtualHost());
cf.setExecutor(connectionPool);
logger.info(String.format("MQ cache mode: %s", cf.getCacheMode().toString()));
logger.info(String.format("MQ connection cache: %d", cf.getConnectionCacheSize()));
logger.info(String.format("MQ channel cache: %d", cf.getChannelCacheSize()));
logger.info(String.format("MQ thread pool: %d threads", connectionPool.getMaximumPoolSize()));
return cf;
}
在上面的代码中,我有每个连接的线程数,镜像虚拟通道的数量,即每个虚拟RabbitMQ通道的一个真实物理线程,因为每个通道引用一个工作线程,每个处理一个消息。这导致通道不再在默认的5个连接上阻塞,而是充分利用扩展的线程数:
操纵RabbitMQ连接可用的线程数将显示阻塞的通道。例如,设置为10个线程并打开50个通道。