为处理生产者将消息推送到交换机中,交换机按照消息中的路由键及自身策略无法将消息投递到指定队列中造成消息丢失的问题,可以使用备份交换机。
为处理在消息队列中到达TTL的过期消息,可采用死信交换机进行消息转存。可以通过死信交换机的方式实现延迟队列的需求。
为实现消息优先消费可以针对队列和消息设置优先级,在消息积压的情况下优先级高的消息将优先被消费。
通过上述描述可知,备份交换机和死信交换机处理的场景不同。备份交换机是处理未被路由的消息,死信交换机是处理队列中过期的消息。但是,它们都是为了避免消息丢失提供的一种手段。
备份交换机
生产者发送消息的过程中会指明交换机名称和路由键,RabbitMQ接收到消息后,根据交换机名称将消息投递到指定交换机中,交换机再根据自身类型以及消息携带的路由键将消息投递到队列中。当无法路由到队列时,并且该交换机存在备份交换机,则该交换机将该消息投递给其备份交换机进行处理。
备份交换机接收到消息后依旧根据其自身类型和消息路由键进行消息投递,如果依旧无法匹配到队列中,则该消息被丢失。该过程中的具体流程如下图所示。
备份交换机的实现
备份交换机的实现方式包括:声明交换机时通过参数配置和通过策略进行配置。申明交换机时配置备份交换机如下所示。
Map<String, Object> args = new HashMap<>();
args.put("alternate-exchange","myAe");
channel.exchangeDeclare("normalExchange","direct",true,false,args);
channel.exchangeDeclare("myAe","fanout",true,false,null);
通过上述代码即实现了声明两个交换机,其中交换机myAe是normalExchange的备份交换机。备份交换机可以理解为一个普通交换机,备份交换机自身并不知晓自己是备份交换机,当某个消息无法被路由到队列中时,该交换机会查找自己的备份交换机,如果存在则将消息交由备份交换机进行处理。
需要说明的时,备份交换机在消息入队的时候也会根据自身类型进行路由匹配,消息重发到备份交换机时路由键和从生产者发送时的路由键一致,如果是直接交换机或者主题交换机,则依旧可能会导致消息丢失,因此备份交换机建议采用扇形交换机。
备份交换机存在以下特殊情况
- 如果备份交换机和mandatory参数一起使用,则mandatory参数无效。
- 如果备份交换机不存在,则消息丢失且生产者和RabbitMQ都不会有异常出现。
- 如果备份交换机没有绑定队列,则消息丢失且生产者和RabbitMQ都不会有异常出现。
- 如果备份交换机依旧无法将消息路由到队列,则消息丢失且生产者和RabbitMQ都不会有异常出现。
死信交换机
当一个消息在一个队列中变成死信后,它能被重新发送到另一个交换机中,这个交换机就是DLX(死信交换机:Dead-Letter-Exchange),绑定DLX的队列就是死信队列。
消息变成死信一般由以下几种情况:
- 消息被消费者拒绝,并且设置不可重新入队
- 消息过期(TTL)
- 队列达到最大长度。
根据上述描述,队列中的消息变成死信后将转发给死信交换机,因此死信交换机的设置是在声明队列的过程中完成的。死信交换机和备份交换机类似,其自身并不知道自己是死信交换机,仅指定其为死信交换机的队列知道其死信交换机身份的存在,本质上死信交换机和正常交换机并不存在区别。
死信交换机的设置可通过声明队列时设置和通过策略设置两种方式实现。声明队列时设置如下所示:
Map<String, Object> args = new HashMap<>();
// 声明该队列的死信交换机为”dlx_exchange“
args.put("x-dead-letter-exchange","dlx_exchange");
// 声明死信交由死信交换机处理时将路由键替换为dlx-routing-key
args.put("x-dead-letter-routing-key","dlx-routing-key");
channel.queueDeclare("queue",false,false,false,args);
死信交换机存在以下特殊情况
- 如果死信交换机不存在,则消息丢失且RabbitMQ都不会有异常出现。
- 如果死信交换机没有绑定队列,则消息丢失且RabbitMQ都不会有异常出现。
- 如果死信交换机依旧无法将消息路由到队列,则消息丢失且RabbitMQ都不会有异常出现。
延迟队列
延迟队列是指当消息发送完成后,消费者间隔一段时间后消费该消息,可以通过死信队列的方式实现延迟队列,生产者把消息发送给设置了过期时间的队列中,该队列不存在消费者,待消费过期后消息会被投递到延迟队列(死信队列),消费者消费延迟队列中的消息,这样就实现了消息的延迟处理。
优先级队列
可以针对队列和消息设置消息,在消息积压的情况下消费者可以优先消费高优先级的消息。
仅向设置优先级的队列中发送具备优先级的消息优先级设置才有效,如果仅对消息设置优先级则优先级设置无效。
消息的优先级默认为0,最高为队列设置的最大优先级,如果设置的消息优先级大于队列设置的最大优先级,则按照队列最大优先级进行计算。
设置队列为优先级队列如下所示:
Map<String,Object> map = new HashMap<>();
map.put("x-max-priority",10);
channel.queueDeclare(QUEUE_NAME,true,false,false,map);
发送具备优先级的消息如下所示:文章来源:https://www.toymoban.com/news/detail-631482.html
AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();
builder.priority(20000);
AMQP.BasicProperties basicProperties = builder.build();
channel.basicPublish(EXCHANGE_NAME ,ROUTING_KEY,basicProperties,msg.getBytes());
优先级队列存在以下几点需要注意:文章来源地址https://www.toymoban.com/news/detail-631482.html
- 仅在消息积压的情况下优先级队列的设置才有意义
- 设置优先级的消息仅在优先级队列中才能体现出优先级消费
- 一旦消息中的优先级设置大于队列的优先级,则按照队列的优先级进行计算
总结
比较 | 备份交换机 | 死信交换机 | 优先级队列 |
---|---|---|---|
作用 | 消息无法路由到队列中后交由备份交换机进行处理 | 消息从队列成为死信后交由死信交换机进行处理 | 挤压消息在优先级队列中可以按照优先级高低被消费者消费 |
设置方法 | 给某个交换机设置备份交换机,备份交换机自身不知道自己备份交换机的身份 | 给某个队列设置死信交换机,死信交换机本身不知道自己死信交换机的身份 | 设置某个队列的优先级,在发送消息的过程中也声明消息优先级 |
到了这里,关于RabbitMQ 备份交换机和死信交换机的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!