赞
踩
一、RabbitMQ 的作用是什么?在什么场景使用?
RabbitMQ是一个开源的消息代理中间件,它实现了高级消息队列协议(AMQP),用于在应用程序之间进行可靠的异步消息传递。
RabbitMQ的主要作用包括:
1. 解耦:RabbitMQ允许将应用程序的不同部分解耦,使它们能够独立地进行开发和扩展。通过将消息发送到RabbitMQ,发送方不需要直接与接收方进行通信,而是通过消息队列进行通信。
2. 异步通信:RabbitMQ允许应用程序通过消息队列进行异步通信。发送方将消息发送到队列中,接收方从队列中获取消息并进行处理。这种异步通信模式可以提高系统的可伸缩性和性能,因为发送方和接收方不需要实时进行交互。
同步调用
Feign客户端可以实现服务间的通信,但是Feign是同步调用,也就是说A服务调用B服务之后,会进入阻塞/等待状态,直到B服务返回调用结果给A服务,A服务才会继续往后执行
在如下场景中:注册接口完成注册之后,需要调用 service-c 来发送短信通知用户注册成功;service-a无需等待service-c的发送短信的结果可以直接响应前端,service-a对service-c的调用可以使用异步调用
异步调用:
当A服务调用C服务之后,无需等待C的调用结果,可以继续往下执行;那么服务间的异步通信该如何实现呢?
服务之间可以通过消息队列实现异步调用
同步调用
A服务调用B服务,需要等待B服务执行完毕的返回值,A服务才可以继续往下执行
同步调用可以通过REST和RPC完成
REST: ribbon、Feign
RPC: Dubbo
异步调用
A服务调用B服务,而无需等待B服务的执行结果,也就是说在B服务执行的同时A服务可以继续往下执行
通过消息队列实现异步调用
3. 负载均衡:RabbitMQ可以将消息分发给多个消费者,实现负载均衡。当有多个消费者订阅同一个队列时,RabbitMQ将消息均匀地分发给消费者,确保每个消费者都有机会处理消息。
4. 消息持久化:RabbitMQ可以将消息持久化到磁盘,以确保消息在发生故障时不会丢失。这对于关键业务的消息传递非常重要。
5. 可靠性:RabbitMQ提供了多种机制来确保消息的可靠性传递,包括确认机制、事务机制和持久化机制。这些机制可以确保消息在发送和接收过程中不会丢失或损坏。
总之,RabbitMQ是一个功能强大的消息代理中间件,可以在应用程序之间提供可靠的异步消息传递,实现解耦、异步通信、负载均衡和消息持久化等功能。它被广泛应用于分布式系统、微服务架构和大规模数据处理等场景。
RabbitMQ 的常用场景如下几种:
场景说明:用户下单之后,订单系统要通知库存系统
传统方式:订单系统直接调用库存系统提供的接口,如果库存系统出现故障会导致订单系统失败 |
---|
使用消息队列: |
---|
场景说明:用户注册成功之后,需要发送注册邮件及注册短信提醒
传统方式: |
---|
使用消息队列: |
---|
场景说明:应用系统之间的通信,例如聊天室
削峰填谷
场景说明:秒杀业务
大量的请求不会主动请求秒杀业务,而是存放在消息队列(缓存) |
---|
场景说明:系统中大量的日志处理
日志搜集处理 |
---|
使用 RabbitMQ 的业务场景总结:
注册功能的短信提醒 (使用RabbitMQ实现服务间的异步通信)
订单超时取消业务(基于RabbitMQ的死信队列实现消息延迟)
对于订单接口、秒杀接口等高并发业务(基于消息队列进行业务接口调用、削峰填谷)
二、RabbitMQ 中常见的消息模型有哪些?
RabbitMQ中常见的消息模型有以下几种:
1. 简单模型(Simple Model):简单模型是最基本的消息模型,它包括一个生产者和一个消费者。生产者将消息发送到队列中,消费者从队列中获取消息并进行处理。这种模型适用于简单的单向通信场景。
2. 工作队列模型(Work Queue Model):工作队列模型也被称为任务队列模型。它包括一个或多个生产者将消息发送到队列中,多个消费者从队列中获取消息并进行处理。消息在队列中按顺序分发给消费者,每个消息只能被一个消费者处理。这种模型适用于需要将工作负载分发给多个消费者的场景。
3. 订阅模型(Publish/Subscribe Model):发布/订阅模型包括一个生产者将消息发布到交换机(Exchange),交换机将消息广播给绑定到它的多个队列,每个队列都有一个对应的消费者。这种模型适用于需要将消息广播给多个消费者的场景。
4. 路由模型(Routing Model):路由模型基于发布/订阅模型,但是引入了路由键(Routing Key)的概念。生产者将消息发送到交换机,并指定一个路由键,交换机根据路由键将消息路由到绑定了匹配路由键的队列。每个队列都有一个对应的消费者。这种模型适用于需要根据消息内容进行选择性消费的场景。
5. 主题模型(Topic Model):主题模型也是基于发布/订阅模型,但是引入了主题(Topic)的概念。生产者将消息发送到交换机,并指定一个主题,交换机根据主题将消息路由到匹配主题的队列。每个队列都有一个对应的消费者。这种模型适用于需要根据消息主题进行选择性消费的场景。
这些消息模型提供了不同的消息传递方式和灵活性,可以根据具体的业务需求选择合适的模型。
三、RabbitMQ 中的AMQP协议是什么?
AMQP(Advanced Message Queuing Protocol)是一种开放的消息队列协议,用于在应用程序之间进行可靠的异步消息传递。它是一种标准化的协议,由多个厂商共同制定和支持,其中包括RabbitMQ。
AMQP定义了一套统一的消息模型、消息路由和消息传递机制,使得不同的消息中间件可以遵循相同的协议进行通信。它提供了以下几个核心概念:
1. 生产者(Producer):负责将消息发送到消息队列中。
2. 消息队列(Queue):用于存储消息的容器,生产者将消息发送到队列中,消费者从队列中获取消息进行处理。
3. 交换机(Exchange):用于接收生产者发送的消息,并将消息路由到一个或多个队列中。
4. 绑定(Binding):用于将交换机和队列进行关联,指定消息的路由规则。
5. 消费者(Consumer):从队列中获取消息,并进行相应的处理。
AMQP协议具有以下特点:
1. 可靠性:AMQP提供了消息确认机制,确保消息在发送和接收过程中不会丢失。
2. 灵活性:AMQP支持多种消息模型,包括简单模型、工作队列模型、发布/订阅模型、路由模型和主题模型,可以根据具体需求选择合适的模型。
3. 互操作性:AMQP是一个开放的标准协议,不同的消息中间件可以遵循相同的协议进行通信,实现不同消息中间件之间的互操作性。
RabbitMQ作为AMQP的实现之一,通过支持AMQP协议,提供了可靠的消息传递和高性能的消息代理服务。
四、如何避免重复消费?
RabbitMQ本身并不提供显式的机制来避免重复消费,但可以通过一些技术手段来实现重复消费的避免。以下是一些常用的方法:
1. 消费端幂等性:在消费端实现幂等性,即使消息被重复消费,也不会产生重复的副作用。可以通过在消费端记录已经处理过的消息的唯一标识,并在处理之前检查是否已经处理过该消息。
解决方案:处理成功的消息setnx到redis
2. 消息去重:在消费端维护一个已消费消息的记录,可以使用数据库、缓存或者分布式锁等机制来实现。在消费消息之前,检查该消息是否已经被消费过,如果已经被消费过,则直接忽略。
3. 消费端手动确认:在消费端使用手动确认模式(acknowledgment mode),即消费者在处理完消息之后,手动发送确认消息给RabbitMQ,告知消息已经被消费。如果消费端处理消息失败,可以选择不发送确认消息,使消息重新进入队列,然后重新消费。
4. 消息过期时间:可以在发送消息时设置消息的过期时间(TTL),当消息过期后,RabbitMQ会将其丢弃,不会再被消费。这样可以避免消息在队列中长时间滞留,导致重复消费。
5. 消息去重中间件:可以使用一些消息去重的中间件,如 Redis 的 setnx 命令,将已经消费过的消息的唯一标识存储在中间件中,每次消费消息之前,先检查该消息是否已经存在于中间件中,如果存在,则表示消息已经被消费过,可以直接忽略。
需要根据具体的业务需求和系统架构选择合适的方法来避免重复消费。以上方法可以单独使用,也可以组合使用,以提高消息消费的可靠性和正确性。
五、如何保证消息的可靠性传递?
消息的可靠性:从生产者发送消息
——消息队列存储消息
——消费者消费消息
的整个过程中消息的安全性及可控性。
生产者发送消息:消息确认机制和Return机制
消息确认机制:确认消息提供者是否成功发送消息到交换机
return机制:确认消息是否成功的从交换机分发到队列
- spring:
- rabbitmq:
- publisher-confirm-type: simple # 开启消息确认模式
- publisher-returns: true # 使用return监听机制
消息确认 、 return机制
- @Component
- public class MyRabbitMQListener implements
- RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback{
-
- @Autowired
- private RabbitTemplate rabbitTemplate;
-
- @PostConstruct //在Bean的属性注入完成后调用
- public void init(){
- rabbitTemplate.setConfirmCallback(this);
- rabbitTemplate.setReturnCallback(this);
- }
-
- @Override
- public void confirm(CorrelationData correlationData, boolean b, String s) {
- if(b){
- System.out.println("---消息发送到交换机:成功");
- }else{
- System.out.println("---消息发送到交换机:失败");
- }
- }
-
- @Override
- public void returnedMessage(Message message, int i, String s, String s1, String s2) {
- System.out.println("---"+ new String ( message.getBody() )+"发送失败");
- }
- }
消息队列存储消息:RabbitMQ支持消息持久化、RabbitMQ支持集群
消费者消费消息:ACK手动应答机制
对于消息队列有一个特性:消费者从队列中消费一个消息之后,这个消息会从队列中移除
- 如果消费者从队列中获取消息之后,队列直接清除这条消息,那么在消费者消息处理过程如果出现处理失败情况,将不能再次处理此消息;
- 因此RabbitMQ提供了消费者的ACK机制,确保消息可以被消费者成功处理。、
- @Service
- @RabbitListener(queues = "queue1")
- public class GetMsg {
-
- @Autowired
- private ObjectMapper objectMapper;
-
- /**
- * 1.在接收消息队列中的消息的方法上,添加Channel、Message类型参数 --> 开启手动ACK应答
- * 2.在消息处理成功之后,手动ack应答
- * 3.如果业务处理出现异常,则手动nack应答(消息队列不会删除此条消息)
- */
- @RabbitHandler
- public void receiveMsg(String msg, Channel channel, Message message) throws IOException {
- try {
- //a.接收消息
- System.out.println("------------接收MSG:"+msg);
- Member member = objectMapper.readValue(msg, Member.class);
- System.out.println(member);
- //b.处理消息(业务:向 用户的手机号发送短信提醒)
- if( !("13030303300".equals( member.getUserTel()) ) ){
- throw new NullPointerException();
- }else{
- System.out.println("向"+member.getUserTel()+"发送短信");
- }
- //c.消息处理成功之后,手动ack应答
- channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
- } catch (Exception e) {
- e.printStackTrace();
- //d.如果消息处理失败,则手动给一个nack应答
- channel.basicNack(message.getMessageProperties().getDeliveryTag(),false, true);
- System.err.println("get msg1 failed msg = "+msg);
- }
- }
-
- }
六、消息的延迟机制是什么?
延迟队列:消息进入到队列之后,延迟指定的时间才能被消费者消费。
延迟消息:对消息进行设置延迟时间。
以上两种情况 RocketMQ 支持,但是 RabbitMQ 不支持。
AMQP协议和RabbitMQ队列本身是不支持延迟队列功能的,但是可以通过TTL(Time To Live)特性模拟延迟队列的功能
TTL就是消息的存活时间。RabbitMQ可以分别对队列和消息设置存活时间
在创建队列的时候可以设置队列的存活时间,当消息进入到队列并且在存活时间内没有消费者消费,则此消息就会从当前队列被移除;
创建消息队列没有设置TTL,但是消息设置了TTL,那么当消息的存活时间结束,也会被移除;
当TTL结束之后,我们可以指定将当前队列的消息转存到其他指定的队列
七、什么是死信队列?
在 RabbitMQ 中,死信队列(Dead Letter Queue,DLQ)是通过 RabbitMQ 的扩展功能来实现的。DLQ 的主要作用是用于存储无法被消费者成功处理的消息。
在 RabbitMQ 中,消息的死信处理是通过以下几个基本组件来实现的:
1. 消息属性(Message Properties):在消息发布时,可以通过设置消息的属性来标记这条消息是否是死信消息。属性 `x-dead-letter-exchange` 用于指定死信消息转发到的交换器,属性 `x-dead-letter-routing-key` 用于指定死信消息的路由键。
2. 死信交换器(Dead Letter Exchange):死信交换器是一个特殊的交换器,它用于接收并转发死信消息。当一条消息被标记为死信后,RabbitMQ 将根据 `x-dead-letter-exchange` 属性指定的交换器将该消息发送到死信交换器。
3. 死信队列(Dead Letter Queue):死信队列是与死信交换器相关联的队列,它用于存储死信消息。一旦消息被发送到死信交换器并路由到死信队列,消费者可以重新处理、分析或者进行其他操作。
整个流程如下:
1. 创建一个正常的交换器和队列,并将它们进行绑定。
2. 设置队列的属性 `x-dead-letter-exchange` 和 `x-dead-letter-routing-key` 分别为死信交换器和死信队列的路由键。
3. 当消息被发送到该队列时,如果消息发生了死信情况(例如消费者拒绝接收、消息过期等),则该消息会被标记为死信,并转发到死信交换器。
4. 死信交换器根据 `x-dead-letter-routing-key` 属性,将死信消息发送到死信队列中。
通过配置死信交换器和死信队列,你可以处理和跟踪无法被消费者成功处理的消息,并对其进行适当的后续处理。这提供了一种容错和错误处理的机制,确保消息不会丢失。
八、RabbitMQ 的镜像队列是什么?
镜像队列(Mirrored Queue)是 RabbitMQ 中的一个功能,用于提供消息队列的高可用性。镜像队列通过在多个节点上复制消息队列的数据来实现。
在镜像队列中,一个主队列在一个节点上创建,然后通过设置节点的镜像参数,将该队列的副本(镜像)复制到其他节点上。每个镜像队列都拥有相同的名称,可以在不同节点上进行读写操作。
镜像队列的优点是能够提供数据的冗余备份,即使其中一个节点发生故障,其他节点上的队列仍然能够正常运行。这提供了高可用性和故障恢复的能力。
需要注意的是,由于数据的复制和同步需要消耗额外的网络和资源开销,使用镜像队列会增加消息的延迟和系统的负载。因此,在应用程序的设计中需要综合考虑可用性和性能方面的需求,选择是否使用镜像队列。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。