【RabbitMQ】8、RabbitMQ之mandatory和immediate
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的更多相关文章
- 【RabbitMQ】RabbitMQ的一些基础概念
工作中使用的是RabbitMQ,需要对其进行熟悉.使用之前,弄清楚它是什么东西,解决什么问题. 场景 一些不必实时执行的任务 开发中,有一些任务并无须实时执行,比如: 会员更新个人信息,更新会员信息之 ...
- 初识RabbitMQ,附RabbitMQ+PHP演示实例
RabbitMQ是一个在AMQP基础上实现的企业级消息系统.何谓消息系统,就是消息队列系统,消息队列是""消费-生产者模型""的一个典型的代表,一端往消息队列中 ...
- 我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比(转载)
转载自:https://www.sojson.com/blog/48.html 前言: MQ 是什么?队列是什么,MQ 我们可以理解为消息队列,队列我们可以理解为管道.以管道的方式做消息传递. 场景: ...
- 【RabbitMQ】 RabbitMQ配置开机启动
环境 系统:Linux(CentOS 7.2) Erlang环境:21.1(安装参考[Erlang]源码安装) RabbitMQ:3.7.9(安装参考[RabbitMQ] RabbitMQ安装) 配置 ...
- 为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比
原文:https://www.sojson.com/blog/48.html 前言: MQ 是什么?队列是什么,MQ 我们可以理解为消息队列,队列我们可以理解为管道.以管道的方式做消息传递. 场景: ...
- 快速掌握RabbitMQ(一)——RabbitMQ的基本概念、安装和C#驱动
1 RabbitMQ简介 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现,官网地址:http://www.rabbitmq.com.Ra ...
- 【详细】【转】C#中理解委托和事件 事件的本质其实就是委托 RabbitMQ英汉互翼(一),RabbitMQ, RabbitMQ教程, RabbitMQ入门
[详细][转]C#中理解委托和事件 文章是很基础,但很实用,看了这篇文章,让我一下回到了2016年刚刚学委托的时候,故转之! 1.委托 委托类似于C++中的函数指针(一个指向内存位置的指针).委托 ...
- Docker安装RabbitMQ,RabbitMQ Management使用
原文:Docker安装RabbitMQ,RabbitMQ Management使用 版权声明:本文为博主原创文章,未经博主允许不得转载.需要转载请先评论或者邮箱联系我,谢谢! https://blog ...
- rabbitmq++:RabbitMQ的消息确认ACK机制介绍
1):什么是消息确认ACK. 答:如果在处理消息的过程中,消费者的服务器在处理消息的时候出现异常,那么可能这条正在处理的消息就没有完成消息消费,数据就会丢失.为了确保数据不会丢失,RabbitMQ支持 ...
- 【RabbitMQ】RabbitMQ在Windows的安装和简单的使用
版本说明 使用当前版本:3.5.4 安装与启动 在官网上下载其Server二进制安装包,在Windows上的安装时简单的,与一般软件没什么区别. 安装前会提示你,还需要安装Erlang,并打开下载页面 ...
随机推荐
- 判断终端类型、微信的文章防盗链、h5页面跳转打开新的app、跳转到app市场
判断终端的类型.安卓.ios.微信.qq function GetMobelType() { var browser = { ...
- 突然 不能f**q
ss 突然访问不了,于是去查看ip是否被f,发现国outer 国inner 都通,不知道什么情况,后来把 系统代理模式 改为全局,发觉可以,又把他改为 pac模式,正常了. 记录一 ...
- APK防护——Anti_Virtual App的思路和实现
作者:HAI_i 原文来自:https://bbs.ichunqiu.com/thread-42982-1-1.html 0×00 前言 Virtual App是一个很强大的存在,破坏了Android ...
- Android 框架式编程 —— 起篇
一般的,在开发的时候,写过的代码在需求变更后,发现需要改动非常多的地方,那么说明之前的代码的架构肯定是存在问题的. 下面我们结合面向对象的六大基本原则谈Android 框架式编程.首先先介绍一下面向对 ...
- js中的柯里化
概述 今天查询事件绑定资料的时候偶然遇到了柯里化这个词,很感兴趣,于是记录下来供以后开发时参考,相信对其他人也有用. 定义 柯里化是函数式编程里面的术语,它是把接受多个参数的函数变换成接受一个单一参数 ...
- idea : shorten command line
[官方文档]:IntelliJ IDEA 2017.3 EAP: Configurable command line shortener and more 如果类路径太长,或者有许多VM参数,程序就无 ...
- 使用Swagger 搭建高可读性ASP.Net WebApi文档
一.前言 在最近一个商城项目中,使用WebApi搭建API项目.但开发过程中,前后端工程师对于沟通接口的使用,是非常耗时的.之前也有用过Swagger构建WebApi文档,但是API文档的可读性并不高 ...
- 上下文无关的GMM-HMM声学模型
一.语音识别基本介绍 (一)统计语音识别的基本等式 X------声学特征向量序列,观测值 W------单词序列 W*------给定观测值下,概率最大的单词序列 应用贝叶斯理论等价于 进而得出统计 ...
- 自动化测试 selenium 环境搭建
做 web 项目,测试是无法避免的.对于某些特定功能,采用单元测试就行.但如果想对网站进行整体测试,人工点击测试可行但有点累,如果能借助自动化测试工具就更好了.selenium 就是一款能满足这样要求 ...
- Spark之submit任务时的Initial job has not accepted any resources; check your cluster UI to ensure that workers are registered and have sufficient memory
Spark submit任务到Spark集群时,会出现如下异常: Exception 1:Initial job has not accepted any resources; check your ...