从本节开始称Sender为生产者 , Recv为消费者

 

一、消息确认

为了确保消息一定被消费者处理,rabbitMQ提供了消息确认功能,就是在消费者处理完任务之后,就给服务器一个回馈,服务器就会将该消息删除,如果消费者超时不回馈,那么服务器将就将该消息重新发送给其他消费者

默认是开启的,在消费者端通过下面的方式开启消息确认,  首先将autoAck自动确认关闭,等我们的任务执行完成之后,手动的去确认,类似JDBC的autocommit一样


QueueingConsumer consumer = new QueueingConsumer(channel);
boolean autoAck = false;
channel.basicConsume("hello", autoAck, consumer);

在前面的例子中使用的是channel.basicConsume(channelName, true, consumer) ; 在接收到消息后,就会自动反馈一个消息给服务器。

下面这个例子来测试消息确认的功能。

Sender03.java

 package com.zf.rabbitmq03;

 import java.io.IOException;

 import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; /**
* 发送消息
* @author zhoufeng
*
*/
public class Sender03 { public static void main(String[] args) throws IOException { ConnectionFactory connFac = new ConnectionFactory() ; //RabbitMQ-Server安装在本机,所以直接用127.0.0.1
connFac.setHost("127.0.0.1"); //创建一个连接
Connection conn = connFac.newConnection() ; //创建一个渠道
Channel channel = conn.createChannel() ; //定义Queue名称
String queueName = "queue01" ; //为channel定义queue的属性,queueName为Queue名称
channel.queueDeclare( queueName , false, false, false, null) ; String msg = "Hello World!"; //发送消息
channel.basicPublish("", queueName , null , msg.getBytes()); System.out.println("send message[" + msg + "] to "+ queueName +" success!"); channel.close();
conn.close(); } }

与Sender01.java一样,没有什么区别。

Recv03.java

 package com.zf.rabbitmq03;

 import java.io.IOException;

 import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.ConsumerCancelledException;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.QueueingConsumer.Delivery;
import com.rabbitmq.client.ShutdownSignalException; /**
* 接收消息
* @author zhoufeng
*
*/
public class Recv03 { public static void main(String[] args) throws IOException, ShutdownSignalException, ConsumerCancelledException, InterruptedException { ConnectionFactory connFac = new ConnectionFactory() ; connFac.setHost("127.0.0.1"); Connection conn = connFac.newConnection() ; Channel channel = conn.createChannel() ; String channelName = "channel01"; channel.queueDeclare(channelName, false, false, false, null) ; //配置好获取消息的方式
QueueingConsumer consumer = new QueueingConsumer(channel) ; //取消 autoAck
boolean autoAck = false ; channel.basicConsume(channelName, autoAck, consumer) ; //循环获取消息
while(true){ //获取消息,如果没有消息,这一步将会一直阻塞
Delivery delivery = consumer.nextDelivery() ; String msg = new String(delivery.getBody()) ; //确认消息,已经收到
channel.basicAck(delivery.getEnvelope().getDeliveryTag()
, false); System.out.println("received message[" + msg + "] from " + channelName);
} } }

注意:一旦将autoAck关闭之后,一定要记得处理完消息之后,向服务器确认消息。否则服务器将会一直转发该消息

如果将上面的channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);注释掉, Sender03.java只需要运行一次 , Recv03.java每次运行将都会收到HelloWorld消息

注意:

但是这样还是不够的,如果rabbitMQ-Server突然挂掉了,那么还没有被读取的消息还是会丢失 ,所以我们可以让消息持久化。 只需要在定义Queue时,设置持久化消息就可以了,方法如下:


boolean durable = true;
channel.queueDeclare(channelName, durable, false, false, null);

这样设置之后,服务器收到消息后就会立刻将消息写入到硬盘,就可以防止突然服务器挂掉,而引起的数据丢失了。  但是服务器如果刚收到消息,还没来得及写入到硬盘,就挂掉了,这样还是无法避免消息的丢失。

 

二、公平调度

上一个例子能够实现发送一个Message与接收一个Message

从上一个Recv01中可以看出,必须处理完一个消息,才会去接收下一个消息。如果生产者众多,那么一个消费者肯定是忙不过来的。此时就可以用多个消费者来对同一个Channel的消息进行处理,并且要公平的分配任务给多个消费者。不能部分很忙  部分总是空闲

实现公平调度的方式就是让每个消费者在同一时刻会分配一个任务。 通过channel.basicQos(1);可以设置

