RabbitMq Connection和Channel 模式的选择

2,001 阅读3分钟

RabbitMq CacheModel

基本概念

Connection

Connection是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑。

Channel

Channel是在connection内部建立的逻辑连接。



CacheMode.CHANNEL

RabbitMQ的默认模式,所有消息共享一个Connection

image.png 集群模式示意图:

image.png

3台服务器 80queue 并发上限


3*1*80 = 240

CacheMode.CONNECTION

开启多个Connection如下图,提供更高的并发。

image.png

集群模式示意图:

image.png

3台服务器 80queue 并发上限


3*(80*4)*80 = 76800

Connection模式的副作用

image.png

如上图 CachingConnectionFactory注释中提到 Connection模式不兼容 auto-declares。

Spring AMQP文档中提到 CacheModel.CONNECTION模式 exclusive和 auto-delete不生效

Automatic declaration is performed only when the CachingConnectionFactory cache mode is CHANNEL (the default). This limitation exists because exclusive and auto-delete queues are bound to the connection. link

spring文档对 auto declare的描述link

容器启动时检测到队列丢失(可能是auto-delete/过期的队列)则重新声明队列

spring文档对 auto-delete的描述link

当所有consumer停止时,broker移除该队列

CachingConnectionFactory的一些说明link

实测

image.png

Connection模式

启动时如果有消费者则自动创建,无消费者时第一次发送消息报错。如果已被创建则无影响。

ERROR - Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=ExchangeNotExist, ReqId:62CD3A5137383265489212B0, ErrorHelp[62CD3A5137383265489212AC], class-id=60, method-id=40)

Channel 模式

启动时如果有消费端则自动创建,无消费端则发送第一条消息时创建

auto-delete channel 模式

启动时如果有消费端则自动创建,无消费端则发送第一条消息时创建

auto-delete Connection 模式

启动时如果有消费端则自动创建,无消费端则无法创建。

实测小结
  1. 使用Connection模式时用bean方式创建队列会有问题.

  2. auto delete队列没有消费者时不能创建队列不能发消息。

结论

  1. 建议不要在代码中定义exchange queue binding,去控制台手动创建。

  2. auto-delete队列也不是必须的,可用普通队列代替。

  3. Connection模式提供了更高的并发上限,可以使用但要满足以上两点。

  4. 根据并发和改造成本做一个权衡,并发确实高经常出现channelMax异常影响正常业务就很有必要改用Connection模式,反之就没必要了。

代码示例

public ConnectionFactory getConnectionFactory() {

    com.rabbitmq.client.ConnectionFactory factory = new com.rabbitmq.client.ConnectionFactory();

    factory.setHost(rabbitProperties.getHost());

    factory.setPort(rabbitProperties.getPort());

    factory.setVirtualHost(rabbitProperties.getVirtualHost());

    factory.setCredentialsProvider(new AliyunCredentialsProvider(rabbitProperties.getUsername(),

    rabbitProperties.getPassword(),instanceId));

    factory.setAutomaticRecoveryEnabled(true);

    factory.setNetworkRecoveryInterval(5000);

    ConnectionFactory connectionFactory = new CachingConnectionFactory(factory);

    ((CachingConnectionFactory)connectionFactory).setPublisherConfirms(rabbitProperties.isPublisherConfirms());

    ((CachingConnectionFactory)connectionFactory).setPublisherReturns(rabbitProperties.isPublisherReturns());

    ((CachingConnectionFactory)connectionFactory).setCacheMode(CachingConnectionFactory.CacheMode.CONNECTION);

    ((CachingConnectionFactory)connectionFactory).setConnectionCacheSize(10);

    ((CachingConnectionFactory)connectionFactory).setChannelCacheSize(64);

    return connectionFactory;

}


FAQ:

  1. connection模式中,connection使用完会被回收吗?

会被回收,connection close时会先判断cache中有没有空位,有则放入,没有则直接销毁连接

  1. connection模式会无限创建连接吗?

不会,单实例连接有上限,超过会被阿里云限制。代码里也可以设置可创建的连接上限。

  1. 达到连接上限后,后续请求会怎样?

请求会被阻塞自旋等待有连接被释放后 执行。


参考文档:

spring-rabbitmq-component-doc

Spring AMQP doc