• RabbitMQ基础概念详解


    一、什么是RabbitMQ

    RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种语言客户端。

    AMQP:即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计

    rabbitMQ的工作性质类似于物流,物流公司职能就是接收、存储、转发。最终确保收件人能够及时的获取到寄件人发的物件。rabbitMQ整体工作流程来看可以分为三个工作对象:生产者(P)、队列(Quene)、消费者(C)。

    生产者:发送消息的程序

    消费者:接收消息的程序

    队列:可以看作是一个消息缓冲器,多个生产者发送的消息进入到同一个队列中,多个消费者可以从同一个队列中接收消息并执行相应的业务逻辑。

    二、RabbitMQ高性能的原因

    RabbitMQ基于Erlang语言实现,而Erlang语言最初用来控制交换机或者变换协议等,非常适合构建分布式应用,它与Socket有着一样的延迟,这样使得RabbitMQ在Broker之间进行数据交互的性能非常优秀。

    三、Message Acknowledgments(消息确认机制)

    如果消费者C1在处理消息的过程中意外挂掉了,也就是业务逻辑没有正常执行完,那我们还希望有另外的消费者C2来继续执行这条消息,就需要保证RabbitMQ知道C1是否正常执行了该条消息,这里也就有了RabbitMQ的消息确认。C1在正常执行完消息之后会返回给RabbitMQ一个确认信息,告知RabbitMQ该条消息已经被接收、执行,RabbitMQ可以删除该消息了。有了这样的机制之后,我们就可以保证队列中的消息能够被消费者正常接收并执行了()。 

    从消费者到RabbitMQ的传递处理确认被称为消息传递协议中的确认。代理对发布者的确认是称为发布者确认的协议扩展 。两种功能都基于相同的思想,并受到TCP的启发。

    (1)自动确认:

      消费者在声明队列时,可以指定autoAck参数,当boolean autoAck=true时,一旦消费者接收到了消息,就视为自动确认了消息。如果消费者在处理消息的过程中,出了错,就没有什么办法重新处理这条消息,所以我们很多时候,需要在消息处理成功后,再确认消息,这就需要手动确认。

    (2)手动确认:

          1)当boolean autoAck=false时,RabbitMQ会等待消费者显式发回确认信号后才从内存(和磁盘,如果是持久化消息的话,后面会讲到消息持久化)中移去消息。否则,RabbitMQ会在队列中消息被消费后立即删除它。

          2)采用消息确认机制后,只要令autoAck=false,消费者就有足够的时间处理消息(任务),不用担心处理消息过程中消费者进程挂掉后消息丢失的问题,因为RabbitMQ会一直持有消息直到消费者显式调用basicAck为止。

          3)当autoAck=false时,对于RabbitMQ服务器端而言,队列中的消息分成了两部分:一部分是等待投递给消费者的消息;一部分是已经投递给消费者,但是还没有收到消费者ack信号的消息。如果服务器端一直没有收到消费者的确认信号,并且消费此消息的消费者已经断开连接,则服务器端会安排该消息重新进入队列,等待投递给下一个消费者。

           通过消息自动确认和手动确认之间的比较可以知道,手动确认在信息安全方面更有优势,但是如果申明了手动确认,但是最后又没有发回确认信息给RabbitMQ,就会导致RabbitMQ无法及时的释放队列中的消息,而内存的消耗也会逐步增加。所以一定要注意返回确认消息

    四、Message durability(消息持久化)

    上面我们保证了在RabbitMQ服务正常运转情况下,队列中的消息都能够正常被消费者接收执行,但是如果RabbitMQ服务崩溃宕机,我们的消息仍会消失,这显然不是我们想要的结果。如何保证RabbitMQ服务宕机重启之后我们的消息仍然能够继续消费呢?

    解决方案:消息持久化

    (1)队列持久化

    boolean durable = true;
    channel.queueDeclare("hello", durable, false, false, null);
    
    //"hello":申明的队列名称

    我们可以通过在代码中使用以上代码申明队列持久化,以保证RabbitMQ服务重启之后,我们的队列不会消失。消息生产者和消费者代码中都需要此申明。

    (2)消息持久化

          

    import com.rabbitmq.client.MessageProperties;
    
    channel.basicPublish("", "Hello_Java",
                MessageProperties.PERSISTENT_TEXT_PLAIN,
                message.getBytes());

    申明了队列持久化和消息持久化之后,我们的RabbitMQ就可以保证重启之后消息队列消息不会丢失了。

    前面为了简单明了说明RabbitMQ的工作流程,简化了消息转送的步骤,实际上消息由生产者发出后,先到达交换机,再由交换机路由到RabbitMQ的队列,消费者再从队列中获取到消息,下图描述了消息的正确转发步骤:

    图中的  'X'  代表的就是交换机 

    从途中我们可以了解到,生产者不会将任何消息直接发送到RabbitMQ的队列中,而是发送给了交换机,但是交换机如何判定此条消息到底应该发送到哪个队列中?还是直接丢弃?又或者是发送到多个队列中?这就由交换机的交换机类型决定:

    四、4种交换机类型

    交换机可以理解成具有路由表的路由程序。每个消息都有一个称为路由键(routing key)的属性,就是一个简单的字符串。

    RabbitMQ中有4种交换机类型:Direct exchange、Fanout exchange、Topic exchange、Headers exchange。

    (1)Direct exchange 处理路由键

    将一个队列绑定到一个交换机上,要求消息与一个特定的路由键完全匹配,例如队列绑定到交换机上要求路由键是”abc“,则只有被标记为“abc”的消息才会被转发,不会转发“abc.a”或者“abc.asfa”。注意是完全匹配!

    (2)Fanout exchange 不处理路由键

    此种交换机类型非常好理解,只需要将队列绑定到交换机上,发送到交换机上的消息都会被转发到与该交换机绑定的所有队列中,你可以想象一下村口放大喇叭的情景:一个人在话筒前喊话,消息通过大喇叭传播转发,此时所有能听到喇叭声(与喇叭有绑定关系的)人都能接收到该消息

    (3)Topic exchange 路由键配合某模式匹配

    将路由键和某种模式进行匹配,队列需要绑定到一个模式上,符号“#”匹配一个或者多个词,“*”匹配一个词。例如“abc.#”可以匹配到“abc.asfd.asga.asf”。"abc."只能匹配到“abc.asfd”。

    (4)Headers exchange  根据消息的Headers属性匹配

    不处理路由键,而是根据消息内容中的Headers属性进行匹配,在队列和交换机进行绑定的时候,指定一组键值对,发送消息时,消息的Headers与交换机指定的键值对进行匹配,如果完全匹配,则消息会被转发。

    五、RabbitMQ架构图

    下图是RabbitMQ的架构模型图,消息生产者producter只需要关注消息发送到哪个交换机,而消息消费者Consumer只需要关注连接哪个消息队列Queue。

    另外一篇中间件AcitiveMQ的集群文章:https://blog.csdn.net/qq_43655835/article/details/102392005

  • 相关阅读:
    前端程序员容易忽视的一些基础知识
    一道前端学习题
    Unity调用Windows对话框保存时另存为弹框
    Unity镜子效果的实现(无需镜子Shader)
    Unity射线检测的用法总结
    unity中实现简单对象池,附教程原理
    Unity调用Window提示框Yes/No(英文提示窗)
    Unity调用Windows弹框、提示框(确认与否,中文)
    C#LinQ语法
    服务器的购买与网站的创建
  • 原文地址:https://www.cnblogs.com/wgty/p/12810495.html
Copyright © 2020-2023  润新知