时间来不及的话,可以暂时只记前四个
1.什么是 RabbitMQ
RabbitMQ 是一个开源的消息队列。RabbitMQ 可以让应用程序在分布式环境下进行异步通信,从而实现解耦。它采用生产者-消费者模式来处理消息,并提供了许多高级特性,如消息确认、消息持久化、消息过期等。
RabbitMQ 是 AMQP 协议的具体实现,AMQP 是一种开放的、标准化的消息协议,用于消息中间件系统之间的通信。RabbitMQ 中的交换器、交换器类型、队列、绑定、路由键等都是遵循 AMQP 协议中相应的概念实现的。
2.RabbitMQ 的特点?
-
可靠性: RabbitMQ 使用一些机制来保证可靠性, 如持久化、传输确认及发布确认等。
-
灵活的路由 : 在消息进入队列之前,通过交换器来路由消息。对于典型的路由功能, RabbitMQ 己经提供了一些内置的交换器来实现。针对更复杂的路由功能,可以将多个交换器绑定在一起, 也可以通过插件机制来实现自己的交换器。
-
扩展性: 多个 RabbitMQ 节点可以组成一个集群,也可以根据实际业务情况动态地扩展 集群中节点。
-
高可用性 : 队列可以在集群中的机器上设置镜像,使得在部分节点出现问题的情况下队 列仍然可用。
-
多种协议: RabbitMQ 除了原生支持 AMQP 协议,还支持 STOMP, MQTT 等多种消息 中间件协议。
-
多语言客户端 :RabbitMQ 几乎支持所有常用语言,比如 Java、 Python、 Ruby、 PHP、 C#、 JavaScript 等。
-
管理界面 : RabbitMQ 提供了一个易用的用户界面,使得用户可以监控和管理消息、集 群中的节点等。
-
插件机制 : RabbitMQ 提供了许多插件 , 以实现从多方面进行扩展,当然也可以编写自 己的插件。
3.RabbitMQ 核心概念?
RabbitMQ 的整体模型架构如下:
3.1 生产者和消费者
-
生产者(publisher):生产消息的一方。消息一般包含两个部分:消息头和消息体。
-
消费者(consumer):消费消息的一方。消费者连接到 RabbitMQ 服务器,并订阅到队列上,消费消息时只消费消息体,丢弃标签。
消息一般由 2 部分组成:消息头 和 消息体。
-
消息体也可以称为 payLoad,消息体是不透明的,
-
消息头也叫标签 Label,由一系列的可选属性组成,这些属性包括 routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。生产者把消息交由 RabbitMQ 后,RabbitMQ 会根据消息头把消息发送给感兴趣的 Consumer(消费者)。
3.2 交换机
Exchange(交换器) 用来接收生产者发送的消息并将这些消息路由给服务器中的队列,当路由不到时,会将消息返回给生产者或者直接丢弃。RabbitMQ 的 Exchange 有 4 种类型,不同的类型对应着不同的路由策略:direct(默认)、fanout、topic、headers。
-
RoutingKey(路由键):生产者将消息发给交换器的时候,一般会指定一个 RoutingKey(路由键),用来指定这个消息的路由规则,而这个 RoutingKey 需要与交换器类型和绑定键(BindingKey)联合使用才能最终生效。
-
BindingKey(路由键):BindingKey 用来将交换器和消息队列连接起来。Exchange 和 Queue 的绑定可以是多对多的关系。
BindlingKey没有存储在Exchange中,而是当生产者将消息以及RoutingKey发送过来时,交换机会拿着这个RoutingKey区RabbitMQ的元数据中去匹配BindingKey,匹配成功后,将消息路由到相应的队列。
交换机类型
RabbitMQ 常用的交换机类型有 fanout、direct、topic、headers 这四种,其中:
fanout:fanout 类型的 Exchange 路由规则非常简单,它会把所有发送到该 Exchange 的消息路由到所有与它绑定的 Queue 中,不需要做任何判断操作,所以 fanout 类型是所有的交换机类型里面速度最快的。fanout 类型常用来广播消息。
direct:direct 类型的 Exchange 路由规则也很简单,它会把消息路由到那些 Bindingkey 与 RoutingKey 完全匹配的 Queue 中。
topic:topic 类型的交换器与 direct 类型的交换器相似,也是将消息路由到 BindingKey 和 RoutingKey 相匹配的队列中,但是在匹配规则上进行了扩展,它约定:
-
RoutingKey 为一个点号 . 分隔的字符串,被点号 . 分隔开的每一段独立的字符串称为一个单词,如 “com.rabbitmq.client”、“java.util.concurrent”、“com.hidden.client”。
-
BindingKey 和 RoutingKey 一样,也是点号 . 分隔的字符串;
-
BindingKey 中可以存在两种特殊字符串 * 和 #,用于做模糊匹配,其中 * 用于匹配一个单词,# 用于匹配0个或多个单词。
以上图为例:
-
路由键为 com.rabbitmq.client 的消息会同时路由到 Queue1 和 Queue2;
-
路由键为 com.hidden.client 的消息只会路由到 Queue2 中;
-
路由键为 com.hidden.demo 的消息只会路由到 Queue2 中;
-
路由键为 java.rabbitmq.demo 的消息只会路由到 Queue1 中;
-
路由键为 java.util.concurrent 的消息将会被丢弃或者返回给生产者(需要设置 mandatory 参数),因为它没有匹配任何路由键。
3.3 消息队列
Queue(消息队列) 用来保存消息直到发送给消费者。一个消息可投入一个或多个队列。消息会一直在队列里面,等待消费者连接到这个队列将其取走。
多个消费者可以订阅同一个队列,这时队列中的消息会被轮询给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理,这样避免消息被重复消费。
3.4 Broker
可以将一个 RabbitMQ Broker 看作一台 RabbitMQ 服务器。RabbitMQ Broker 是 RabbitMQ 消息中间件的核心部分,它通过队列、交换机和绑定等机制实现了消息的路由和传递,确保了生产者和消费者之间的可靠通信,它还提供了诸如消息持久化、消息确认、消息过期等功能。
4.RabbitMQ 有哪些工作模式?
rabbitMQ一共有 6 种工作模式,分别是简单模式、工作队列模式、发布订阅模式、路由模式、主题模式以及RPC模式。
简单模式(Simple Mode):简单模式包括一个生产者和一个消费者。生产者将消息发送到队列,消费者从队列中获取消息进行处理。这种模式适用于单个生产者和单个消费者的简单场景,消息的处理是同步的。
工作队列模式(Work Queues Mode):工作队列模式包括一个生产者和多个消费者。生产者将消息发送到共享的队列,多个消费者从队列中获取并处理消息,每个消息只能被一个消费者处理。这种模式适合于多个消费者并发处理消息的情况,提高了系统的处理能力和吞吐量。
发布/订阅模式:发布/订阅模式用于实现一条消息被多个消费者同时接收和处理。在发布/订阅模式中,一个生产者将消息发送到交换器(Exchange)中,交换器将消息广播到所有绑定的队列,每个队列对应一个消费者。这种模式适用于消息需要被多个消费者同时接收和处理的广播场景,如日日志订阅和事件通知等。
路由模式:路由模式用于实现根据消息的路由键(Routing Key)将消息路由到不同的队列中。在路由模式中,一个生产者将消息发送到交换器中,并指定消息的路由键,交换器根据路由键将消息路由到与之匹配的队列中。这种模式适用于根据不同的条件将消息发送到不同的队列中,以实现消息的筛选和分发。
主题模式:主题模式是一种更灵活的消息路由模式,它使用通配符匹配路由键,将消息路由到多个队列中。在主题模式中,一个生产者将消息发送到交换器中,并指定主题(Topic)作为路由键,交换器根据通配符匹配将消息路由到与之匹配的队列中。这种模式适用于消息的复杂路由需求,可以实现高度灵活的消息筛选和分发。
RPC模式:RPC模式是一种用于实现分布式系统中远程调用的工作模式。指的是通过rabbitMQ来实现一种RPC。
5.rabbitMQ如何实现延迟消息?
RabbitMQ中实现延迟消息有两种方式,分别是通过死信队列以及通过延迟消息插件来实现。
6.什么是死信队列?如何导致的?
当消息在一个队列中变成死信之后,如果配置了死信队列,死信将被发送到死信交换机中,死信交换机将死信投递到一个队列上,这个队列就是死信队列。如果没有配置死信队列,那么这个消息将被丢弃。
导致死信的几种原因:
-
消息处理失败:当消费者由于代码错误、消息格式不正确、业务规则冲突等原因无法成功处理一条消息时,这条消息可以被标记为死信。
-
消费者拒绝处理消息:当消费者明确拒绝一条消息时,它可以被标记为死信并发送到死信队列。拒绝消息的原因可能是消息无法处理,或者消费者认为消息不符合处理条件。
-
消息过期:在RabbitMQ中,消息可以设置过期时间。如果消息在规定的时间内没有被消费,它可以被认为是死信并被发送到死信队列。
-
队列满了:队列中的消息已经满了,无法再添加。
-
消息无法路由:当消息不能被路由到任何队列时,例如,没有匹配的绑定关系或路由键时,消息可以被发送到死信队列。
配置死信队列
要设置死信队列,通常需要以下步骤:
-
创建死信队列:定义一个用于存储死信消息的队列。
-
创建死信交换机:为死信队列定义一个交换机,通常是一个direct类型的交换机。
-
将队列与死信交换机绑定:将主要队列和死信交换机绑定,以便无法处理的消息能够被转发到死信队列。
-
在主要队列上设置死信属性:通过设置队列的x-dead-letter-exchange和x-dead-letter-routing-key属性,指定死信消息应该被发送到哪个交换机和路由键。
当消息被标记为死信时,它将被发送到死信队列,并可以由应用程序进一步处理、审查或记录。这种机制有助于增加消息处理的可靠性和容错性,确保不丢失重要的消息,并提供了一种处理失败消息的方式。以下是一个配置死信队列的方式:
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfig {
//配置死信队列和交换机
@Bean public DirectExchange deadLetterExchange() {
return new DirectExchange("dead-letter-exchange");
}
//死信队列
@Bean public Queue deadLetterQueue() {
return new Queue("dead-letter-queue");
}
//绑定死信队列到死信交换机
@Bean public Binding deadLetterBinding() {
return BindingBuilder.bind(deadLetterQueue()).to(deadLetterExchange())
.with("dead-letter-routing-key");
}
//主队列的交换机
@Bean public DirectExchange mainExchange() {
return new DirectExchange("main-exchange");
}
//主队列
@Bean
public Queue mainQueue() {
Map<String, Object> args = new HashMap<>(2);
// 声明当前队列绑定的死信交换机
args.put("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE);
// 这里声明当前队列的死信路由key
args.put("x-dead-letter-routing-key", "dead-letter-routing-key");
return QueueBuilder.durable("main-queue").withArguments(args).build();
}
//绑定主队列到主交换机
@Bean
public Binding binding() {
return BindingBuilder.bind(mainQueue()).to(mainExchange()).with("main-routing-
key");
}
}
这样,消费者在消费的时候,分别监听主队列和死信队列就可以了:
@Component
public class DeadLetterMessageReceiver {
@RabbitListener(queues = "dead-letter-queue")
public void receiveA(Message message, Channel channel) throws IOException {
System.out.println("收到死信消息:" + new String(message.getBody()));
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
@Component
public class MainMessageReceiver {
@RabbitListener(queues = "main-queue")
public void receiveA(Message message message, Channel channel) throws IOException {
System.out.println("收到普通消息A:" + new String(message.getBody()));
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
RabbitMQ的死信队列其实有很多作用,比如我们可以借助他实现延迟消息,进而实现订单的到期关闭,超时关单等业务逻辑。
7.RabbitMQ如何防止重复消费
RabbitMQ的消息消费是有确认机制的,正常情况下,消费者在消费消息消费成功后,会发送一个确认消息,消息队列接收到之后,就会将该消息从消息队列中删除,下次也就不会再投递了。 但是,如果存在网络延迟的问题,导致确认消息没有发送到消息队列,导致消息重投了,是有可能发生重复消费的,所以,当我们使用MQ的时候,消费者端自己也需要做好幂等控制来防止消息被重复消费。 一般来说,处理这种幂等问题就是我们提过无数次的'一锁、二判、三更新'。
8.RabbitMQ是如何保证高可用的
RabbitMQ通过集群的方式保证高可用。RabbitMQ 有三种模式:单机模式、普通集群模式、镜像集群模式。