使用默认的exchange

channel.basicPublish("", QUEUE_NAME, null, message.getBytes());

如果用空字符串去申明一个exchange,那么系统就会使用"amq.direct"这个exchange。我们在创建一个queue的时候,默认的都会有一个和新建queue同名的routingKey绑定到这个默认的exchange上去

在方法中的第一个参数是需要输入一个exchange。在RabbitMQ中,所有的消息都必须要通过exchange发送到各个queue里面去。发送者发送消息,其实也就是把消息放到exchange中去。而exchange知道应该把消息放到哪里去。在这个方法中,我们没有输入exchange的名称,只是定义了一个空的echange,而在第二个参数routeKey中输入了我们目标队列的名称。RabbitMQ会帮我定义一个默认的exchange,这个exchange会把消息直接投递到我们输入的队列中,这样服务端只需要直接去这个定义了的队列中获取消息就可以了

信息确认

RabbitMQ有两种应答模式,自动和手动。这也是AMQP协议所推荐的。这在point-to-point和broadcast都是一样的。

自动应答-当RabbitMQ把消息发送到接收端,接收端把消息出队列的时候就自动帮你发应答消息给服务。

手动应答-需要我们开发人员手动去调用ack方法去告诉服务已经收到。

文档推荐在大数据传输中,如果对个别消息的丢失不是很敏感的话选用自动应答比较理想,而对于那些一个消息都不能丢的场景,需要选用手动应答,也就是说在正确处理完以后才应答。如果选择了自动应答,那么消息重发这个功能就没有了。

点对点模式

也就是一发一接的模式,不适用发布/订阅这种广播模式

//autoAck 设置false,消费端挂掉,信息不会丢失,server会re-queue
channel.basicConsume(TASK_QUEUE_NAME, false, consumer);
//向服务器发送应答
channel.basicAck(envelope.getDeliveryTag(), false);

在RabbitMQ中,为了不让消息丢失,它提供了消息应答的概念。当消费者获取到了一个消息以后,需要给RabbitMQ服务一个应答的消息,告知服务我已经收到或正确处理了该消息。那么RabbitMQ可以放心的在队列中删除该消息

队列持久化

//durable 设置true,queue持久化,server重启,此queue不丢失
  channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null);

方法的第四的参数autoDelete,一般都会输入false。文档描述这个参数如果是true的话,意思是:如果这个queue不再使用(没有被订阅)的话,server就会删除它。在我的测试过程中,只要是连接改queue的所有接收者都断开连接的话,该queue就会被删除,即使里面还有没有处理的消息。RabbitMQ的重启也同样会删除他们。如果输入的是false,那与之相连的客户端都断开连接的话,服务是不会删除这个队列的,队列中的消息也就会存在。发送端在没有客户端连接的时候也可以把消息放入改队列,客户端起来的时候,就会得到这些消息。但是如果RabbitMQ服务重启的话,该队列就没有了,里面的消息自然也就没有了。

第三个参数是exclusive,文档描述说,如果是true,那么申明这个queue的connection断了,那么这个队列就被删除了,包括里面的消息。

第二个参数durable,文档描述说,如果是true,则代表是一个持久的队列,那么在服务重启后,也会存在。因为服务会把持久化的queue存放在硬盘上,放服务重启的时候,会重新申明这个queue。当然必须是在autoDelete和exclusive都为false的时候。队列是可以被持久化,但是里面的消息是否为持久化那还要看消息的持久化设置。也就是说,如果重启之前那个queue里面还有没有发出去的消息的话,重启之后那队列里面是不是还存在原来的消息,这个就要取决于发送者在发送消息时对消息的设置了(信息持久化)。

信息持久化

  //BasicProperties设置MessageProperties.PERSISTENT_TEXT_PLAIN,信息持久化
channel.basicPublish("", TASK_QUEUE_NAME,MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes("UTF-8"));
IBasicProperties properties = channel.CreateBasicProperties();
properties.DeliveryMode = 2;
channel.BasicPublish("", "TaskQueue", properties, bytes);