rabbitMQ学习笔记(三) 消息确认与公平调度消费者的更多相关文章

  1. RabbitMQ 消息确认与公平调度消费者

    一.消息确认 为了确保消息一定被消费者处理,rabbitMQ提供了消息确认功能,就是在消费者处理完任务之后,就给服务器一个回馈,服务器就会将该消息删除,如果消费者超时不回馈,那么服务器将就将该消息重新 ...

  2. rabbitMQ学习笔记(五) 消息路由

    生产者会生产出很多消息 , 但是不同的消费者可能会有不同的需求,只需要接收指定的消息,其他的消息需要被过滤掉. 这时候就可以对消息进行过滤了. 在消费者端设置好需要接收的消息类型. 如果不使用默认的E ...

  3. Linux内核学习笔记(7)--完全公平调度(CFS)

    一.完全公平调度算法 完全公平调度 CFS 的出发点基于一个简单的理念:进程调度的效果应该如同系统具备一个理想中的完美多任务处理器.在这种系统中,每个进程能够获得 1/n 的处理器时间(n 为可运行进 ...

  4. RabbitMQ学习笔记三:Java实现RabbitMQ之与Spring集成

    搭建好maven项目环境,加入RabbitMQ依赖包 <dependency> <groupId>org.springframework.amqp</groupId> ...

  5. RabbitMQ学习笔记五:RabbitMQ之优先级消息队列

    RabbitMQ优先级队列注意点: 1.只有当消费者不足,不能及时进行消费的情况下,优先级队列才会生效 2.RabbitMQ3.5以后才支持优先级队列 代码在博客:RabbitMQ学习笔记三:Java ...

  6. RabbitMQ学习系列三-C#代码接收处理消息

    RabbitMQ学习系列三:.net 环境下 C#代码订阅 RabbitMQ 消息并处理 http://www.80iter.com/blog/1438251320680361 http://www. ...

  7. rabbitmq学习(三) —— 工作队列

    工作队列,又称任务队列,主要思想是避免立即执行资源密集型任务,并且必须等待完成.相反地,我们进行任务调度,我们将一个任务封装成一个消息,并将其发送到队列.工作进行在后台运行不断的从队列中取出任务然后执 ...

  8. 物联网学习笔记三:物联网网关协议比较:MQTT 和 Modbus

    物联网学习笔记三:物联网网关协议比较:MQTT 和 Modbus 物联网 (IoT) 不只是新技术,还是与旧技术的集成,其关键在于通信.可用的通信方法各不相同,但是,各种不同的协议在将海量“事物”连接 ...

  9. 官网英文版学习——RabbitMQ学习笔记(十)RabbitMQ集群

    在第二节我们进行了RabbitMQ的安装,现在我们就RabbitMQ进行集群的搭建进行学习,参考官网地址是:http://www.rabbitmq.com/clustering.html 首先我们来看 ...

随机推荐

  1. 单片机project师必备的知识

    C语言编程 程序编译过程  哪部分干什么 数据结构  链表 二叉树 算法   数组  堆栈 队列算法 遍历 常量在内存中的表现形式 语法和内存的相应关系 数电 UML 类图 时序图 状态图 用例图   ...

  2. spring注入对象类型的属性

    一.1.创建service类和Dao类 (1)在service中得到dao对象 2.具体实现过程 (1)在service里边把dao作为类型属性 (2)生成dao类型属性的set方法 public c ...

  3. Linux下开启vim高亮

    默认是不高亮的. [root@local ~]# vi ~/.vimrc 没有则新建这个文件. 或者修改 [root@local vim74]# vi /etc/vimrc 添加一行. syntax ...

  4. 国内物联网平台初探(八):中移物联网开放平台OneNet

    平台定位 OneNET是中移物联网有限公司搭建的开放.共赢设备云平台,为各种跨平台物联网应用.行业解决方案,提供简便的云端接入.存储.计算和展现,快速打造物联网产品应用,降低开发成本. IoT Paa ...

  5. [.Net] 导出Excel中身份证等数字串的解决方式

    public static void DataTableToExcel(System.Data.DataTable dtData, String FileName) { GridView dgExpo ...

  6. [luogu普及] ---P1032 字串变换

    目的 刷完100AC (最近很不舒服,写博客耗时啊 记录第一个字符串的题目 参考 https://www.luogu.org/blog/user20197/solution-p1032 代码 #inc ...

  7. docker(部署常见应用):docker部署mysql

    上节回顾:docker(部署常见应用):docker部署nginx docker部署mysql:5.7.26 # 下载镜像 docker pull mysql: # 查看镜像 docker image ...

  8. javascript 将单词首字母大写,其余小写

    // 1 别人写的,我拿来参考了一下 function titleCase(str) { var array = str.toLowerCase().split(" "); for ...

  9. Tomcat 报错 记录

    Resource is out of sync with the file system: 该错误为替换了image中的图片而没有进行更新,造成找不到该资源,进而保存,解决只要eclipse刷新一下F ...

  10. 解决Android单个dex文件不能超过65535个方法问题

    一.找坑:谷歌规定单个dex文件中的方法不能超过65536的限制 我们编写项目过程中在工程的lib文件夹下引用的第三方插件jar包太多或者项目过大,编译运行时就有可能报出com.android.dex ...