1.什么是MQ?
MQ( Message queue ), 从字⾯意思上看, 本质是个队列, FIFO 先⼊先出,只不过队列中存放的内容是消息(message) ⽽已. 消息可以⾮常简单,⽐如只包含⽂本字符串, JSON等,也可以很复杂, ⽐如内嵌对象.
MQ多⽤于分布式系统之间进⾏通信.
系统之间通信
1.同步通信
2.异步通信
RabbitMQ就是MQ的一种实现
2.MQ的作用及什么时候使用MQ
MQ主要⼯作是接收并转发消息, 在不同的应⽤场景下可以展现不同的作⽤,可以看一下下面的框图来理解
以下总结了一些使用MQ的场景以及为什么使用
- 异步解耦:在业务流程中,一些操作可能非常耗时,但并不需要即时返回结果。可以借助 MQ 把这些操作异步化,比如 用户注册后发送注册短信或邮件通知,可以作为异步任务处理,而不必等待这些操作完成后才告知用户注册成功.
- 流量削峰:在访问量剧增的情况下,应用仍然需要继续发挥作用,但是是这样的突发流量并不常见。如果以能处理这类峰值为标准而投入资源,无疑是巨大的浪费。使用 MQ 能够使关键组件支撑突发访问压力,不会因为突发流量而崩溃。比如秒杀或者促销活动,可以使用 MQ 来控制流量,将请求排队,然后系统根据自己的处理能力逐步处理这些请求.
- 异步通信:在很多时候应用不需要立即处理消息,MQ 提供了异步处理机制,允许应用把一些消息放入 MQ 中,但并不立即处理它,在需要的时候再慢慢处理.
- 消息分发:当多个系统需要对同一数据做出响应时,可以使用 MQ 进行消息分发。比如支付成功后,支付系统可以向 MQ 发送消息,其他系统订阅该消息,而无需轮询数据库.(说明MQ可以将一个消息转发给多个对象,一个生产者对应多个消费者)
- 延迟通知:在需要在特定时间后发送通知的场景中,可以使用 MQ 的延迟消息功能,比如在电子商务平台中,如果用户下单后一定时间内未支付,可以使用延迟队列在超时后自动取消订单
3.RabbitMQ基本概念核心组成
我们必须需要了解一下RabbitMQ的一些基本组成以及处理消息的流程,才能更好的使用写一些关于MQ的代码,可以看一下以下的框图来有个快速的认知
注意一点这里多个消费者可以订阅同一个队列
4.Web界面操作
这里可以通过该界面来查看一下队列的一些情况,这里通过url:服务器ip+端口号(RabbitMQ的WEB端口一般默认为15672,这里如果为rabbitmq的web端口配置了隧道就使用隧道端口) 来访问,这里需要账号和密码来登录,我的账号密码是:admin,admin

5.RabbitMQ配置与使用
需要添加依赖
java
<!-- RabbitMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
需要添加的配置项(.properties)
java
## mq ##
#安装Rabbitmq服务器地址
spring.rabbitmq.host=IP地址
#rabbit服务的业务端口号(一般为5672,这里如果专门配置了隧道使用隧道的端口)
spring.rabbitmq.port=端口号
spring.rabbitmq.username=用户名
spring.rabbitmq.password=密码
#消息确认机制,默认auto
spring.rabbitmq.listener.simple.acknowledge-mode=auto
#设置失败重试 5次
spring.rabbitmq.listener.simple.retry.enabled=true
spring.rabbitmq.listener.simple.retry.max-attempts=5
确认机制:这里可以看一下这里的自动确认机制,首先明白什么叫确认,比如消息队列想要知道消费者拿了消息之后消费了吗,这个是需要消费者来告诉的,而中这个自动确认机制就是,消费者拿到消息之后处理后,没有抛出异常,就默认是消费成功了,而当消费者在消费消息方法中抛出了异常,MQ就认定你消费失败了,这就是自动确认机制spring.rabbitmq.listener.simple.acknowledge-mode=auto
当然除了自动确认机制还有手动确认机制,这个就是由消费者手动返回告诉消息队列是否消费成功,还有比如,消息队列给消费者发后,不管消费者是否消费都直接默认算你消费成功了,以上就说了三种确认机制,当然还有别的确认机制可以自行去了解
失败重试:这个就是当确认消费者消费失败以后,消息队列重新向消费者发消息的最大次数,
通过这两个我们可以确保一些必须要做的事情,就算失败了也要重做
需要的配置类
java
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* RabbitMQ 直连交换机(Direct Exchange)配置类
*/
@Configuration
public class DirectRabbitConfig {
// 队列名称
public static final String QUEUE_NAME = "DirectQueue";
// 交换机名称
public static final String EXCHANGE_NAME = "DirectExchange";
// 路由键
public static final String ROUTING = "DirectRouting";
/**
* 声明直连队列
* durable: 是否持久化(默认false),持久化队列会存储在磁盘,MQ重启后仍存在;暂存队列仅当前连接有效
* exclusive: 是否排他(默认false),排他队列仅当前连接可用,连接关闭后自动删除,优先级高于durable
* autoDelete: 是否自动删除(默认false),无生产者/消费者使用时自动删除
*
* @return 直连队列实例
*/
@Bean
public Queue directQueue() {
// 一般仅设置队列持久化,其余参数使用默认值(false)
return new Queue(QUEUE_NAME, true);
}
/**
* 声明直连交换机
*
* @return 直连交换机实例
*/
@Bean
public DirectExchange directExchange() {
// 参数:交换机名称、是否持久化、是否自动删除
return new DirectExchange(EXCHANGE_NAME, true, false);
}
/**
* 绑定队列和交换机,并指定匹配的路由键
*
* @return 绑定关系实例
*/
@Bean
public Binding bindingDirect() {
return BindingBuilder.bind(directQueue())
.to(directExchange())
.with(ROUTING);
}
/**
* 配置消息转换器,将消息序列化为JSON格式
*
* @return JSON消息转换器
*/
@Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
}
该类仔细阅读一下,其实就是
设置队列的名称,并设置持久化,
设置交换机的名称,并设置持久化,不会自动删除,
绑定了队列和交换机,并绑定了一个key(路由键),这样子我们通过他来指定放到哪个队列里面去
最后设置了一下消息的转换格式就算将消息序列化为JSON
配置完rabbitmq其实就等于我们将 生产者-消息队列-消费者 中消息队列部分的代码写完了,这里我们只需要完成生产者的代码,以及消费者代码即可