No available channels

No available channels 异常

项目配置如下:

spring:
    rabbitmq:
        host: uck1
        port: 5672
        username: xxx
        password: xxxx
        publisher-confirms: true
        publisher-returns: true
        listener:
            direct:
                retry:
                    max-attempts: 3
                    enabled: true
                acknowledge-mode: manual
                # 每个队列的消费者数量
                consumers-per-queue: 5
                prefetch: 10
            type: direct
        cache:
            channel:
                size: 500
                checkout-timeout: 1000
            connection:
                mode: channel
                #size: 2

再无其他特殊配置,但是部署到线上会报 No available channels 的异常

org.springframework.amqp.AmqpTimeoutException: No available channels
	at org.springframework.amqp.rabbit.connection.CachingConnectionFactory.obtainPermits(CachingConnectionFactory.java:521)
	at org.springframework.amqp.rabbit.connection.CachingConnectionFactory.getChannel(CachingConnectionFactory.java:487)
	at org.springframework.amqp.rabbit.connection.CachingConnectionFactory.access$1600(CachingConnectionFactory.java:101)
	at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$ChannelCachingConnectionProxy.createChannel(CachingConnectionFactory.java:1333)
	at org.springframework.amqp.rabbit.core.RabbitTemplate.doExecute(RabbitTemplate.java:2079)
	at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:2047)
	at org.springframework.amqp.rabbit.core.RabbitTemplate.send(RabbitTemplate.java:994)
	at org.springframework.amqp.rabbit.core.RabbitTemplate.convertAndSend(RabbitTemplate.java:1060)
	at org.springframework.amqp.rabbit.core.RabbitTemplate.convertAndSend(RabbitTemplate.java:1053)
	at com.dkd.mq.PushProvider.sendOrdinaryMessage(PushProvider.java:83)
	at com.dkd.RabbitmqDelayApplication.lambda$afterSingletonsInstantiated$0(RabbitmqDelayApplication.java:62)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)

rabbitmq 无论是生产者还是消费者 都需要和 RabbitMQ Broker 建立连接,这个连接就是一条 TCP 连接,也就是 Connection. 一旦 TCP 连接建立起来,客户端紧接着可以创建一个 AMQP 信道(Channel),每个信道都会被指派一个唯一的 ID . 信道是建立在 Connection 之上的虚拟连接,RabbitMQ 处理的每条 AMQP 指令都是通过信道完成的。

我们完全可以使用 Connection 就能完成信道的工作,为什么还要引入信道呢?

试想这样一个场景,一个应用程序中有很多个线程需要从 RabbitMQ 中消费消息,或者生产消息,那么必然需要建立很多个 Connection,也就是多个 TCP 连接。

然而对于操作系统而言,建立和销毁 TCP 连接是非常昂贵的开销,如果遇到使用高峰,性能瓶颈也随之显现。

RabbitMQ 采用类似 NIO(Non-blocking I/O)的做法,选择 TCP 连接复用,不仅可以减少性能开销,同时也便于管理。

每个线程把持一个信道,所以信道复用了 Connection 的 TCP 连接。同时 RabbitMQ 可以确保每个线程的私密性,就像拥有独立的连接一样。当每个信道的流量不是很大时,复用单一的 Connection 可以在产生性能瓶颈的情况下有效地节省 TCP 连接资源。但是信道本身的流量很大时,这时候多个信道复用一个 Connection 就会产生性能瓶颈,进而使整体的流量被限制了。此时就需要开辟多个 Connection,将这些信道均摊到这些 Connection 中,至于这些相关的调优策略需要根据业务自身的实际情况进行调节。

上面内容转自博客: https://www.cnblogs.com/eleven24/p/10326718.html

由上面可以知道 我们整个应用只使用了一个连接connection,并在这个连接的基础上创建了500个channel,我们的消费者和生产者都共同使用这些channel来传输数据. 如果此时系统性的并发度不高的话,就是说这个时候500个channel没有同时在使用的话,系统是没有问题的,但是如果系统并发度高,需要同时传输大量的数据和消费大量的数据时,同时耗尽了500个channel,并且还需要创建channel 这个时候就是出现了 No available channels
的问题.

解决办法

  • 措施1: 生产和消费使用不同的connection 扩大传输通路
    rabbitTemplate.setUsePublisherConnection(true);
    在这里插入图片描述

CachingConnectionFactory 在创建时就创建了两个工厂实例,
当设置这个值为true后,在创建连接时,程序会区分是发送还是消费来创建不同的连接,
这两个连接又分别缓存各自的channel

  • 措施2: 增大channel的缓存size
    这个在channel的缓存size 较小时是可以的,当channel的缓存size本身就较大时,更明智的办法不是继续增大size.
    因为connection 就好比 一条高速公路,channel 就好比一辆辆货车.
    货车太多会造成高速公路拥堵,造成数据传输效率降低和增加系统内存消耗.

  • 措施3: 减小部分消费者的并发度即consumers-per-queue: 5
    有些队列的数据量较小,完全可以一个并发即单线程消费搞定,减少channel占用.

  • 措施4: 增大checkout-timeout
    因为达到channel上限后即channel缓存池中channel耗尽,程序在申请channel 他不会立即报错,而是阻塞checkout-timeout时间,在这段时间内有谁及时归还了channel,这个时候也是会正常拿到channel的.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值