1.RabbitMQ工作模型与基本原理
1. MQ 了解
1.1. 消息队列简介
1.1.1.MQ 的诞生历程
1.1.2.什么是 MQ(Message Queue)?
1.1.3.为什么要使用 MQ?
1.1.1.1.实现异步通信
1.1.1.1.实现系统解耦
// 伪代码
public void returnGoods(){
stockService.updateInventory ();
payService.refund();
noticeService.notice();
}

1.1.1.2.实现流量削峰
1.1.4.使用消息队列带来的一些问题
1.2. RabbitMQ 简介
1.2.1.基本特性
1.2.2.AMQP 协议
1.2.2.1.总体介绍

1.2.2.2.工作模型

1.2.2.3.路由方式

channel.basicPublish(“MY_DIRECT_EXCHANGE”,”spring”,”msg1”);
只有第一个队列能收到消息。

channel.basicPublish("MY_TOPIC_EXCHANGE","junior.fjd.klj","msg 2");
只有第一个队列能收到消息。
channel.basicPublish("MY_TOPIC_EXCHANGE","junior.jvm", "msg 3");
第 一个队列和第三个队列能收到消息。
channel.basicPublish("MY_FANOUT_EXCHANGE", "", "msg 4");
三个队列都会收到 msg 4。
1.3. 基本使用
1.3.1.安装
1.3.2.Java API 编程
1.3.2.1.引入依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
1.3.2.2.生产者
package com.simple;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class MyProducer {
private final static String EXCHANGE_NAME = "SIMPLE_EXCHANGE";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
// 连接 IP
factory.setHost("127.0.0.1");
// 连接端口
factory.setPort(5672);
// 虚拟机
factory.setVirtualHost("/");
// 用户
factory.setUsername("guest");
factory.setPassword("guest");
// 建立连接
Connection conn = factory.newConnection();
// 创建消息通道
Channel channel = conn.createChannel();
// 发送消息
String msg = "Hello world, Rabbit MQ";
// String exchange, String routingKey, BasicProperties props, byte[] body
channel.basicPublish(EXCHANGE_NAME, "gupao.best", null, msg.getBytes());
channel.close();
conn.close();
}
}
1.3.2.3.消费者
package com.simple;
import com.rabbitmq.client.*;
import java.io.IOException;
public class MyConsumer {
private final static String EXCHANGE_NAME = "SIMPLE_EXCHANGE";
private final static String QUEUE_NAME = "SIMPLE_QUEUE";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
// 连接 IP
factory.setHost("127.0.0.1");
// 默认监听端口
factory.setPort(5672);
// 虚拟机
factory.setVirtualHost("/");
// 设置访问的用户
factory.setUsername("guest");
factory.setPassword("guest");
// 建立连接
Connection conn = factory.newConnection();
// 创建消息通道
Channel channel = conn.createChannel();
// 声明交换机
// String exchange, String type, boolean durable, boolean autoDelete, Map<String, Object> arguments
channel.exchangeDeclare(EXCHANGE_NAME,"direct",false, false, null);
// 声明队列
// String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" Waiting for message....");
// 绑定队列和交换机
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"best");
// 创建消费者
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
String msg = new String(body, "UTF-8");
System.out.println("Received message : '" + msg + "'");
System.out.println("consumerTag : " + consumerTag );
System.out.println("deliveryTag : " + envelope.getDeliveryTag() );
}
};
// 开始获取消息
// String queue, boolean autoAck, Consumer callback
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
1.3.2.4.参数详解
1.3.3.UI 管理界面的使用
1.3.3.1.启用管理插件
1.3.3.2.管理界面访问端口
1.3.3.3.虚拟机
2. 深入理解RabbitMQ
2.1. TTL(Time To Live)
2.1.1.消息的过期时间
@Bean("ttlQueue")
public Queue queue() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("x-message-ttl", 11000); // 队列中的消息未被消费 11 秒后过期
return new Queue("TTL_QUEUE", true, false, false, map);
}
MessageProperties messageProperties = new MessageProperties();
messageProperties.setExpiration("4000"); // 消息的过期属性,单位 ms
Message message = new Message("这条消息 4 秒后过期".getBytes(), messageProperties);
rabbitTemplate.send("GP_TTL_EXCHANGE", "ttl", message);
2.2. 死信队列
@Bean("oriUseExchange")
public DirectExchange exchange() {
return new DirectExchange("RI_USE_EXCHANGE", true, false, new HashMap<>());
}
@Bean("oriUseQueue")
public Queue queue() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("x-message-ttl", 10000); // 10 秒钟后成为死信
map.put("x-dead-letter-exchange", "DEAD_LETTER_EXCHANGE"); // 队列中的消息变成死信后,进入死信交换机
return new Queue("ORI_USE_QUEUE", true, false, false, map);
}
@Bean
public Binding binding(@Qualifier("oriUseQueue") Queue queue,@Qualifier("oriUseExchange") DirectExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("ori.use");
}
@Bean("deatLetterExchange")
public TopicExchange deadLetterExchange() {
return new TopicExchange("DEAD_LETTER_EXCHANGE", true, false, new HashMap<>());
}
@Bean("deatLetterQueue")
public Queue deadLetterQueue() {
return new Queue("DEAD_LETTER_QUEUE", true, false, false, new HashMap<>());
}
@Bean
public Binding bindingDead(@Qualifier("deatLetterQueue") Queue queue,@Qualifier("deatLetterExchange") TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("#"); // 无条件路由
}

