消息队列的主要功能:流量削峰、
如果订单系统最多能处理一万次订单,这个处理能力应付正常时段的下单时绰绰有余,正常时段我们下单一秒后就能返回结果。但是在高峰期,如果有两万次下单操作系统是处理不了的,只能限制订单超过一万后不允许用户下单。使用消息队列做缓冲,我们可以取消这个限制,把一秒内下的订单分散成一段时间来处理,这时有些用户可能在下单十几秒后才能收到下单成功的操作,但是比不能下单的体验要好。
应用解耦:
异步处理:
常用的消息队列:
kafka:通常是大数据的处理
RocketMQ: 非常靠谱,一般是金融级别的无法
rabbitMq: 当前最主流的消息中间件之一。结合erlang语言本身的并发优势,性能好时效性微秒级,社区活跃度也比较高,管理界面用起来十分方便,如果你的数据量没有那么大,中小型公司优先选择功能比较完备的RabbitMQ;
四大核心概念:
生产者
交换机:一方面它接收来自生产者的消息,另一方面它将消息推送到队列中。交换机必须确切知道如何处理它接收到的消息,是将这些消息推送到特定队列还是推送到多个队列,亦或者是把消息丢弃,这个得有交换机类型决定
队列:队列是RabbitMQ内部使用的一种数据结构,尽管消息流经RabbitMQ和应用程序,但它们只能存储在队列中。队列仅受主机的内存和磁盘限制的约束,本质上是一个大的消息缓冲区。
消费者
Downloading and Installing RabbitMQ — RabbitMQ
安装
拉取镜像:
docker pull rabbitmq:3.8.12-management-alpine
启动:
docker run -d --hostname rabbit_host1 --name xd_rabbit -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=password -p 15672:15672 -p 5672:5672 rabbitmq:3.8.12-management-alpine
浏览器访问: ip:15672
rabbitMQ 的基本概念
1、TTL 存活时间
time to live 消息存活时间,如果在存活时间内没有被消费,就会被清除
2、RabbitMQ 支持两种ttl
单独消息进行ttl配置
整个队列进行配置ttl(居多)
3、什么是死信队列
没有被及时消费的消息存放的队列
4、死信交换机
当消息成为死信后,会被重新发送到另一个交换机,这个交换机就是死信交换机
消息有哪几种情况会成为死信:
1、消费者拒收消息(basic.reject/basic.nack),并且没有重新入队requeue = false;
2、消息在队列中未被消费,且超过队列或者消息本身的过期时间TTL
3、队列的消息长度达到极限
注意,消息成为死信后,如果该队列绑定了死信交换机,则消息会被死信交换机重新路由到死信队列。
延迟队列:
一种带有延迟功能的消息队列,producer 将消息发送到消息队列的服务端后,但是并不希望这条消息被立马投递,而是推迟到在当前时间点之后的某一个时间投递到消费者,该消息即定时消息;
rocketMQ 自带延迟队列的功能,但是rabbitMQ 没有,通过死信队列实现延迟功能
如下:消费者直接监听死信队列;
使用RabbitMQ
1、导入依赖
<!--消息队列-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2、各个项目中添加配置(spring 下的配置)
# 消息队列
rabbitmq:
host: 47.100.54.149
port: 5672
virtual-host: /
username: admin
password: password
# 开启手动确认消息
listener:
simple:
acknowledge-mode: manual
3、建立配置文件以及配置类
mqconfig:
# 延迟队列,不能被监听消费
coupon_release_delay_queue: coupon.release.delay.queue
# 延迟队列的消息过期后转发的队列
coupon_release_queue: coupon.release.queue
# 交换机
coupon_event_exchange: coupon.event.exchange
# 进入延迟队列的路由key
coupon_release_delay_routing_key: coupon.release.delay.routing.key
# 消息过期,进入释放死信队列的key
coupon_release_routing_key: coupon.release.routing.key
# 消息过期的时间,毫秒
ttl: 15000
@Configuration
@Data
public class RabbitMqconfig {
/**
* 交换机
*/
@Value("${mqconfig.coupon_event_exchange}")
private String eventExchange;
/**
* 第一个队列 延迟队伍
*/
@Value("${mqconfig.coupon_release_delay_queue}")
private String couponReleaseDelayQueue;
/**
* 第一个队列的路由key
* 进入队列的路由key
*/
@Value("${mqconfig.coupon_release_delay_routing_key}")
private String couponReleaseDelayRoutingKey;
/**
* 第二个队列,被监听恢复库存的队伍
*/
@Value("${mqconfig.coupon_release_queue}")
private String couponReleaseQueue;
/**
* 第二个队列的路由key
* 即进入死信队列的路由key
*/
@Value("${mqconfig.coupon_release_routing_key}")
private String couponReleaseRoutingKey;
/**
* 过期时间
*/
@Value("${mqconfig.ttl}")
private Integer ttl;
/**
* 消息转换器
* @return
*/
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
/**
* 定义交换机
* Topic 类型,也可以是direct路由
* 一般一个微服务一个交换机
* @return
*/
@Bean
public Exchange couponEventExchange(){
return new TopicExchange(eventExchange,true,false);
}
/**
* 延迟队列
*/
@Bean
public Queue couponReleaseDelayQueue(){
Map<String,Object> args = new HashMap<>();
args.put("x-message-ttl",ttl);
args.put("x-dead-letter-routing-key",couponReleaseRoutingKey);
args.put("x-dead-letter-exchange",eventExchange);
return new Queue(couponReleaseDelayQueue,true,false,false,args);
}
/**
* 死信队列
*/
@Bean
public Queue coupponReleaseQueue(){
return new Queue(couponReleaseQueue,true,false,false);
}
/**
* 死信队列绑定关系建立
* 建立队列与交换机的绑定
* @return
*/
@Bean
public Binding couponReaseBinding(){
return new Binding(couponReleaseQueue,Binding.DestinationType.QUEUE,eventExchange,couponReleaseRoutingKey,null);
}
/**
* 第一个队列即延迟队列的绑定关系建立
* 建立队列与交换机的绑定
* @return
*/
@Bean
public Binding couponReaseDelayBinding(){
return new Binding(couponReleaseDelayQueue,Binding.DestinationType.QUEUE,eventExchange,couponReleaseDelayRoutingKey,null);
}
}
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class MQtest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void sendDelayMsg(){
// 发送消息,有三个参数,分别是交换机、路由key 消息体
rabbitTemplate.convertAndSend("coupon.event.exchange","coupon.release.delay.routing.key","this is a coupon ");
}
}