RabbitMQ介绍
MQ全称为Message Queue,消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求
MQ的特点
MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取或者订阅队列中的消息。
使用场景
在项目中,将一些无需即时返回且耗时的操作提取出来,进行了异步处理,而这种异步处理的方式大大的节省了服务器的请求响应时间,从而提高了系统的吞吐量。
几个概念
- Exchange:交换机,决定了消息路由规则;
- Queue:消息队列;
- Channel:进行消息读写的通道;
- Bind:绑定了Queue和Exchange,意即为符合什么样路由规则的消息,将会放置入哪一个消息队列;
消息持久化
- 将交换机置为可持久;
- 将通道置为可持久
- 将通道置为可持久
当我们“生产”了一条可持久化的消息,尝试中断MQ服务,启动消费者获取消息,消息依然能够恢复。相反,则抛出异常。
RabbitMQ的结构图如下:
概念说明:
- Broker:简单来说就是消息队列服务器实体。
- Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
- Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
- Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
- Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
- vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
- producer:消息生产者,就是投递消息的程序。
- consumer:消息消费者,就是接受消息的程序。
- channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。
消息队列的使用过程
- 客户端连接到消息队列服务器,打开一个channel。
- 客户端声明一个exchange,并设置相关属性。
- 客户端声明一个queue,并设置相关属性。
- 客户端使用routing key,在exchange和queue之间建立好绑定关系。
- 客户端投递消息到exchange。
exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里。
exchange也有几个类型,完全根据key进行投递的叫做Direct(直接)交换机,例如,绑定时设置了routing key为”abc”,那么客户端提交的消息,只有设置了key为”abc”的才会投递到队列。对key进行模式匹配后进行投递的叫做Topic交换机,符号”#”匹配一个或多个词,符号””匹配正好一个词。例如”abc.#”匹配”abc.def.ghi”,”abc.”只匹配”abc.def”。还有一种不需要key的,叫做Fanout交换机,它采取广播模式,一个消息进来时,投递到与该交换机绑定的所有队列。
RabbitMQ支持消息的持久化,也就是数据写在磁盘上,为了数据安全考虑,我想大多数用户都会选择持久化。消息队列持久化包括3个部分:
- exchange持久化,在声明时指定durable => 1
- queue持久化,在声明时指定durable => 1
- 消息持久化,在投递时指定delivery_mode => 2(1是非持久化)
如果exchange和queue都是持久化的,那么它们之间的binding也是持久化的。如果exchange和queue两者之间有一个持久化,一个非持久化,就不允许建立绑定。
基于Idea+Springboot2.0+SpringCloud Hoxton.SR3,rabbitmq使用
- 在pom.xml引入依赖amqp
- 配置application.yml
- 创建消息接收者服务
- 创建发送消息客户端
引入amqp依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
配置appcation.yml
spring:
rabbitmq:
host: 192.168.99.100
port: 5672
username: guest
password: guest
接下来创建接收信息服务
package com.example.order.message;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* 接受MQ消息
* Created by Administrator
* 2020/4/8 21:30
*/
@Component
@Slf4j
public class MqReceiver {
//1.@RabbitListener(queues = "myQueue") 需要在rabbitMQ创建名字为myQueue消息队列
//2.自动创建队列 @RabbitListener(queuesToDeclare = @Queue("myQueue"))
//3.自动创建,Exchange和Queue绑定
@RabbitListener(bindings = @QueueBinding(
value = @Queue("myQueue"),
exchange = @Exchange("myExchange")
))
public void process(String message){
log.info("message :{}",message);
}
/**
* 电子数码供应商服务,接收信息
* @param message
*/
@RabbitListener(bindings = @QueueBinding(
exchange = @Exchange("myOrderExchange"),
key = "computer",
value = @Queue("computerOrderQueue")
))
public void processComputer(String message){
log.info("computer MqReceiver: {}",message);
}
/**
* 零食供应商服务,接收消息
* @param message
*/
@RabbitListener(bindings = @QueueBinding(
exchange = @Exchange("myOrderExchange"),
key = "foods",
value = @Queue("foodsOrderQueue")
))
public void processFoots(String message){
log.info("foods MqReceiver: {}",message);
}
}
模拟客户端发送消息进行测试:
package com.example.order;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
*发送消息
* Created by Administrator
* 2020/4/8 21:38
*/
@Component
@SpringBootTest
public class MqSenderTest {
@Autowired
private AmqpTemplate amqpTemplate;
/**
* 发送消息给接收方
*/
@Test
public void sendMessage(){
amqpTemplate.convertAndSend("myQueue","now: "+new Date());
}
/**
* 发送消息给电子数码服务接收方
*/
@Test
public void sendComputerMessage(){
amqpTemplate.convertAndSend("myOrderExchange","computer","now:"+new Date());
}
/**
* 发送消息给零食服务接收方
*/
@Test
public void sendFoodsMessages(){
amqpTemplate.convertAndSend("myOrderExchange","foods","now: "+new Date());
}
}
通过RabbitMQ的管理界面,查看Queues,已经有了三个队列都是自动创建,分别为computerOrderQueue,myQueue,foodsOrderQueue,并且绑定到Exchange中。