SpringBoot是如何管理RabbitMQ中的Channel?

Channel是什么

RabbitMQ是AMQP0-9-1协议的实现,先来看看AMQP0-9-1协议中对通道Channel的阐述。

有些应用程序需要与broker建立多个连接。但是,保持多个TCP连接同时打开是不可取的,因为这样做会消耗系统资源,使配置防火墙更加困难。AMQP0-9-1的Connection可以多路复用,Channel可以被认为是“共享一个TCP连接的轻量级连接”。


客户端执行的每个协议操作都发生在一个channel上。在特定channel上的通信与在另一个channel上的通信完全独立,因此每个协议方法也都带有信道ID(a.k.a)。一个整数,代理和客户端都使用它来确定该方法用于哪个通道。


channel仅存在于connection的上下文中,而不会单独存在。当channel关闭时,其上的所有channel也会关闭。


对于使用多个线程/进程进行处理的应用程序,为每个线程/进程打开一个新channel而不在它们之间共享channel是很常见的。

在普通的JAVAEE项目中,经常采用1个进程-1个connection-1个channel。但是这在JAVAWEB场景中实不可取的。一个web项目仅有1个进程,会有非常多的线程,每个线程都创建一个connection是不可取的。

在AMQP-0-9-1协议中推荐了使用每个线程使用一个独立的channel,这样不同线程之间的channel相互独立,并且公用同一个connection。

但是问题又来了,在并发情况下,web场景下,用户的每一次http请求都是一个线程,难道这样的每一个http请求都要对应创建一个channel吗?Spring在集成RabbitMQ时对这个问题有了非常好的解决。




Spring如何管理Channel?

springboot使用了RabbitMQ中的IO多路复用的理念,并对这种方案在web场景下进行了优化,尽可能的复用空闲中的channel。boot默认使用CachingConnectionFactoryConnection和空闲Channel进行缓存。

看看Spring中的RabbitMQ是如何工作的:

Spring中对RabbitMQ的消息操作都是通过一个Template模板对象RabbitTemplate,该对象中封装了对消息的接受和发送的各种重载方法。消息的send都需要调用一个核心私有方法doExcute()
在这里插入图片描述
Spring也是通过TransactionSupport进行管理RabbitMQ中的事务Channel。这一点和MyBatis的SqlSessionTemplate管理开启事务的SqlSession的步骤相同。这里不多赘述如果管理事务的channel,可以参考一下我的mybatis文章。

  1. 当第一次有请求连接rabbitmq时,spring创建一个AMQP的connection,并使用CachingConnectionFactory将其封装并缓存起来。
    在这里插入图片描述

  2. 然后使用这个connection,创建channel,当channel的任务执行完成后(也就是逻辑close时,并非真正的关闭了channel,而是在内存中给channel创建了一个标记。)则使用CachingConnectionFactory的静态子类ChannelConnectionFactoryProxy把这个channel缓存到一个空闲列表中。开启了事务的channel存放在不同的列表中。
    在这里插入图片描述

  3. 其他线程执行任务时,CachingConnectionFactory中获取connection,然后创建channel时,会去ChannelConnectionFactoryProxy的空闲列表中寻找哪些channel是open状态。然后将寻找到的一个channel移出列表,并使用这个channel执行任务。(取出缓存中的channel这一过程是同步代码块, 开启了事务的channel存放在不同的列表中。)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  4. 任务执行完毕,将channel在缓存入空闲列表中。默认最多缓存25个channel

在这里插入图片描述
在这里插入图片描述

channel.basicQos方法用于设置消费者在处理多个消息时的预取数量(Prefetch Count)。预取数量指的是消费者在处理完一定数量的消息后,会向RabbitMQ服务器发送一个确认消息(ACK),告知服务器可以继续向消费者发送更多的消息。如果预取数量设置的较小,消费者需要更频繁地向服务器发送确认消息,会降低消息处理的效率;如果预取数量设置的较大,消费者可能会一次性处理过多的消息,导致内存占用过高。 在Springboot,我们可以通过RabbitListenerContainerFactory来配置消费者的预取数量。具体步骤如下: 1. 定义一个RabbitListenerContainerFactory的Bean,可以使用SimpleRabbitListenerContainerFactory或DirectRabbitListenerContainerFactory等实现类,根据需要配置相关属性。 ``` @Bean public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) { SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); factory.setPrefetchCount(10); // 设置预取数量为10 factory.setConcurrentConsumers(5); // 设置并发消费者数量为5 factory.setMaxConcurrentConsumers(10); // 设置最大并发消费者数量为10 return factory; } ``` 2. 在消费者方法上使用@RabbitListener注解,并指定containerFactory属性为上一步定义的Bean名称。 ``` @RabbitListener(queues = "test.queue", containerFactory = "rabbitListenerContainerFactory") public void consumeMessage(Message message) { // 消费消息的逻辑 } ``` 通过以上步骤,我们就可以在Springboot配置消费者的预取数量,提高消息处理的效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值