RabbitMQ:消息何去何从

在正常情况下,生产者产生并发送一条消息然后被交换器正确路由到某个队列中。但是如果一条消息不能被正确路由到某个队列时,那么这条消息该何去何从呢?RabbitMQ提供以下几个处理方案:

(1)将消息返回给生产者;

(2)直接将消息丢失;

(3)使用备份交换器将未能被路由的消息存储起来。

1. 返回给生产者

void basicPublish(String exchange, String routingKey, boolean mandatory, boolean immediate, BasicProperties props, byte[] body)
            throws IOException;

在上面这个方法,mandatoryimmediate两个参数都有当消息不能被正确路由时将消息返回给生产者的功能。

  • mandatory

mandatory参数设置为true时,交换器无法根据自身的类型和路由键找到一个符合条件的队列,那么RabbitMQ会调用Basic.Return命令将消息返回给生产者。当该参数设置为false时,出现上述情形,则消息直接被丢弃。

生产者可通过调用channel.addReturnListener来添加返回的消息。

channel.addReturnListener(new ReturnListener() {
    @Override
    public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
        System.out.println("消息不能被正确路由,消息体:" + new String(body));
    }
});

// 设置mandatory参数为true
channel.basicPublish("demo.direct.exchange", "demo.routingKey not exists", true, MessageProperties.PERSISTENT_TEXT_PLAIN, "mandatory is true, but routingKey not exists.".getBytes());
  • immediate

immediate参数设置为true时,如果交换器在将消息路由到队列时发现队列上并不存在任何消费者,那么这条消息将不会存入队列。当与路由键匹配的所有队列都没有消费者时,该消息会通过Basic.Return返回给生产者。

概括来说,mandatory参数告诉服务器至少将该消息路由到一个队列中,否则将消息返回给生产者。immediate参数告诉服务器,如果该消息路由的目标队列上有消费者,则立即投递;如果所有匹配的队列上都没有消费者,则直接将消息返回给生产者,不用将消息存入队列而等待消费者了。

2. 备份交换器

备份交换器的作用是指当生产者在发送消息的时候如果不设置mandatory参数或者设置为false时,那么消息在未被路由的情况下可以使用备份交换器将消息存储起来,在未来需要的时候再去处理这些消息。

// 创建备份交换器
channel.exchangeDeclare("demo.alternate.exchange", "fanout", true, false, null);
channel.queueDeclare("demo.unrouted.queue", true, false, false, null);
channel.queueBind("demo.unrouted.queue", "demo.alternate.exchange", "");

// 创建普通交换器,并为其指定备份交换器
Map<String, Object> arguments = new HashMap<>();
arguments.put("alternate-exchange", "demo.alternate.exchange");
channel.exchangeDeclare("demo.direct.exchange", "direct", true, false, arguments);
channel.queueDeclare("demo.queue", true, false, false, null);
channel.queueBind("demo.queue", "demo.direct.exchange", "demo.routingKey");

// 往普通交换器发送消息
channel.basicPublish("demo.direct.exchange", "demo.routingKey.error",
                     MessageProperties.PERSISTENT_TEXT_PLAIN, "alternate exchange test message.".getBytes());

创建好备份交换器和普通交换器后,当我们发送一条无法被路由的消息时,则可以通过web管理界面看到消息被投递到demo.unrouted.queue队列上来了。

在这里插入图片描述

我们可以看到,声明一个备份交换器和声明一个普通的交换器没有任何区别。但通常在使用场景上来说,备份交换器的类型建议设置成fanout,即忽略绑定键将消息投递到每个队列。当然这里只是建议,并不是强制要求。需要注意的是,消息从普通交换器发送到备份交换器的路由键和从生产者发出的路由键是一样的。

考虑这样一种情况,如果备份交换器的类型为direct,那么当一条消息投递到备份交换器但仍然无法投递到备份交换器所绑定的队列上,则消息丢失。

对于备份交换器,总结以下几种特殊情况:

(1)如果设置的备份交换器不存在,客户端和RabbitMQ服务端都不会有异常,此时消息丢失。

(2)如果备份交换器没有绑定任何队列,客户端和RabbitMQ服务端都不会有异常出现,此时消息丢失。

(3)如果备份交换器没有任何匹配的队列,客户端和RabbitMQ服务端都不会有异常出现,此时消息丢失。

(4)如果备份交换器和madatory参数一起使用,那么madatory参数无效。

——End——
更多精彩分享,可扫码关注微信公众号哦。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值