RabbitMq CacheModel
基本概念
Connection
Connection是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑。
Channel
Channel是在connection内部建立的逻辑连接。
CacheMode.CHANNEL
RabbitMQ的默认模式,所有消息共享一个Connection
集群模式示意图:
3台服务器 80queue 并发上限
3*1*80 = 240
CacheMode.CONNECTION
开启多个Connection如下图,提供更高的并发。
集群模式示意图:
3台服务器 80queue 并发上限
3*(80*4)*80 = 76800
Connection模式的副作用
如上图 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
实测
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 模式
启动时如果有消费端则自动创建,无消费端则无法创建。
实测小结
-
使用Connection模式时用bean方式创建队列会有问题.
-
auto delete队列没有消费者时不能创建队列不能发消息。
结论
-
建议不要在代码中定义exchange queue binding,去控制台手动创建。
-
auto-delete队列也不是必须的,可用普通队列代替。
-
Connection模式提供了更高的并发上限,可以使用但要满足以上两点。
-
根据并发和改造成本做一个权衡,并发确实高经常出现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:
- connection模式中,connection使用完会被回收吗?
会被回收,connection close时会先判断cache中有没有空位,有则放入,没有则直接销毁连接
- connection模式会无限创建连接吗?
不会,单实例连接有上限,超过会被阿里云限制。代码里也可以设置可创建的连接上限。
- 达到连接上限后,后续请求会怎样?
请求会被阻塞自旋等待有连接被释放后 执行。
参考文档: