Spring RabbitMQ Channel理解

3,576 阅读4分钟

概述


AMQP协议中,有channel的概念,在RabbitMq中,channel表示逻辑连接或者叫虚拟连接,是棣属于TCP连接的。一个TCP连接里可以创建多个channel,在Rabbit MQ里,消息的发送和接收都是基于channel的。

collection和channel的关系

有了TCP连接后,还需要channel的原因如下:

  • 创建和销毁TCP连接很耗时;
  • 打开太多TCP连接,耗操作系统资源,并发量大到一定程度,系统的吞吐量会降低;
  • 使用一个collectionchannel的方式,可以提升连接的利用率。

因此采用多个channel多路复用一个TCP连接的方式才比较合理。


channel线程不安全


channel不是线程安全的,线程并发的去访问同一个channel会出问题。这里有几种处理方式:

  1. 全局公用一个channel且使用全局锁,让操作channel排队.这种明显性能是不行的;
  2. 一个线程对应创建一个新的channel,但是要处理好一个连接能支撑的最大channel数量;
  3. 一个线程对应一个channel,但是是从channel池子拿的,不是每次都创建新的.一旦一个线程完成了一个channel的使用,它将返回到池中,从而使该channel可用于另一个线程。

量不大的话,使用第二种方式就可以了。量大的话,建议使用第三种方式,毕竟创建和销毁channel也是耗时耗资源的.在spring amqp中,提供了一个缓存channel的方案。可以在创建CachingConnectionFactory时指定缓存的模式。

connectionFactory.setCacheMode(CachingConnectionFactory.CacheMode.CHANNEL);
connectionFactory.setChannelCacheSize(25);

上面的两行代码,表示channel共用唯一的一个连接,且缓存了25个channel,注意这里的25个并不是说,这个连接里只能最多创建25个channel,而是说最多缓存25个channel。举个例子,假设并发发送100条消息,在CachingConnectionFactory.CacheMode.CHANNEL模式下,瞬间会创建100个channel的,然后往缓存里放25个channel,当流量下去了,刚刚创建的多余的channel会自动关闭掉的,缓存里只保留25个。

使用这种方式的话,要注意缓存的channel数量,不能太小,不然流量一大,仍然会造成频繁关闭channel的情况。当然我们也不能说有多少并发,就创建多少个channel,还是要限制一下,这个时候可以使用:

connectionFactory.setChannelCheckoutTimeout(1000);

ChannelCheckoutTimeout的值大于0的时候,ChannelCacheSize的值就是最大的channel数量了,一旦从缓存中获取不到channel,等待ChannelCheckoutTimeout毫秒后,如果还是获取不到的,就会抛AmqpTimeoutException了。

我们也可以自己实现channel pool,但是不太建议怎么做,毕竟spring amqp还是相当成熟的,直接使用就可以了。


CacheMode.CHANNEL模式性能


如上文所述,采用了CacheMode.CHANNEL的模式的话,就是一线程一channel形式,且这些channel共享了同一个连接,也即是共享同一个socket。当并发量一大的时候,可能导致同一时刻,多个线程都想往这个socket上写数据。为了避免这种情况,只能加锁,让拿不到锁的线程block住。在老外写的Using spring-rabbit under high throughput一文中,也提到了这点,并做了压力测试,并发10个线程发送1000000条消息,结果线程被block住了,如下图:

在这里插入图片描述
作者也提到,当流量很大的时候,使用CacheMode.CONNECTION的模式,可以提高发送效率。关于这两种模式的性能问题,也可以看一下在stackoverflow的讨论,Spring CachingConnectionFactory limiting channels & causing Thread Blocking;


channel的监控


RabbitMQ Admin UI提供了一个监控channel的界面,我们主要关注两点:

  • channel有没有可能泄露,打开了channel,却没有关闭channel;
  • 打开channel和关闭channel的速率。

如果通道打开操作的速率始终高于通道关闭操作的速率,那就可能发生channel泄露了。如下图:

在这里插入图片描述

如果打开和关闭channel的速率都很高,也值得观察一下。因为可能是没有缓存channel了。当流量继续增大的时候,可能会出现吞吐量上不去的情况,如下图:

在这里插入图片描述

--

原来链接


Spring RabbitMQ Channel理解