前言:
前面我们对 RabbitMQ 有了基本认知和使用,本篇分享一些 RabbitMQ 的常见面试问题。
RabbitMQ 系列文章传送门
RabbitMQ 如何保证消息一定会发送成功?【RabbitMQ Publisher Confirm 机制】
RabbitMQ 的事务消息了解吗【RabbitMQ 事务消息实战】
RabbitMQ 的死信队列了解吗?
RabbitMQ 的死信队列(Dead LetterQueue,简称DLQ)是用于处理消息处理失败或无法路由的消息的机制,它会将无法被正常消费的消息重新路由到另一个新的队列,以便消后进行进一步的处理,这个队列就是死信队列。
当 RabbitMQ 中的消息有以下情况的时候,可以认为消息是死信。
- 消息处理失败:消息消费端因为代码、业务逻辑等导致的消息消费失败,这个消息可以被标记为死信。
- 消息过期:消息设置了过期时间,在过期时间内消息没有被消费,可以认为是死信消息。
- 消息被拒收:消费者明确拒收一条消息的时候,这条消息可以标记为死信发布到死信队列中。
- 消息无法路由:当消息没有路由到任何队列的时候,消息可以被发送到死信队列中。
当消息变成死信之后,如果配置了死信队列,它将被发送到死信了交换机,死信交换机将死信投递到一个队列上,但是如果没有配置死信队列,那么这个消息将会被丢弃。
RabbitMQ 的死信队列有很多作用,比如我们可以借助他实现延迟消息,进而实现订单的到期关闭,超时关单等业务逻辑。
RabbitMQ 如何实现延迟消息?
RabbitMQ 实现延迟消息一般有两种方式,分别是使用死信队列和延迟消息插件来实现。
死信队列实现延迟消息
基于死信队列的机制,就可以实现延迟消息了,我们给一个消息设定 TTL(可以设置任何时间),但并不消费这个消息,等它过期后就会进入到死信队列,然后我们再监听死信队列的消息消费,就实现了延迟消息的功能。
RabbitMQ 设置延迟消息的方式:
- 设置队列 TTL:给队列设置 TTL,意味这这个队列的所有消息的 TTL 都是一样的(除非又单独对消息设置了 TTL),那么过期的消息一定是在队列的头部这一部分,这个时候从队列头部开始扫描,将过期的消息全部抛弃或者进入死信队列。
- 设置消息 TTL:给消息设置 TTL,同一个队列的每个消息的 TTL 可能都不一样,如果想要判断消息是否过期,理论上来说是要扫描整个队列,这样操作会比较消耗性能,因此 RabbitMQ 索性等消息即将要发送给消费者的时候,判断消息是否过期,如果过期则抛弃或者进入死信队列。
设置队列 TTL 代码如下:
@Bean("normalQueue")
public Queue normalQueue() {
Map<String, Object> map = new HashMap<>();
//当前队列中 message 过期时间
map.put("x-message-ttl", 5000);
//给当前队列绑定死信交换机
map.put("x-dead-letter-exchange", "dead-buget-exchange");
//绑定 Routing key
map.put("x-dead-letter-routing-key", "dead-buget-exch