RabbitMQ六种队列模式-工作队列模式
前言
RabbitMQ六种队列模式-简单队列
RabbitMQ六种队列模式-工作队列 [本文]
RabbitMQ六种队列模式-发布订阅
RabbitMQ六种队列模式-路由模式
RabbitMQ六种队列模式-主题模式
上文我们了解了 RabbitMQ 六种队列模式中的简单队列,代码也是非常的简单,比较容易理解。
但是简单队列有个缺点,简单队列是一一对应的关系,即点对点,一个生产者对应一个消费者,按照这个逻辑,如果我们有一些比较耗时的任务,也就意味着需要大量的时间才能处理完毕,显然简单队列模式并不能满足我们的工作需求,我们今天再来看看工作队列。
文章目录
1. 什么是工作队列2. 代码部分2.1 生产者2.2 消费者3. 循环分发3.1 启动生产者3.2 启动两个消费者3.3 公平分发4. 消息持久化4.1 问题背景4.2 参数配置5. 工作队列总结
1. 什么是工作队列
工作队列:用来将耗时的任务分发给多个消费者(工作者)
主要解决问题:处理资源密集型任务,并且还要等他完成。有了工作队列,我们就可以将具体的工作放到后面去做,将工作封装为一个消息,发送到队列中,一个工作进程就可以取出消息并完成工作。如果启动了多个工作进程,那么工作就可以在多个进程间共享。
工作队列也称为公平性队列模式,怎么个说法呢?
循环分发,假如我们拥有两个消费者,默认情况下,RabbitMQ 将按顺序将每条消息发送给下一个消费者,平均而言,每个消费者将获得相同数量的消息,这种分发消息的方式称为轮询。
看代码吧。
2. 代码部分
2.1 生产者
创建50个消息
public class Producer2 {
/** 队列名称 */
private static final String QUEUE_NAME = "test_queue";
public static void main(String[] args) throws IOException, TimeoutException {
/** 1.获取连接 */
Connection newConnection = MQConnectionUtils.newConnection();
/** 2.创建通道 */
Channel channel = newConnection.createChannel();
/**3.创建队列声明 */
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
/**保证一次只分发一次 限制发送给同一个消费者 不得超过一条消息 */
channel.basicQos(1);
for (int i = 1; i <= 50; i++) {
String msg = "生产者消息_" + i;
System.out.println("生产者发送消息:" + msg);
/**4.发送消息 */
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
}
channel.close();
newConnection.close();
}
}
2.2 消费者
public class Customer2_1 {
/**
* 队列名称
*/
private static final String QUEUE_NAME = "test_queue";
public static void main(String[] args) throws IOException, TimeoutException {
System.out.println("001");
/** 1.获取连接 */
Connection newConnection = MQConnectionUtils.newConnection();
/** 2.获取通道 */
final Channel channel = newConnection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
/** 保证一次只分发一次 限制发送给同一个消费者 不得超过一条消息 */
channel.basicQos(1);
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String msgString = new String(body, "UTF-8");
System.out.println("消费者获取消息:" + msgString);
try {
Thread.sleep(1000);
} catch (Exception e) {
} finally {
/** 手动回执消息 */
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
/** 3.监听队列 */
channel.basicConsume(QUEUE_NAME, false, defaultConsumer);
}
}
3. 循环分发
3.1 启动生产者
3.2 启动两个消费者
在生产者中我们发送了50条消息进入队列,而上方消费者启动图里很明显的看到轮询的效果,就是每个消费者会分到相同的队列任务。
3.3 公平分发
由于上方模拟的是非常简单的消息队列的消费,假如有一些非常耗时的任务,某个消费者在缓慢地进行处理,而另一个消费者则空闲,显然是非常消耗资源的。
再举一个例子,一个1年的程序员,跟一个3年的程序员,分配相同的任务量,明显3年的程序员处理起来更加得心应手,很快就无所事事了,但是3年的程序员拿着非常高的薪资!显然3年的程序员应该承担更多的责任,那怎么办呢?
公平分发。
其实发生上述问题的原因是 RabbitMQ 收到消息后就立即分发出去,而没有确认各个工作者未返回确认的消息数量,类似于TCP/UDP中的UDP,面向无连接。
因此我们可以使用 basicQos 方法,并将参数 prefetchCount 设为1,告诉 RabbitMQ 我每次值处理一条消息,你要等我处理完了再分给我下一个。这样 RabbitMQ 就不会轮流分发了,而是寻找空闲的工作者进行分发。
关键性代码:
/** 2.获取通道 */
final Channel channel = newConnection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
/** 保证一次只分发一次 限制发送给同一个消费者 不得超过一条消息 */
channel.basicQos(1);
4. 消息持久化
4.1 问题背景
上边我们提到的公平分发是由消费者收取消息时确认解决的,但是这里面又会出现被 kill 的情况。
当有多个消费者同时收取消息,且每个消费者在接收消息的同时,还要处理其它的事情,且会消耗很长的时间。在此过程中可能会出现一些意外,比如消息接收到一半的时候,一个消费者死掉了。
这种情况要使用消息接收确认机制,可以执行上次宕机的消费者没有完成的事情。
但是在默认情况下,我们程序创建的消息队列以及存放在队列里面的消息,都是非持久化的。当RabbitMQ死掉了或者重启了,上次创建的队列、消息都不会保存。
怎么办呢?
4.2 参数配置
参数配置一:生产者创建队列声明时,修改第二个参数为 true
/**3.创建队列声明 */
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
参数配置二:生产者发送消息时,修改第三个参数为MessageProperties.PERSISTENT_TEXT_PLAIN
for (int i = 1; i <= 50; i++) {
String msg = "生产者消息_" + i;
System.out.println("生产者发送消息:" + msg);
/**4.发送消息 */
channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes());
}
5. 工作队列总结
1、循环分发:消费者端在信道上打开消息应答机制,并确保能返回接收消息的确认信息,这样可以保证消费者发生故障也不会丢失消息。
2、消息持久化:服务器端和客户端都要指定队列的持久化和消息的持久化,这样可以保证RabbitMQ重启,队列和消息也不会丢失。
3、公平分发:指定消费者接收的消息个数,避免出现消息均匀推送出现的资源不合理利用的问题。
案例代码:https://www.lanzous.com/i5ydu6d
18年专科毕业后,期间一度迷茫,最近我创建了一个公众号用来记录自己的成长。
RabbitMQ六种队列模式-工作队列模式的更多相关文章
- RabbitMQ六种队列模式-简单队列模式
前言 RabbitMQ六种队列模式-简单队列 [本文]RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主 ...
- RabbitMQ六种队列模式-发布订阅模式
前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅 [本文]RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主 ...
- RabbitMQ六种队列模式-路由模式
前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅RabbitMQ六种队列模式-路由模式 [本文]RabbitMQ六种队列模式-主 ...
- RabbitMQ六种队列模式-主题模式
前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主题模式 [ ...
- (九)RabbitMQ消息队列-通过Headers模式分发消息
原文:(九)RabbitMQ消息队列-通过Headers模式分发消息 Headers类型的exchange使用的比较少,以至于官方文档貌似都没提到,它是忽略routingKey的一种路由方式.是使用H ...
- (七)RabbitMQ消息队列-通过fanout模式将消息推送到多个Queue中
原文:(七)RabbitMQ消息队列-通过fanout模式将消息推送到多个Queue中 前面第六章我们使用的是direct直连模式来进行消息投递和分发.本章将介绍如何使用fanout模式将消息推送到多 ...
- 【RabbitMQ】3、工作队列模式(work模式)
上一篇博客的作为rabbitMQ的入门程序,也是简单队列模式,一个生产者,一个消费者,今天这篇博客介绍work模式,一个生产者,多个消费者,下面的例子模拟两个消费者的情况. 图示: 一 ...
- 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_7.RabbitMQ研究-工作模式-工作队列模式
RabbitMQ有以下几种工作模式 : 1.Work queues 2.Publish/Subscribe 3.Routing 4.Topics 5.Header 6.RPC 1.Work queue ...
- python使用rabbitMQ介绍二(工作队列模式)
一模式介绍 第一章节的生产-消费者模式,是非常简单的模式,一发一收.在实际的应用中,消费者有的时候需要工作较长的时间,则需要增加消费者. 队列模型: 这时mq实现了一下几个功能: rabbitmq循环 ...
随机推荐
- Centos.安装Goaccess1.2
下载 wget http://tar.goaccess.io/goaccess-1.2.tar.gz 解压 tar -xzvf goaccess-1.2.tar.gz 安装支持库GeoIP-devel ...
- C#用mouse_event模拟鼠标点击的问题
1.首先添加using System.Runtime.InteropServices; 2.为鼠标添加模拟点击的各种参数 //鼠标事件 因为我用的不多,所以其他参数没有写 1 2 3 4 5 6 7 ...
- 使用mysqldump命令进行mysql数据库备份
1.用法 mysqldump -uroot -p --databases test > /home/test.sql mysqldump -uroot -h127.0.0.1 -p --data ...
- 在Visual Studio中新增生成项目
在Visual Studio中新增生成项目 选择适配器类型 选择WCF-SQL适配器 创建连接选项 选择相应的存储过程 生成相应的消息架构
- Feign的介绍和使用
一.Feign的简介 Feign是一个声明式 WebService 客户端,使用Feign能够让编写Web Service 客户端更加简单,它的使用方法是定义一个接口,然后在上面添加注解,同时也支持J ...
- SpringBoot+EventBus使用教程(一)
一.简介 EventBus是一个基于发布订阅的事件总线,在Java和Android里都可以使用. 二.使用 1.引入pom <dependency> <groupId>org. ...
- Java内部类是如何实现的
内部类(inner class)是定义在另一个类中的类. 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据. 内部类可以对同一个包中的其他类隐藏起来 当想定义一个回调函数且不想编写大量代 ...
- zbar android sdk在CentOS 7下的编译和使用
环境:CentOS 7+NDK 20.0.5594570+libiconv-1.14 下载 下载libiconv-1.14版本,地址: https://ftp.gnu.org/pub/gnu/libi ...
- django学习_学生信息管理后台
一.功能: 实现对学生对个人信息的增删查改 实现后台对所有学生信息的操作 二.此后台采用的是MVC的风格模式进行编码 1.VIEWS部分 from django.http import HttpRes ...
- linux服务器可以访问IP访问不了域名地址
1.curl www.baidu.com报错,curl 183.232.231.173可以或者nslookup+域名,nslookup+IP2.这个是因为linux服务器没有配置DNS域名服务器地址导 ...