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

【RabbitMQ】8、RabbitMQ之mandatory和immediate的更多相关文章

  1. 【RabbitMQ】RabbitMQ的一些基础概念

    工作中使用的是RabbitMQ,需要对其进行熟悉.使用之前,弄清楚它是什么东西,解决什么问题. 场景 一些不必实时执行的任务 开发中,有一些任务并无须实时执行,比如: 会员更新个人信息,更新会员信息之 ...

  2. 初识RabbitMQ,附RabbitMQ+PHP演示实例

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

  3. 我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比(转载)

    转载自:https://www.sojson.com/blog/48.html 前言: MQ 是什么?队列是什么,MQ 我们可以理解为消息队列,队列我们可以理解为管道.以管道的方式做消息传递. 场景: ...

  4. 【RabbitMQ】 RabbitMQ配置开机启动

    环境 系统:Linux(CentOS 7.2) Erlang环境:21.1(安装参考[Erlang]源码安装) RabbitMQ:3.7.9(安装参考[RabbitMQ] RabbitMQ安装) 配置 ...

  5. 为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比

    原文:https://www.sojson.com/blog/48.html 前言: MQ 是什么?队列是什么,MQ 我们可以理解为消息队列,队列我们可以理解为管道.以管道的方式做消息传递. 场景: ...

  6. 快速掌握RabbitMQ(一)——RabbitMQ的基本概念、安装和C#驱动

    1 RabbitMQ简介 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现,官网地址:http://www.rabbitmq.com.Ra ...

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

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

  8. Docker安装RabbitMQ,RabbitMQ Management使用

    原文:Docker安装RabbitMQ,RabbitMQ Management使用 版权声明:本文为博主原创文章,未经博主允许不得转载.需要转载请先评论或者邮箱联系我,谢谢! https://blog ...

  9. rabbitmq++:RabbitMQ的消息确认ACK机制介绍

    1):什么是消息确认ACK. 答:如果在处理消息的过程中,消费者的服务器在处理消息的时候出现异常,那么可能这条正在处理的消息就没有完成消息消费,数据就会丢失.为了确保数据不会丢失,RabbitMQ支持 ...

  10. 【RabbitMQ】RabbitMQ在Windows的安装和简单的使用

    版本说明 使用当前版本:3.5.4 安装与启动 在官网上下载其Server二进制安装包,在Windows上的安装时简单的,与一般软件没什么区别. 安装前会提示你,还需要安装Erlang,并打开下载页面 ...

随机推荐

  1. Struts2学习第四天——拦截器及文件上传

    1.概述 Struts2的很多核心功能都是由拦截器完成的. 拦截器很好的实现了AOP的编程思想,在动作的执行之前和结果的返回之后,做拦截处理. 2.struts2的默认拦截器栈 3.自定义拦截器 St ...

  2. EF6学习笔记(六续) 复杂数据模型建表测试

    测试以下几种模型关系: 1对1或0  . 1对多  . 多对多 1 对 1 或 0 如果直接定义两个模型,相互直接增加导航属性,会提示错误,必须为这个对应关系设定主副关系: public class ...

  3. git diff 理解

    0. 理解 git diff 返回信息 1. 命令 $ git diff README.md 2. 返回信息,注解 diff --git a/README.md b/README.md ## 1. 表 ...

  4. ZZ 使用Jenkins配置Git+Maven的自动化构建

    http://blog.csdn.net/xlgen157387/article/details/50353317 Jenkins是帮我们将代码进行统一的编译打包.还可以放到tomcat容器中进行发布 ...

  5. [UWP]不那么好用的ContentDialog

    ContentDialog是UWP开发中最常用的组件之一,一个体验良好的UWP应用很难避免不去使用它.博客园里也有许多的文章介绍如何来利用ContentDialog实现各种自定义样式的弹窗界面.不过实 ...

  6. 背水一战 Windows 10 (92) - 文件系统: 读写“最近访问列表”和“未来访问列表”, 管理以及使用索引

    [源码下载] 背水一战 Windows 10 (92) - 文件系统: 读写“最近访问列表”和“未来访问列表”, 管理以及使用索引 作者:webabcd 介绍背水一战 Windows 10 之 文件系 ...

  7. Swift5 语言指南(十八) 可选链接

    可选链接是一个查询和调用当前可选的可选项的属性,方法和下标的过程nil.如果optional包含值,则属性,方法或下标调用成功; 如果是可选的nil,则返回属性,方法或下标调用nil.多个查询可以链接 ...

  8. fiddler 使用方法汇总

    作为网络开发人员,怎能不使用一些抓包工具呢?fiddler是个不错的选择. 不过,一般情况下,我们往往使用浏览器自带的控制台的[网络]选项就可以达到查看数据的通信情况了,当然,一些浏览器不容易捕捉的事 ...

  9. java中微信统一下单采坑(app微信支付)

    app支付前java后台统一下单文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1 微信支付接口签名校验工具:https ...

  10. Spring Boot 配置随机数技巧

    Spring Boot支持在系统加载的时候配置随机数. 添加config/random.properties文件,添加以下内容: #随机32位MD5字符串 user.random.secret=${r ...