DeliveryMode等于2就说明这个消息是persistent的。1是默认是,不是持久的。在接收者接收消息并处理的时候会出现各种各样的问题:抛出异常导致与RabbitMQ连接断开,程序挂掉,网络问题等等。往往在出现这些问题的时候我们通常都希望队列能保存这些消息,并在程序再次起来的时候能够重新处理,或如果是负载均衡的模式下,能够把这个消息重新分配给其他的同等的接受者来处理。这同样也是RabbitMQ对消息持久化的一种功能。这我们在消息的传输控制中做详细的说明

消息的拒收

拒收,是接收端在收到消息的时候响应给RabbitMQ服务的一种命令,告诉服务器不应该由我处理,或者拒绝处理,扔掉。接收端在发送reject命令的时候可以选择是否要重新放回queue中。如果没有其他接收者监控这个queue的话,要注意一直无限循环发送的危险。

BasicDeliverEventArgs ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
channel.BasicReject(ea.DeliveryTag, false);

BasicReject方法第一个参数是消息的DeliveryTag,对于每个Channel来说,每个消息都会有一个DeliveryTag,一般用接收消息的顺序来表示:1,2,3,4 等等。第二个参数是是否放回queue中,requeue。

BasicReject一次只能拒绝接收一个消息,而BasicNack方法可以支持一次0个或多个消息的拒收,并且也可以设置是否requeue。

channel.BasicNack(3, true, false);

在第一个参数DeliveryTag中如果输入3,则消息DeliveryTag小于等于3的,这个Channel的,都会被拒收。

消息的QoS

QoS = quality-of-service, 顾名思义,服务的质量。通常我们设计系统的时候不能完全排除故障或保证说没有故障,而应该设计有完善的异常处理机制。在出现错误的时候知道在哪里出现什么样子的错误,原因是什么,怎么去恢复或者处理才是真正应该去做的。在接收消息出现故障的时候我们可以通过RabbitMQ重发机制来处理。重发就有重发次数的限制,有些时候你不可能不限次数的重发,这取决于消息的大小,重要程度和处理方式。

甚至QoS是在接收端设置的。发送端没有任何变化,接收端的代码也比较简单,只需要加如下代码:

channel.BasicQos(0, 1, false);

代码第一个参数是可接收消息的大小的,但是似乎在客户端2.8.6版本中它必须为0,即使:不受限制。如果不输0,程序会在运行到这一行的时候报错,说还没有实现不为0的情况。第二个参数是处理消息最大的数量。举个例子,如果输入1,那如果接收一个消息,但是没有应答,则客户端不会收到下一个消息,消息只会在队列中阻塞。如果输入3,那么可以最多有3个消息不应答,如果到达了3个,则发送端发给这个接收方得消息只会在队列中,而接收方不会有接收到消息的事件产生。总结说,就是在下一次发送应答消息前,客户端可以收到的消息最大数量。第三个参数则设置了是不是针对整个Connection的,因为一个Connection可以有多个Channel,如果是false则说明只是针对于这个Channel的。

这种数量的设置,也为我们在多个客户端监控同一个queue的这种负载均衡环境下提供了更多的选择。

 //对服务器确认之前,一次只接受一条信息
channel.basicQos(1);

mandatory标志的作用

在生产者通过channel的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;

他们共有的参数分别是:​ exchange:交换机名称​ routingKey:路由键​ props:消息属性字段,比如消息头部信息等等​ body:消息主体部分

mandatory和immediate是AMQP协议中basic.pulish方法中的两个标志位,它们都有当消息传递过程中不可达目的地时将消息返回给生产者的功能。具体区别在于:

mandatory标志位

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

immediate标志位

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

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