2.3. 延迟队列
2.3.1.TTL+DLX 的实现
2.3.2.基于延迟队列插件的实现(Linux)
whereis rabbitmq
cd /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.12/plugins
wget
https://bintray.com/rabbitmq/community-plugins/download_file?file_path=rabbitmq_delayed_message_exchange-0.0.1.ez
mv download_file?file_path=rabbitmq_delayed_message_exchange-0.0.1.ez
rabbitmq_delayed_message_exchange-0.0.1.ez
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
rabbitmq-plugins disable rabbitmq_delayed_message_exchange
@Bean("delayExchange")
public TopicExchange exchange() {
Map<String, Object> argss = new HashMap<String, Object>();
argss.put("x-delayed-type", "direct");
return new TopicExchange("GP_DELAY_EXCHANGE", true, false, argss);
}
MessageProperties messageProperties = new MessageProperties();
// 延迟的间隔时间,目标时刻减去当前时刻
messageProperties.setHeader("x-delay", delayTime.getTime() - now.getTime());
Message message = new Message(msg.getBytes(), messageProperties);
// 不能在本地测试,必须发送消息到安装了插件的 Linux 服务端
rabbitTemplate.send("GP_DELAY_EXCHANGE", "#", message);
2.4. 服务端流控(Flow Control)
2.4.1.内存控制
[{rabbit, [{vm_memory_high_watermark, 0.4}]}].
rabbitmqctl set_vm_memory_high_watermark 0.3
2.4.2.磁盘控制
disk_free_limit.relative = 3.0
disk_free_limit.absolute = 2GB
2.5. 消费端限流
channel.basicQos(2); // 如果超过 2 条消息没有发送 ACK,当前消费者不再接受队列消息
channel.basicConsume(QUEUE_NAME, false, consumer);
container.setPrefetchCount(2);
spring.rabbitmq.listener.simple.prefetch=2
3. Spring AMQP
3.1. Spring AMQP 介绍
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
3.2. Spring AMQP 核心组件
3.2.1.ConnectionFactory
3.2.2.RabbitAdmin
// 声明一个交换机
rabbitAdmin.declareExchange(new DirectExchange("ADMIN_EXCHANGE", false, false));
// 声明一个队列
rabbitAdmin.declareQueue(new Queue("ADMIN_QUEUE", false, false, false));
// 声明一个绑定
rabbitAdmin.declareBinding( new Binding("ADMIN_QUEUE", Binding.DestinationType.QUEUE,
"ADMIN_EXCHANGE", "admin", null));
declareExchanges(channel, exchanges.toArray(new Exchange[exchanges.size()]));
declareQueues(channel, queues.toArray(new Queue[queues.size()]));
declareBindings(channel, bindings.toArray(new Binding[bindings.size()]));
3.2.3.Message
3.2.4.RabbitTemplate 消息模板
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMandatory(true);
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback(){
public void returnedMessage(Message message,
int replyCode,
String replyText,
String exchange,
String routingKey){
}
});
return rabbitTemplate;
}
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback(){
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (ack) {
System.out.println("消息确认成功");
} else {
// nack
System.out.println("消息确认失败");
}
}
});
3.2.5.MessageListener 消息侦听
@Bean
public SimpleMessageListenerContainer messageContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setQueues(getSecondQueue(), getThirdQueue()); //监听的队列
container.setConcurrentConsumers(1); // 最小消费者数
container.setMaxConcurrentConsumers(5); // 最大的消费者数量
container.setDefaultRequeueRejected(false); //是否重回队列
container.setAcknowledgeMode(AcknowledgeMode.AUTO); //签收模式
container.setExposeListenerChannel(true);
container.setConsumerTagStrategy(new ConsumerTagStrategy() { //消费端的标签策略
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID().toString();
}
});
return container;
}
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory)
{
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(new Jackson2JsonMessageConverter());
factory.setAcknowledgeMode(AcknowledgeMode.NONE);
factory.setAutoStartup(true);
return factory;
}
@Component
@PropertySource("classpath:mq.properties")
@RabbitListener(queues = "${com.firstqueue}", containerFactory="rabbitListenerContainerFactory")
public class FirstConsumer {
@RabbitHandler
public void process(@Payload Merchant merchant){
System.out.println("First Queue received msg : " + merchant.getName());
}
}
public class ContainerSender {
public static void main(String[] args) throws Exception {
ConnectionFactory connectionFactory = new CachingConnectionFactory(new URI("amqp://guest:guest@localhost:5672"));
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
SimpleMessageListenerContainer container = factory.createListenerContainer();
// 不用工厂模式也可以创建
// SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setConcurrentConsumers(1);
container.setQueueNames("BASIC_SECOND_QUEUE");
container.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
System.out.println("收到消息:"+message);
}
});
container.start();
AmqpTemplate template = new RabbitTemplate(connectionFactory);
template.convertAndSend("BASIC_SECOND_QUEUE", "msg 1");
}
}
3.2.6.转换器 MessageConvertor
@Bean
public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
return rabbitTemplate;
}
3.3. Spring 集成 RabbitMQ 配置解读
<rabbit:connection-factory id="connectionFactory" virtual-host="/" username="guest" password="guest"
host="127.0.0.1" port="5672" />
<rabbit:admin id="connectAdmin" connection-factory="connectionFactory" />
<rabbit:queue name="MY_FIRST_QUEUE" durable="true" auto-delete="false" exclusive="false"
declared-by="connectAdmin" />
<rabbit:direct-exchange name="MY_DIRECT_EXCHANGE" durable="true" auto-delete="false"
44
declared-by="connectAdmin">
<rabbit:bindings>
<rabbit:binding queue="MY_FIRST_QUEUE" key="FirstKey">
</rabbit:binding>
</rabbit:bindings>
</rabbit:direct-exchange>
<bean id="jsonMessageConverter"
class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" />
<rabbit:template id="amqpTemplate" exchange="${gupao.exchange}" connection-factory="connectionFactory"
message-converter="jsonMessageConverter" />
<bean id="messageReceiver" class="com.gupaoedu.consumer.FirstConsumer"></bean>
<rabbit:listener-container connection-factory="connectionFactory">
<rabbit:listener queues="MY_FIRST_QUEUE" ref="messageReceiver" />
</rabbit:listener-container>

