概述
MQ全称为Message Queue,消息队列是应用与应用之间的通信方法
适用场景
- 任务异步处理:将不需要同步处理的并且消耗时长的操作通过消息队列通知消息接收方进行异步处理。提高应用程序的响应时间。
- 程序间解耦:程序之间通过MQ进行通信,达到一定程度的解耦
- 削峰填谷:解决高并发情况下,服务器同时处理过多任务量。保证服务器在不宕机的情况下达到最高执行效率。
JMS和AMQP
JMS
jms是java消息通信的一种应用程序接口,同jdbc一样,只定义了接口规范,用于两个应用程序之间进行异步通信。
AMQP
amqp是面向协议的,应用程序之间进行通信必须遵循这个协议,amqp不直接定义API接口,只在网络通信层定义规范,通过网络协议规范传输格式。
MQ替代品
名称 | 介绍 |
---|---|
ActiveMQ | 基于JMS进行通信 |
ZeroMQ | 基于C语言进行开发 |
RabbitMQ | 基于AMQP协议,erlang语言开发 |
RocketMQ | 基于JMS,阿里巴巴旗下产品 |
Kafka | 类似MQ的产品,高吞吐量 |
RabbitMQ安装
windows版本
链接:https://pan.baidu.com/s/1sZjgiwpWF-XiWAzvH8oncw
提取码:by2p
压缩包内有教程,跟着教程安装即可。
安装完成后打开浏览器,访问下面链接地址
初始化账号:guest
初始化密码:guest
登录后就进入到RabbitMQ图形管理界面
入门案例
编写生产者
- 创建一个空项目
- 创建一个maven模块 名称为rabbitMQ-producer
- 在pom.xml中导入依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
- 编写消息的生产者,模拟用户发送请求
package com.dyh.producer;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class TestProducer {
public static void main(String[] args) throws IOException, TimeoutException {
// 创建连接工厂,并初始化参数
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
// 创建连接
Connection connection = connectionFactory.newConnection();
// 创建频道
Channel channel = connection.createChannel();
/*
声明队列
queue:队列名称
durable:是否为持久队列,服务器重启后是否存在
exclusive:是否被此频道独占
autoDelete:是否在不使用时自动删除
arguments:其他参数
* */
channel.queueDeclare("queue01", true, false, false, null);
// 初始化要发送的消息
String message = "hello rabbitMQ";
/*
通过队列发送消息
exchange:发送至哪个交换机,""空字符串代表不选择交换机
routingKey:路由秘钥 当不选择交换机时,路由秘钥就是发送的队列名称
props:其他参数
body:发送信息的字节码数组
* */
channel.basicPublish("", "queue01", null, message.getBytes());
// 关闭连接
channel.close();
connection.close();
}
}
执行main方法后,可以看见控制台多了一个队列queue01,并且里面有一条消息
编写消费者
- 创建一个maven模块 名称为rabbitMQ-consumer
- 在pom.xml中导入依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
- 编写消费者,模拟服务处理用户请求
package com.dyh.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class TestConsumer {
public static void main(String[] args) throws IOException, TimeoutException {
// 创建连接工厂,并初始化参数
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
// 创建连接
Connection connection = connectionFactory.newConnection();
// 创建频道
Channel channel = connection.createChannel();
/*
声明队列
queue:队列名称
durable:是否为持久队列,服务器重启后是否存在
exclusive:是否被此频道独占
autoDelete:是否在不使用时自动删除
arguments:其他参数
* */
channel.queueDeclare("queue01", true, false, false, null);
// 初始化消费者并监听此频道
DefaultConsumer defaultConsumer = new DefaultConsumer(channel);
/*
进行消费
queue:队列名称
autoAck:服务器收到消息后自动确认则为true,如果手动确认则为false
callback:消费者对象
* */
channel.basicConsume("queue01", true, defaultConsumer);
}
}
执行main方法后,查看管理控制台,发现消息已被处理
注意!当开启服务消费者后,线程会呈现阻塞状态,不断等待消息进入队列。
常用的五种工作模式
简单模式
简单模式从字面意思上来看就是最简单的模式,容易上手,也是我们快速入门的案例使用的模式,但是工作中因为业务逻辑不同,所以不会这样直接使用。
工作队列模式
工作队列模式目的在于增加一个相同的服务节点,提高消息任务处理的效率
多个消费端共同监听同一个队列时,消费者之间对于任务之间的关系是竞争关系
发布订阅模式
发布订阅模式引入了一个新的组件 交换机 它的作用是可以通过交换机对不同的队列发送相同的消息,而每一个队列又可以执行不同的操作
比如用户发送消息后,首先会被交换机接收,随后将消息转发至该交换机所绑定的所有队列,而每一个队列都会执行不同的操作,这样就实现了用户发送了一条消息,但是被交换机下所有队列执行对应的操作。
路由模式
虽然上面的订阅模式可以实现将消息进行分发,只要是交换机所绑定的队列都可以收到消息,但是如果用户只想往队列1里发送消息,不想让队列2里发送消息怎么办呢?
这样就引出里新的模式,路由模式
通过指定交换机后,跟着再绑定一个路由key,我们可以理解为一个标记,目的是为了告诉交换机,你只能向绑定了这个路由key的队列发送这条消息。这样就实现了条件过滤
当然一个队列可以绑定多个key
比如
用户发送一条消息并且携带key1,那么根据下图,两个队列都绑定了key1,那么两个队列都可以收到用户消息并处理。
用户发送一条消息并携带key2,那么根据下图,只有队列2绑定了key2,所以只用队列2可以收到用户消息并处理。
主题模式(通配符模式)
虽然路由模式可以绑定多个路由key,并通过路由key进行队列的选择,但是如果业务过于庞大,绑定队列也会显得非常麻烦,并且维护其他也不够方便,所以又引入了更简单的主题模式(通配符模式)
我们不在通过使用路由key的绑定来进行队列的选择,而使用通配符的方式进行队列选择,这样在配置上就显得更为轻松。
路由key改变为一个或多个词,多个词中间必须使用.
连接
例如:order.insert
order.delet
通配符路由规则;
通配符 | 说明 |
---|---|
# | 匹配一个或多个词 |
* | 匹配一个词 |
例如
order.*
:前缀为order,后面只能有一个词 比如order.insert
order.delete
order.#
:前缀为order,后面可以是任意词 比如 order.detail
order.detail.insert
order.detail.info.insert
*.order
:后缀为order,前面必须有一个词 比如user.order
#.order
:后缀为order,前面可以有0个或多个词
这样就实现了使用通配符替代路由key,实现了更加灵活的配置