RabbitMQ特性的更多相关文章

  1. RabbitMQ 特性

    1RabbitMQ 特点 与 SpringAMQP 完美整合.API 丰富. 集群模式丰富,表达式配置,HA 模式,镜像队列模型. 保证数据不丢失的前提做到高可靠性.可用性.

  2. RabbitMQ&RocketMQ动态添加Queue参考

    Kafka重复消费与消息丢失参考: https://www.cnblogs.com/kaleidoscope/p/9763053.html https://blog.csdn.net/qingqing ...

  3. RabbitMQ学习笔记(八、RabbitMQ总结)

    1.什么是消息中间件 Message Queue Middleware,简称MQ,是一种利用高效可靠的消息传递机制进行与平台无关的数据交互的技术. 2.MQ的作用 异步:类似于短信业务,将需要发送的消 ...

  4. 消息队列RabbitMQ的安装配置与PHP中的使用

    一.RabbitMQ安装 windows安装 下载地址: https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.3/ra ...

  5. 消息队列那么多,为什么建议深入了解下RabbitMQ?

    你为啥要在项目中选择xxx消息中间件? 提起消息队列,也许你的脑海里会不自觉地蹦出好多概念:JMS.Kafka.RocketMQ.AMQP.RabbitMQ.ActiveMQ.Pulsar.Redis ...

  6. java消息中间件的使用与简介

    一.为什么要使用消息中间件 消息中间件就是可以省去繁琐的步骤,直达目的,怎么讲呢,就是比如你想很多人,知道你的动态,而知道的人可能手机没电,可能手机信号不好,可能手机不在服务区,或者看的人比较忙,看的 ...

  7. 一个基于 .NET Core 2.0 开发的简单易用的快速开发框架 - LinFx

    LinFx 一个基于 .NET Core 2.0 开发的简单易用的快速开发框架,遵循领域驱动设计(DDD)规范约束,提供实现事件驱动.事件回溯.响应式等特性的基础设施.让开发者享受到正真意义的面向对象 ...

  8. 分布式消息通信之RabbitMQ_02

    目录 1. 可靠性投递分析 1.1 消息投递 1.2 消息路由 1.3 消息存储 1.4 消息消费 1.5 其他 2. 高可用架构部署方案 2.1 集群 2.2 镜像 3. 经验总结 3.1 配置文件 ...

  9. 最新咕咆+鲁班+图灵+享学+蚂蚁+硅谷+源码 Java架构师资料《Java架构师VIP课程》

    最新的Java架构师完整资料,完整视频+源码+文档. 每一套都是一百多个G的资料,无密. JAVA架构师全套课程 咕泡学院互联网架构师第一期 咕泡学院互联网架构师第二期 咕泡学院互联网架构师第三期 博 ...

随机推荐

  1. Linux查看网卡带宽的两个命令

    1.ethtool ethtool 网络接口名 #ethtool em4 Settings for em4: Supported ports: [ TP ] Supported link modes: ...

  2. python创建MySQL多实例-1

    python创建MySQL多实例-1 前言 什么是多实例 多实例就是允许在同一台机器上创建另外一套不同配置文件的数据库,他们之间是相互独立的,主要有以下特点, 1> 不能同时使用一个端口 2&g ...

  3. Python3基础 try-多个指定except与不指定except 简单示例

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  4. MySQL 5.7.18 解压版安装

    原文链接:https://my.oschina.net/u/3474266/blog/895696 我在安装免安装版的5.7.18的时候出现了问题,正好找到这个,十分感激 今天下载安装了MySQL C ...

  5. sql server文件另存为的时候,选择文件编码和换行

    文件编码 使用code page来标记的,没有找到utf8 without bom 换行

  6. IDEA启动时自动报Plugin Error错误

    Plugin Error Problems found loading plugins: Plugin "JBoss Integration" was not loaded: re ...

  7. HDU 6073 Matching In Multiplication(拓扑排序+思维)

    http://acm.hdu.edu.cn/showproblem.php?pid=6073 题意:有个二分图,左边和右边的顶点数相同,左边的顶点每个顶点度数为2.现在有个屌丝理解错了最佳完美匹配,它 ...

  8. POJ 1029 False coin

    http://poj.org/problem?id=1029 题意: 在一堆硬币中有一个假硬币,重量是重是轻不知道.每次称量多个硬币,并给出称量结果.判断依据题目给出的几次称量结果能否找出假硬币. 思 ...

  9. Cocos2d-x学习笔记(八)精灵对象的创建

    精灵类即是Sprite,它实际上就是一张二维图. 它首先直接继承了Node类,因此,它具有节点的特征,同时,它也直接继承了TextureProtocol类,因此,它也具有纹理的基本特征. 这里,有必要 ...

  10. DBCC CHECKIDENT 和SET IDENTITY_INSERT table OFF

    TRUNCATE TABLE [DBO].TRACKING_CODE_BASE_Jasmine DELETE FROM TRACKING_CODE_BASE_Jasmine 有同一张表,一次用trun ...