3.4. Spring Boot 集成 RabbitMQ
3.4.1.配置文件
@Bean("vipDirectExchange")
public DirectExchange getDirectExchange(){
return new DirectExchange(directExchange);
}
@Bean("vipTopicExchange")
public TopicExchange getTopicExchange(){
return new TopicExchange(topicExchange);
}
@Bean("vipFanoutExchange")
public FanoutExchange getFanoutExchange(){
return new FanoutExchange(fanoutExchange);
}
@Bean("vipFirstQueue")
public Queue getFirstQueue(){
return new Queue(firstQueue);
}
@Bean("vipSecondQueue")
public Queue getSecondQueue(){
return new Queue(secondQueue);
}
@Bean("vipThirdQueue")
public Queue getThirdQueue(){
return new Queue(thirdQueue);
}
@Bean("vipFourthQueue")
public Queue getFourthQueue(){
return new Queue(fourthQueue);
}
@Bean
public Binding bindFirst(@Qualifier("vipFirstQueue") Queue queue, @Qualifier("vipDirectExchange")
DirectExchange exchange){
return BindingBuilder.bind(queue).to(exchange).with("gupao.best");
}
@Bean
public Binding bindSecond(@Qualifier("vipSecondQueue") Queue queue, @Qualifier("vipTopicExchange")
TopicExchange exchange){
return BindingBuilder.bind(queue).to(exchange).with("*.gupao.*");
}
@Bean
public Binding bindThird(@Qualifier("vipThirdQueue") Queue queue, @Qualifier("vipFanoutExchange")
FanoutExchange exchange){
return BindingBuilder.bind(queue).to(exchange);
}
@Bean
public Binding bindFourth(@Qualifier("vipFourthQueue") Queue queue, @Qualifier("vipFanoutExchange")
FanoutExchange exchange){
return BindingBuilder.bind(queue).to(exchange);
}
3.4.2.消费者
@Component
@PropertySource("classpath:mq.properties")
@RabbitListener(queues = "${com.firstqueue}")
public class FirstConsumer {
@RabbitHandler
public void process(@Payload Merchant merchant){
System.out.println("First Queue received msg : " + merchant.getName());
}
}
3.4.3.生产者
@Autowired
AmqpTemplate upTemplate;
public void send() throws JsonProcessingException {
Merchant merchant = new Merchant(1001,"a direct msg : 中原镖局","汉中省解放路 266 号");
upTemplate.convertAndSend(directExchange,directRoutingKey, merchant);
upTemplate.convertAndSend(topicExchange,topicRoutingKey1,"a topic msg : shanghai.teacher");
upTemplate.convertAndSend(topicExchange,topicRoutingKey2,"a topic msg : changsha.student");
// 发送 JSON 字符串
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(merchant);
System.out.println(json);
upTemplate.convertAndSend(fanoutExchange,"", json);
}
3.5. Spring Boot 参数解析
1.RabbitMQ工作模型与基本原理的更多相关文章
- 认识RabbitMQ交换机模型
前言 RabbitMQ是消息队列中间件(Message Queue Middleware)中一种,工作虽然有用到,但是却没有形成很好的整体包括,主要是一些基础概念的认识,这里通过阅读<Rabbi ...
- [转载] PHP工作模型与运行机制
转载自http://www.nowamagic.net/librarys/veda/detail/350 PHP的工作模型非常特殊.从某种程度上说,PHP和ASP.ASP.NET.JSP/Servle ...
- HTTPD三种工作模型
HTTPD三种工作模型 MPM是apache的多道处理模块,用于定义apache对客户端请求的处理方式.在linux中apache常用的三种MPM模型分别是prefork.worker和event. ...
- RabbitMQ系列(二)深入了解RabbitMQ工作原理及简单使用
深入了解RabbitMQ工作原理及简单使用 RabbitMQ系列文章 RabbitMQ在Ubuntu上的环境搭建 深入了解RabbitMQ工作原理及简单使用 RabbitMQ交换器Exchange介绍 ...
- 深入解读RabbitMQ工作原理及简单使用
RabbitMQ系列目录 RabbitMQ在Ubuntu上的环境搭建 深入解读RabbitMQ工作原理及简单使用 Rabbit的几种工作模式介绍与实践 Rabbit事务与消息确认 Rabbit集群搭建 ...
- Git Flow 工作模型与使用
一. Git Flow 工作模型的原理 无规矩不成方圆,但是规矩太多了,则感觉到束缚.我们一个人工作的时候喜欢无拘无束,想怎么干就怎么干,没有人评判,没有人检验.时间久了就会盲目自大,以为增删改查熟悉 ...
- linux下的工作模型以及Nginx工作原理
Web服务器主要任务就是处理来自客户端的请求,一般情况下Web服务器处理并发连接请求的工作模型有以下几种方式: 1.单线程web服务器(Single-threaded web servers) 此 ...
- 【 Linux 】I/O工作模型及Web服务器原理
一.进程.线程 进程是具有一定独立功能的,在计算机中已经运行的程序的实体.在早期系统中(如linux 2.4以前),进程是基本运作单位,在支持线程的系统中(如windows,linux2.6) ...
- 【python】-- RabbitMQ RPC模型
RabbitMQ RPC模型 RPC(remote procedure call)模型说通俗一点就是客户端发一个请求给远程服务端,让它去执行,然后服务端端再把执行的结果再返回给客户端. 1.服务端 i ...
随机推荐
- (尚020)Vue打包发布项目
1.项目的打包与发布 1.1打包: npm run build 报错: 原因:原来eslint是一个语法检查工具,但是限制很严格,在我的vue文件里面很多空格都会导致红线(红线可以关闭提示),虽然可以 ...
- git log filter(六)
显示前10条提交记录: root@vmuer-VirtualBox:/media/vmuer/share/cmake-uart-server# git log -10 commit b056dacb0 ...
- Xamarin.IOS/Mac开发中遇到的问题
虚拟机中安装的mac系统无法识别iphone 今天在 Xamarin.iOS 应用的免费预配 时,进行到 5.插入要在其中部署应用的 iOS 设备. 在第8选择iphone设备时,发现iphone并没 ...
- mysql ERROR 1862 (HY000): 密码超时错误解决 Your password has expired.To log in you must change it using a client that supports expired password
工具链接可能报错,使用黑窗口链接后: 1. SET PASSWORD = PASSWORD("xinmima"); 2. flush privileges; 使用新密码链接即可.
- Ubuntu 安装MySQL报共享库找不到
错误信息1: ./mysqld: error : cannot open shared object file: No such file or directory 解决办法:安装改库 # apt-g ...
- 记录linux上mongo迁移使用的命令
首先mongodb的文件路径必须在系统盘,这里是 这里安装路径 /usr/mongodb/bin 一般迁移的只是db文件夹和log文件 看配置文件内容 port=27017 #端口 dbpath=/d ...
- Ajax:修改了项目的ajax相关代码,点击运行没有效果
在运行ajax代码的时候发现这个问题,无论是重启浏览器还是IDE依旧不能解决. 原因: 浏览器调试的缓存 措施: 浏览器启用开发者模式,以Chrome.IDEA为例 1.浏览器设置disable ca ...
- NoSql数据库Redis系列(6)——Redis数据过期策略详解
本文对Redis的过期机制简单的讲解一下 讲解之前我们先抛出一个问题,我们知道很多时候服务器经常会用到redis作为缓存,有很多数据都是临时缓存一下,可能用过之后很久都不会再用到了(比如暂存sessi ...
- delete、truncate、drop三种删除语句联系与区别
相同点: 1.truncate和不带where子句的delete.以及drop都会删除表内的数据. 2.drop.truncate都是DDL语句(数据定义语言),执行后会自动提交. 不同点: 1. t ...
- 深度强化学习 之 运行环境 mujoco 报错 ERROR: GLEW initalization error: Missing GL version
使用 mujoco环境 运行代码,报错 ERROR: GLEW initalization error: Missing GL version 一直无法解决,发现网址: https://blog. ...