通过消息回退机制和mandatory参数,可以处理交换机投递失败的消息。
消息回退到生产者后,有时候并不知道该如何处理这些无法路由的消息,最多就是打个日志,存到缓存定时投递,超出投递失败次数进行报警,再手动处理,手动的通病就是麻烦易出错。此外,生产者不止一台机器,那么每台都需要写处理这些回退消息的逻辑代码,反而增加了生产者的复杂性。
那么既不丢失消息,又不增加生产者的复杂性,该怎么做?
可以为队列设置死信交换机来存储投递失败的消息,可是这些不可路由消息根本没有机会进入到队列,因此无法使用死信队列来保存消息。在 RabbitMQ 中,有一种备份交换机的机制存在,可以很好的应对这个问题。
一、备份交换机
备份交换机可以理解为 RabbitMQ 中交换机的“备胎”,当我们为某一个交换机声明一个对应的备份交换机时,就是为它创建一个备胎,当交换机接收到一条不可路由消息时,将会把这条消息转发到备份交换机中,由备份交换机来进行转发和处理,通常备份交换机的类型为 Fanout ,这样就能把所有消息都投递到与其绑定的队列中,然后我们在备份交换机下绑定一个队列,这样所有那些原交换机无法被路由的消息,就会都进入这个队列了。 当然,还可以建立一个报警队列,用独立的消费者来进行监测和报警。
二、代码实现
新增一个备份交换机,绑定在 confirm.exchange 上,当 confirm.exchange 投递消息到队列失败后,将交给备份交换机来投递消息,设置交换机类型为 fanout,有两个队列 backup.queue,还有一个报警队列用来告知我们存在异常情况。
ConfirmConfig 新增配置
修改 confirm.exchange 的代码,绑定上备份交换机,声明其它组件。
/**
* 发布确认机制-示例使用
*/
public static final String CONFIRM_QUEUE_NAME = "confirm.queue";
public static final String CONFIRM_EXCHANGE_NAME = "confirm.exchange";
public static final String ROUTING_KEY_CONFIRM = "confirm.routing";
/** 备份交换机常量 */
public static final String CONFIRM_BACKUP_EXCHANGE = "backup.exchange";
public static final String CONFIRM_BACKUP_QUEUE_NAME = "backup.queue";
public static final String CONFIRM_WARNING_QUEUE_NAME = "warning.queue";
@Bean(CONFIRM_EXCHANGE_NAME