problems_rabbitmq
目录
problems_rabbitmq
1 rabbitmq的guest账户无法远程登录,只能在本地登录
RCA: guest被限制为只能本地登录了,rabbitmq从3.3.0开始禁止使用guest/guest权限通过除localhost外的访问。
solution: 修改配置文件rabbit.app
(rabbit.app的路径,在我的ubuntu18.04系统中为:/usr/lib/rabbitmq/lib/rabbitmq_server-3.6.10/ebin/ )
将:{loopback_users, [<<"guest">>]},改为:{loopback_users, []}
reference: https://www.cnblogs.com/yzp666/archive/2019/06/11/11004975.html
2 每次启动系统,总是重复执行某个@RabbitListener监听的方法
desc: 每次启动总是执行那个方法,以下是方法中的提示消息:
2021-11-30 11:51:42.988 INFO --- com..orders.service.impl.BizOrderServiceImpl.notifyUserAfterOrderCreated[464]: 王五 您好,有笔订单支付提醒!订单编号:SN1000016,订单详情:http://url:port/vtbLhZ。订单有效期为半个小时,请在有效内尽快完成支付。感谢您的支持。
RCA: 之前消息确认改为了手动确认,如下设置:
spring:
rabbit:
listener:
direct:
# manual 消息手动确认;auto 自动确认;none 不确认
acknowledge-mode: manual
simple:
acknowledge-mode: manual
所以需要在方法中显式调用确认方法,如下所示:
// 第二个参数,手动确认可以被批处理,当该参数为 true 时,则可以一次性确认 delivery_tag 小于等于传入值的所有消息
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
3 springboot系统启动报错
desc:报如下错误消息:
2021-11-30 09:53:55.321 ERROR --- org.springframework.amqp.rabbit.connection.CachingConnectionFactory.log[748]: Shutdown Signal: channel error; protocol method: #method<channel.close>(reply-code=405, reply-text=RESOURCE_LOCKED - cannot obtain exclusive access to locked queue 'biz.order.return.queue' in vhost '/'. It could be originally declared on another connection or the exclusive property value does not match that of the original declaration., class-id=50, method-id=10)
RCA: 设置了队列为durable和exclusive,系统重启后,队列还在,但是不能被重启系统后的新建的channel消费了,新建的channel属于另一个channel了。
那我怎么能消费原来的队列呢?
solution: 创建queue时,将exclusive属性设置为false,即“非独占”,允许其他的channel消费该队列。创建代码如下:
/**
* @param name 队列名称
* @param durable 是否持久化,默认是true,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
* @param exclusive 默认是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
* @param autoDelete 是否自动删除, 默认false,当没有生产者或者消费者使用此队列,该队列会自动删除。
*/
new Queue(BIZ_ORDER_SAVE_QUEUE, true, false, false);
4
Caused by: org.springframework.messaging.converter.MessageConversionException: Cannot convert from [[B] to [com.beyondsoft.orders.entities.dto.BizOrderDTO] for GenericMessage [payload=byte[1554], headers={amqp_receivedDeliveryMode=PERSISTENT, amqp_receivedRoutingKey=biz.order.save.routingKey, spring_listener_return_correlation=adc96bdb-4283-4659-ac7f-31b37022bcfd, amqp_receivedExchange=biz.order.exchange, amqp_deliveryTag=1, amqp_consumerQueue=biz.order.save.queue, amqp_redelivered=false, id=f31ce1be-eaa9-59b3-65e7-18f35928e2d0, amqp_consumerTag=amq.ctag-6mIbvGvdRi8dsekH_xBudA, amqp_lastInBatch=false, contentType=application/x-java-serialized-object, timestamp=1638204199537}]
RCA: 没有配置消息转换器,没法转换原始的消息类型(好像是字节数组类型)为目标类型(即我们实际需要的类型)
solution: MyAMQPConfig类中,增加以下bean:
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
5 springboot启动时rabbitmq总是报错
报错内容如下:
// 1 配置virtual-host为 / 时报如下错误:
Caused by: com.rabbitmq.client.ShutdownSignalException: connection error; protocol method: #method<connection.close>(reply-code=530, reply-text=NOT_ALLOWED - access to vhost '/' refused for user 'java_demo', class-id=10, method-id=40)
RCA: 用户java_demo没有权限访问虚拟主机 /
// 2 配置virtual-host为 /java_demo 时报如下错误:
Caused by: com.rabbitmq.client.ShutdownSignalException: connection error; protocol method: #method<connection.close>(reply-code=530, reply-text=NOT_ALLOWED - vhost /java_demo not found, class-id=10, method-id=40)
RCA:虚拟主机 /java_demo 不存在,此处因为前面多了一个斜杠,真正应该配置这个虚拟主机 java_demo
SOLUTION:然后我配置virtual-host为 java_demo,就能正常启动了。
// 3 在另一个springboot系统中,我配置 virtual-host 为 java_demo,但是总是报第1个错误:
Caused by: com.rabbitmq.client.ShutdownSignalException: connection error; protocol method: #method<connection.close>(reply-code=530, reply-text=NOT_ALLOWED - access to vhost '/' refused for user 'java_demo', class-id=10, method-id=40)
ACTION:各种排查,各种修改配置文件,但仍然没用,而且可以确定配置文件的其他rabbitmq配置项是起作用的,就virtual-host不起作用,搞了几个小时。
RCA: 最终发现是在代码中写死了 virtual-host 为 /
SOLUTION:将代码中的virtual-host改为使用配置文件中的值。
具体方法是:在RabbitMqConfig.java中增加私有属性:
@Value("${spring.rabbitmq.virtual-host}")
private String virtualHost;
@Bean
public ConnectionFactory connectionFactory() {
...
connectionFactory.setVirtualHost(virtualHost);
...
}
NOTE:
a. 配置文件中的配置为:
spring:
rabbitmq:
host: host1
port: 5672
username: username1
password: password1
virtual-host: java_demo
b. 代码中的写死的内容为:
类名:RabbitMqConfig.java
代码:
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host, port);
connectionFactory.setUsername(userName);
connectionFactory.setPassword(password);
connectionFactory.setVirtualHost("/");
// connectionFactory.setPublisherConfirms(true);
return connectionFactory;
}