消息中间件之八股面试回答篇:二、MQ如何保证消息不重复消费(幂等性)+RabbitMQ死信交换机(延迟队列)+回答模板

发布时间:2024年01月24日

MQ消息重复消费问题

可能出现重复消费的场景

  • 网络抖动
  • 消费者挂了

MQ通用的解决方案

  • 每条消息设置一个唯一的标识id
  • 幂等方案:【 分布式锁、数据库锁(悲观锁、乐观锁) 】

RabbitMQ的死信交换机

当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter)

  • 消费者使用basic.reject或 basic.nack声明消费失败,并且消息的requeue参数设置为false
  • 消息是一个过期消息,超时无人消费。其又可以细分为两种情况(以最短的时间超时为准)
    1. 消息所在的队列设置了存活时间
    2. 消息本身设置了存活时间
  • 要投递的队列消息堆积满了,最早的消息可能成为死信

如果该队列配置了dead-letter-exchange属性,指定了一个交换机,那么队列中的死信就会投递到这个交换机中,而这个交换机称为死信交换机(Dead Letter Exchange,简称DLX)

ATT:死信交换机实际上也就是一个普通的交换机,它能在任何队列被指定,只不过赋予了接受死信的功能而已。所以需要在定义队列时就指定死信交换机。

@Bean
public Queue ttlQueue(){
	return QueueBuilder.durable("simple.queue")//指定队列名称并持久化
	.ttl(10000)//设置队列的超时时间,10秒
	.dealLetterExchange("dl.direct")//指定死信交换机
	.build();
}

RabbitMQ的延迟队列(DelayExchange)

延迟队列:进入队列的消息会被延迟消费的队列
场景:超时订单、限时优惠、定时发布

延迟队列本质还是官方的三种交换机,只是添加了延迟功能。

实现延迟队列可以用以下两种方法之一:

  1. 队列绑定一个死信交换机,在死信交换机上可以绑定其他队列,在我们发消息的时候可以按照需求指定TTL的时间。(本质上是死信交换机+TTL)
  2. 安装一个DelayExchange插件,声明一个交换机,然后设定delayed属性为true即可。

RabbitMQ官方的插件社区地址为:https://www.rabbitmq.com/community-plugins.html

不需要掌握,本人留档使用

在这里插入图片描述
在这里插入图片描述

问题与回答模板

RabbitMQ消息的重复消费问题如何解决的?

回答:(背熟以下回答,大概用时1min)

嗯,这个我们还真遇到过,是这样的,我们当时消费者是设置了自动确认机制,当服务还没来得及给MQ确认的时候,服务宕机了,导致服务重启之后,又消费了一次消息。这样就重复消费了

因为我们当时处理的支付(订单|业务唯一标识),它有一个业务的唯一标识,我们再处理消息时,先到数据库查询一下,这个数据是否存在,如果不存在,说明没有处理过,这个时候就可以正常处理这个消息了。如果已经存在这个数据了,就说明消息重复消费了,我们就不需要再消费了

面试官:那你还知道其他的解决方案吗?

候选人

嗯,我想想~

其实这个就是典型的幂等的问题,比如,redis分布式锁、数据库的锁都是可以的。

RabbitMQ中死信交换机或者说延迟队列有了解过嘛?

回答:(背熟以下回答大概用时1min)

首先关于死信的定义,一般满足以下情况之一,就可能成为死信。譬如,过期时间到了却仍未被消费的消息,或者要投递的队列满了,最早的消息就可能成为死信。死信交换机实际上就是设置的一个用来接收死信的交换机,它与普通的交换机其实没有什么区别。
而延迟队列,一般用于超时订单、限时优惠、定时发布之类的场景。本质还是官方的三种交换机之一,只是添加了延迟功能。我们实现它可以有两种方式。第一种就相当于死信交换机加上TTL,第二种更简单一些,就是去官网下载相关的插件,然后定义时把delay设置为true即可。

文章来源:https://blog.csdn.net/zhiaidaidai/article/details/135773727
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。