1.RabbitMq - Work 模式
RabbitMq - Work 模式
一、什么是Work模式
如果有几个消息都需要处理,且每个消息的处理时间很长,仅有一个消费者,那么当它在处理一个消息的时候,其他消息就只有等待。
等待有时候是好的,但在程序中并不那么好,当队列中有多个消息待处理,将其分发给多个消费者,当一个消费者在处理的时候,有其他消费者继续消费队列中的消息,便缓解了等待的尴尬。
那么这篇文章将实现一个生产者,多个消费者的模式,实现任务分发:work模式,如图所示。

二、消息确认机制
处理一个消息可能会花一定的时间,万一还没处理完消费者就gg了…生产者一发送消息,便会将其标记为已删除,故最终的结果是:这条消息没有得到正确的处理。而且,指派给该消费者且尚未处理的所有消息都会gg。
解决策略:取消自动回复机制
为了解决消息的丢失问题,RabbitMQ提供了消息确认机制:message acknowledgments,一个消费者处理完成后,将会回传一个ack给生产者,以表示处理成功,这样生产者才可以将消息删除。
这样即使一个消费者gg了,没有回传ack,那么发送者便会重发消息到队列,如果这时候有其他的消费者服务该队列,那么便会从队列中取出消息并处理。这就保证了消息的不丢失。
自动回复机制:不管是否处理成功,还是失败,都会回复ack。
channel.basicConsume(QUEUE_NAME, true, consumer);
自动恢复机制默认是打开的,在接收端的代码最后:第二个参数为true,表示会自动回复,只要生产发送消息,就会标记删除。所以我们需要将自动回复设置为false。
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME, autoAck, consumer);
这样来保证消息不会因为消费者的gg而丢失了。
那么取消自动回复以后,我们需要手动回复一次:
channel.basicAck(envelope.getDeliveryTag(), false);
注意当前的消息确认机制只适用于同一个channel。
---------------------
application.yml
#############################################################
############## rabbitmq config ##############################
#############################################################
spring.rabbitmq.host: 127.0.0.1
spring.rabbitmq.port:
spring.rabbitmq.username: admin
spring.rabbitmq.password: admin
package com.maozw.mq.config; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope; /**
* @author MAOZW
* @Description: Broker:它提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线,保证数据能按照指定的方式进行传输,
* Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
* Queue:消息的载体,每个消息都会被投到一个或多个队列。
* Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来.
* Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
* vhost:虚拟主机,一个broker里可以有多个vhost,用作不同用户的权限分离。
* Producer:消息生产者,就是投递消息的程序.
* Consumer:消息消费者,就是接受消息的程序.
* Channel:消息通道,在客户端的每个连接里,可建立多个channel.
* @date 2018/11/26 14:33
*/
@Configuration
public class RabbitConfig { private static final Logger LOGGER = LoggerFactory.getLogger(RabbitConfig.class); @Value("${spring.rabbitmq.host}")
private String rabbitmqHost; @Value("${spring.rabbitmq.port}")
private int rabbitmqPort; @Value("${spring.rabbitmq.username}")
private String userName; @Value("${spring.rabbitmq.password}")
private String password; public static final String EXCHANGE_A = "my-mq-exchange_A";
public static final String EXCHANGE_B = "my-mq-exchange_B";
public static final String EXCHANGE_C = "my-mq-exchange_C"; public static final String QUEUE_A = "QUEUE_A";
public static final String QUEUE_WORK = "QUEUE_WORK";
public static final String QUEUE_C = "QUEUE_C"; public static final String ROUTINGKEY_A = "spring-boot-routingKey_A";
public static final String ROUTINGKEY_B = "spring-boot-routingKey_B";
public static final String ROUTINGKEY_C = "spring-boot-routingKey_C"; @Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setUsername(userName);
connectionFactory.setPassword(password);
connectionFactory.setVirtualHost("/vir_simple");
connectionFactory.setPublisherConfirms(false);
return connectionFactory;
} public static ConnectionFactory getConnectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/vir_simple");
connectionFactory.setPublisherConfirms(false);
return connectionFactory;
}
}
生产者
package com.maozw.mq.work; import com.maozw.mq.config.RabbitConfig;
import com.rabbitmq.client.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import java.io.IOException; /**
* work 模式
* 两种分发: 轮询分发 + 公平分发
* 轮询分发:消费端:自动确认消息;boolean autoAck = true;
* 公平分发: 消费端:手动确认消息 boolean autoAck = false; channel.basicAck(envelope.getDeliveryTag(),false);
* @author MAOZW
* @Description: ${todo}
* @date 2018/11/26 15:06
*/
@RestController
@RequestMapping("/work")
public class WorkProducer {
private static final Logger LOGGER = LoggerFactory.getLogger(WorkProducer.class);
@Autowired
RabbitConfig rabbitConfig; @RequestMapping("/send")
public String send() throws IOException {
ConnectionFactory connectionFactory = rabbitConfig.connectionFactory();
Connection connection = connectionFactory.createConnection();
Channel channel = connection.createChannel(false);
//创建队列申明
channel.queueDeclare(RabbitConfig.QUEUE_WORK, false, false, false, null); /**
* 每个消费者 发送确认消息之前,消息队列不会发送下一个消息给消费者,一次只处理一个消息
* 自动模式无需设置下面设置
*/
int prefetchCount = ;
channel.basicQos(prefetchCount); String Hello = ">>>> Hello Simple <<<<";
for (int i = ; i < ; i++) {
String message = Hello + i;
channel.basicPublish("", RabbitConfig.QUEUE_WORK, null, message.getBytes());
LOGGER.info("生产消息: " + message);
}
return "OK";
}
}
消费者
package com.maozw.mq.work; import com.maozw.mq.config.RabbitConfig;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.connection.ConnectionFactory; import java.io.IOException; /**
* @author MAOZW
* @Description: ${todo}
* @date 2018/11/26 15:06
*/ public class WorkConsumer2 {
private static final Logger LOGGER = LoggerFactory.getLogger(WorkConsumer2.class); public static void main(String[] args) throws IOException {
ConnectionFactory connectionFactory = RabbitConfig.getConnectionFactory();
Connection connection = connectionFactory.createConnection();
Channel channel = connection.createChannel(false);
//创建队列申明
channel.queueDeclare(RabbitConfig.QUEUE_WORK, false, false, false, null); /**
* 改变分发规则
*/
channel.basicQos(); DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
super.handleDelivery(consumerTag, envelope, properties, body);
System.out.println("[2] 接口数据 : " + new String(body, "utf-8")); try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[2] done!");
//消息应答:手动回执,手动确认消息
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
//监听队列
/**
* autoAck 消息应答
* 默认轮询分发打开:true :这种模式一旦rabbitmq将消息发送给消费者,就会从内存中删除该消息,不关心客户端是否消费正常。
* 使用公平分发需要关闭autoAck:false 需要手动发送回执
*/
boolean autoAck = false;
channel.basicConsume(RabbitConfig.QUEUE_WORK,autoAck, consumer);
} }
1.RabbitMq - Work 模式的更多相关文章
- rabbitMQ tipic 模式
RabbitMQ消息队列(八)-通过Topic主题模式分发消息(.Net Core版) 前两章我们讲了RabbitMQ的direct模式和fanout模式,本章介绍topic主题模式的应用.如果对di ...
- Rabbitmq -Publish_Subscribe模式- python编码实现
what is Exchanges ?? Let's quickly go over what we covered in the previous tutorials: A producer is ...
- RabbitMQ事物模式
Rabbit的消息确认机制(事务+confirm)在rabbmitmq中我们可以通过持久化数据解决rabbitmq服务器异常的数据丢失问题问题:生产者将消息发送出去之后消息到底有没有到达rabbitm ...
- RabbitMQ广播模式
广播模式:1对多,produce发送一则消息多个consumer同时收到.注意:广播是实时的,produce只负责发出去,不会管对端是否收到,若发送的时刻没有对端接收,那消息就没了,因此在广播模式下设 ...
- RabbitMQ镜像模式双节点部署时故障转移过程中队列中消息的状态
场景 现有节点Node1和Node2,建立Exchange:yu.exchange,创建队列yu1.queue镜像队列master位于Node1,yu2.queue镜像队列位于Node2,使用topi ...
- 使用rabbitmq rpc 模式
服务器端 安装 ubuntu 16.04 server 安装 rabbitmq-server 设置 apt 源 curl -s https://packagecloud ...
- RabbitMQ工作模式
------------恢复内容开始------------ RabbitMQ基本概念: Producer:生产者(消息的提供者) Consumer:消费者(消息的使用者) Message:消息(程序 ...
- RabbitMQ 消息模式
消息模式实例 视频教程:https://ke.qq.com/course/304104 编写代码前,最好先添加好用户并设置virtual hosts 一.简单模式 1.导入jar包 <depen ...
- 干货!基于SpringBoot的RabbitMQ多种模式队列实战
目录 环境准备 安装RabbitMQ 依赖 连接配置 五种队列模式实现 1 点对点的队列 2 工作队列模式Work Queue 3 路由模式Routing 4 发布/订阅模式Publish/Subsc ...
随机推荐
- Cache的一些总结
输出缓存 这是最简单的缓存类型,它保存发送到客户端的页面副本,当下一个客户端发送相同的页面请求时,此页面不会重新生成(在缓存有限期内),而是从缓存中获取该页面:当然由于缓存过期或被回收,这时页面会重新 ...
- Python的global指令的作用
Python的global指令的作用 学过其他常用编程语言的同学一定清楚,Python是一个语法非常宽容的语言.它是个变量的定义可以省略.直接赋值.根据赋值结果自动确定变量类型的弱类型语言. 但是这样 ...
- 【PR笔记】一、打造希区柯克变焦效果
1. 导入素材,“链接选择项”关闭,删除音频 2. 添加效果--视频效果--扭曲--视频稳定器, 然后程序帮我们自动稳定 3.视频首尾添加关键帧,首帧缩放200% 尾帧不变, 使视频前后的主体大小差 ...
- 03 - Mongodb数据查询 | Mongodb
1.基本查询 ①方法find():查询 db.集合名称.find({条件文档}) ②方法findOne():查询,只返回第一个 db.集合名称.findOne({条件文档}) ③方法pretty(): ...
- jquery.serializejson.min.js的妙用
关于这个jquery.serializejson.min.js插件来看,他是转json的一个非常简单好用的插件. 前端在处理含有大量数据提交的表单时,除了使用Form直接提交刷新页面之外,经常碰到的需 ...
- 查看PHP指定扩展的版本信息
命令:php --ri 扩展名
- react route使用HashRouter和BrowserRouter的区别-Content Security Policy img-src 404(Not found)
踩坑经历 昨天看了篇关于react-route的文章,说BrowserRouter比HashRouter好一些,react也是推荐使用BrowserRouter,毕竟自己在前端方面来说,就是个小白,别 ...
- 【Java并发】线程通信
一.概述 1.1 什么是多线程之间通讯? 1.2 案例 代码实现 解决线程安全问题 二.等待通知机制 2.1 示例 2.2 wait与sleep区别 三.Lock锁 3.1 概述 3.2 等待/通知机 ...
- BootStrap【二、样式】
H5文档类型 由于使用了H5和CSS熟悉,需要在文件头引入 移动设备优先 为了对移动设备友好,需要使用标签viewport width=device-width 宽度为设备宽度 height 高度 i ...
- 轻量化模型之MobileNet系列
自 2012 年 AlexNet 以来,卷积神经网络在图像分类.目标检测.语义分割等领域获得广泛应用.随着性能要求越来越高,AlexNet 已经无法满足大家的需求,于是乎各路大牛纷纷提出性能更优越的 ...