1. 概述

mandatory和immediate是AMQP协议中basic.publish方法中的两个标识位,它们都有当消息传递过程中不可达目的地时将消息返回给生产者的功能。对于刚开始接触RabbitMQ的朋友特别容易被这两个参数搞混,这里博主整理了写资料,简单讲解下这两个标识位。

mandatory 
当mandatory标志位设置为true时,如果exchange根据自身类型和消息routeKey无法找到一个符合条件的queue,那么会调用basic.return方法将消息返回给生产者(Basic.Return + Content-Header + Content-Body);当mandatory设置为false时,出现上述情形broker会直接将消息扔掉。

mandatory标志的作用:在消息没有被路由到合适队列情况下会将消息返还给消息发布者,同时我们测试了哪些情况下消息不会到达合适的队列,测试1演示的是创建了exchange但是没有为他绑定队列导致的消息未到达合适队列,测试3演示的是创建了exchange同时创建了queue,但是在将两者绑定的时候,使用的bindingKey和消息发布者使用的rountingKey不一致导致的消息未到达合适队列;

immediate 
当immediate标志位设置为true时,如果exchange在将消息路由到queue(s)时发现对于的queue上么有消费者,那么这条消息不会放入队列中。当与消息routeKey关联的所有queue(一个或者多个)都没有消费者时,该消息会通过basic.return方法返还给生产者。

概括来说,mandatory标志告诉服务器至少将该消息route到一个队列中,否则将消息返还给生产者;immediate标志告诉服务器如果该消息关联的queue上有消费者,则马上将消息投递给它,如果所有queue都没有消费者,直接把消息返还给生产者,不用将消息入队列等待消费者了。


2. mandatory

在生产者通过channle的basicPublish方法发布消息时,通常有几个参数需要设置,为此我们有必要了解清楚这些参数代表的具体含义及其作用,查看channel接口,会发现存在3个重载的basicPublish方法:

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

mandatory和immediate上面已经解释过了,其余的参数分别是: 
exchange:交换机名称 
routingkey:路由键 
props:消息属性字段,比如消息头部信息等等 
body:消息主体部分

本节主要讲述mandatory, 下面我们写一个demo,在RabbitMQ broker中有: 
exchange : exchange.mandatory.test 
queue: queue.mandatory.test 
exchange路由到queue的routingkey是mandatory 
这里先不讲当前的exchange绑定到queue中,即:

channel.basicPublish(exchangeName, "", mandatory, immediate, MessageProperties.PERSISTENT_TEXT_PLAIN, "===mandatory===".getBytes());

详细代码如下:

