RabbitMQ

本文详细介绍了RabbitMQ,一个开源的消息队列系统,其特点包括可靠性、灵活路由、扩展性和高可用性。文章涵盖了生产者-消费者模型、交换器、队列、死信处理、防止重复消费以及RabbitMQ的集群和事务机制。
摘要由CSDN通过智能技术生成

时间来不及的话,可以暂时只记前四个

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 常用的交换机类型有 fanoutdirecttopicheaders 这四种,其中:

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 有三种模式:单机模式、普通集群模式、镜像集群模式。

9.如何保障消息一定能发送到RabbitMQ

10.RabbitMQ如何保证消息不丢

11.介绍下RabbitMQ的事务机制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

真滴book理喻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值