package com.vms.test.zzh.rabbitmq.self;import com.rabbitmq.client.*;import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; /** * Created by hidden on 2017/2/7. */ public class RBmandatoryTest { public static final String ip = "10.198.197.73"; public static final int port = 5672; public static final String username = "root"; public static final String password = "root"; public static final String queueName = "queue.mandatory.test"; public static final String exchangeName = "exchange.mandatory.test"; public static final String routingKey = "mandatory"; public static final Boolean mandatory = true; public static final Boolean immediate = false; public static void main(String[] args) { try { ConnectionFactory factory = new ConnectionFactory(); factory.setHost(ip); factory.setPort(port); factory.setUsername(username); factory.setPassword(password); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.basicQos(1); channel.basicPublish(exchangeName, "", mandatory, immediate, MessageProperties.PERSISTENT_TEXT_PLAIN, "===mandatory===".getBytes()); // channel.close(); // connection.close(); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } }

运行,之后通过wireshark抓包工具可以看到如下图所示: 

这里可以看到最后执行了basic.return方法,将发布者发出的消息返回给了发布者,查看协议的arguments参数部分可以看到:reply-text字段值为NO_ROUTE,表示消息并没有路由到合适的队列中;

那么我们该怎么获取到没有被正确路由到合适队列的消息呢?这时候可以通过为channel信道设置ReturnListener监听器来实现,具体代码(main函数部分):

try {ConnectionFactory factory = new ConnectionFactory();factory.setHost(ip);factory.setPort(port); factory.setUsername(username); factory.setPassword(password); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.basicQos(1); channel.basicPublish(exchangeName, "", mandatory, immediate, MessageProperties.PERSISTENT_TEXT_PLAIN, "===mandatory===".getBytes()); channel.addReturnListener(new ReturnListener() { public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties basicProperties, byte[] body) throws IOException { String message = new String(body); System.out.println("Basic.return返回的结果是:"+message); } }); // channel.close(); // connection.close(); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); }

运行结果:

Basic.return返回的结果是:===mandatory===

下面我们来看一下,设置mandatory标志且exchange路由到queue中,代码部分只需要将:

channel.basicPublish(exchangeName, "", mandatory, immediate, MessageProperties.PERSISTENT_TEXT_PLAIN, "===mandatory===".getBytes());

改为

channel.basicPublish(exchangeName, routingKey, mandatory, immediate, MessageProperties.PERSISTENT_TEXT_PLAIN, "===mandatory===".getBytes());

即可。 
通过wireshark抓包如下: 

可以看到并不会有basic.return方法被调用。查看RabbitMQ管理界面发现消息已经到达了队列。


3. immediate

在RabbitMQ3.0以后的版本里,去掉了immediate参数的支持,发送带immediate标记的publish会返回如下错误: 
“{amqp_error,not_implemented,”immediate=true”,’basic.publish’}”

为什么移除immediate标记,参见如下版本变化描述: 
Removal of “immediate” flag 
What changed? We removed support for the rarely-used “immediate” flag on AMQP’s basic.publish. 
Why on earth did you do that? Support for “immediate” made many parts of the codebase more complex, particularly around mirrored queues. It also stood in the way of our being able to deliver substantial performance improvements in mirrored queues. 
What do I need to do? If you just want to be able to publish messages that will be dropped if they are not consumed immediately, you can publish to a queue with a TTL of 0. 
If you also need your publisher to be able to determine that this has happened, you can also use the DLX feature to route such messages to another queue, from which the publisher can consume them. 
这段解释的大概意思是:immediate标记会影响镜像队列性能,增加代码复杂性,并建议采用“TTL”和“DLX”等方式替代。

出处:https://yq.aliyun.com/articles/238349?spm=5176.8091938.0.0.EfSZh4

http://www.mamicode.com/info-detail-1673003.html?spm=5176.100239.blogcont238349.8.FAbhIg

转载于:https://www.cnblogs.com/wangzhongqiu/p/7832796.html

【RabbitMQ】8、RabbitMQ之mandatory和immediate相关推荐

  1. RabbitMQ原理RabbitMQ各组件作用RabbitMQ使用场景

    RabbitMQ原理 RabbitMQ介绍 MQ全称为Message Queue, 是一种分布式应用程序的的通信方法,它是消费-生产者模型的一个典型的代表 producer往消息队列中不断写入消息,而 ...

  2. RabbitMQ【RabbitMQ】

    RabbitMQ[RabbitMQ] 前言 说明 推荐 RabbitMQ 一.中间件 1.什么是中间件 2.中间件技术及架构的概述 3.基于消息中间件的分布式系统的架构 4.消息队列协议 5.消息队列 ...

  3. Spring Boot2.x-15 整合RabbitMQ 及RabbitMQ的基本使用

    文章目录 概述 在Docker CE中安装RabbitMQ 依赖 配置 基本使用 手工创建队列,发送消息到指定的队列 自动创建队列,发送消息到指定的队列 自动创建队列,Exchange和队列绑定 自动 ...

  4. 初识RabbitMQ,附RabbitMQ+PHP演示实例(亲测通过)

    RabbitMQ是一个在AMQP基础上实现的企业级消息系统.何谓消息系统,就是消息队列系统,消息队列是""消费-生产者模型""的一个典型的代表,一端往消息队列中 ...

  5. rabbitmq多个消费者_为什么要选择RabbitMQ,RabbitMQ简介,各种MQ选型对比

    MQ 是什么?队列是什么,MQ 我们可以理解为消息队列,队列我们可以理解为管道.以管道的方式做消息传递. 场景: 1.其实我们在双11的时候,当我们凌晨大量的秒杀和抢购商品,然后去结算的时候,就会发现 ...

  6. RabbitMQ系列——Rabbitmq Plugin configuration unchanged. 解决方案

    RabbitMQ系列--Rabbitmq Plugin configuration unchanged. 解决方案 一.问题概述 cmd命令窗口执行rabbitmq-plugins enable ra ...

  7. 【RabbitMQ】RabbitMQ架构模型

    目录 RabbitMQ架构模型 Producer:生产者 Consumer:消费方 Broker:服务节点 Queue队列: Exchange:交换器 --fanout广播 --topic主题 --d ...

  8. java学习day50(RabbitMQ)RabbitMQ

    1. 消息队列概述 1.1. 消息队列 MQ MQ 全称为 Message Queue ,消息队列是应用程序和应用程序之间的通信方法. 为什么使用 MQ 在项目中,可将一些无需即时返回且耗时的操作提取 ...

  9. 【详细】【转】C#中理解委托和事件 事件的本质其实就是委托 RabbitMQ英汉互翼(一),RabbitMQ, RabbitMQ教程, RabbitMQ入门...

    [详细][转]C#中理解委托和事件 文章是很基础,但很实用,看了这篇文章,让我一下回到了2016年刚刚学委托的时候,故转之! 1.委托 委托类似于C++中的函数指针(一个指向内存位置的指针).委托是C ...

  10. 【深入理解RabbitMQ】RabbitMQ exclusive和mandatory的理解

                                 RabbitMQ exclusive和mandatory的理解 exclusive 排他性 队列的排他性的理解,是针对首次建立连接的,一个连接 ...

最新文章

  1. html:text中readonly,HTML Input Text readOnly用法及代码示例
  2. python自学攻略-你是如何自学 Python 的?
  3. LeetCode 454 4Sum II(哈希法)
  4. CSS3伪类选择器:nth-child()(nth-child(odd)/nth-child(even))
  5. Effective C++学习第五天
  6. linux查看命令类型,查看linux命令类型
  7. JVM 学习四:类加载之双亲委派机制与沙箱安全机制
  8. idea maven dependencies 总是报红
  9. JavaScript验证正则表达式大全
  10. Cisco 2960交换机配置
  11. CCF201409-2 画图(100分)
  12. linkin大话设计模式--抽象工厂
  13. mysql存储过程返回结果集_原来MySQL的存储过程也可以这么玩?
  14. Sketch56.1汉化
  15. 我的世界java版地狱_我的世界怎么去地狱_Minecraft地狱门建造教程 - 我的世界中文站...
  16. jsp之${CTX}理解
  17. [希腊神话--英语]另类重看英语词汇---序言
  18. 信息安全 数据赛 铁人三项_2018.5.18信息安全铁人三项赛数据赛题解
  19. Show出你的高超技能 首届“中国高性能云计算创新大赛”要开赛啦!
  20. 用JBE修改Java字节码

热门文章

  1. jQUery中closest和parents的主要区别是
  2. 【C#-枚举】枚举的使用
  3. java操作mongodb(连接池)(转)
  4. python教程--__init_.py的作用
  5. 2.9 bitset
  6. 分类树/装袋法/随机森林算法的R语言实现
  7. [Object-C语言随笔之三] 类的创建和实例化以及函数的添加和调用!
  8. 网络安全不是奢侈品,而是必需品
  9. 《Adobe Illustrator大师班:经典作品与完美技巧赏析》—Svetlana Makarova
  10. 全栈测试:平衡单元测试和端到端测试