Skip to content

rabbitMQ

一、介绍

rabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、C、用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不错, 与SpringAMQP完美的整合、API丰富易用

二、核心概念

  • Broker:RabbitMQ的服务端程序,可以认为一个mq节点就是一个broker

  • Producer生产者:创建消息Message,然后发布到RabbitMQ中

  • Consumer消费者:消费队列里面的消息

  • Message 消息:生产消费的内容,有消息头和消息体,也包括多个属性配置,比如routingKey路由键

  • Queue 队列:是RabbitMQ 的内部对象,用于存储消息,消息都只能存储在队列中

  • Channel 信道:一条支持多路复用的通道,独立的双向数据流通道,可以发布、订阅、接收消息。信道是建立在真实的TCP连接内的虚拟连接,复用TCP连接的通道

  • Connection连接:是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑,一个连接上可以有多个channel进行通信

  • Exchange 交换器:生产者将消息发送到 Exchange,交换器将消息路由到一个或者多个队列中,里面有多个类型,后续再一一介绍,队列和交换机是多对多的关系。

  • RoutingKey 路由键:生产者将消息发给交换器的时候,一般会指定一个RoutingKey,用来指定这个消息的路由规则,最大长度255 字节

  • Binding 绑定:通过绑定将交换器与队列关联起来,在绑定的时候一般会指定一个绑定键 ( BindingKey ),这样 RabbitMQ 就知道如何正确地将消息路由到队列了

注:生产者将消息发送给交换器时,需要一个RoutingKey,当BindingKey和 RoutingKey相匹配时,消息会被路由到对应的队列中

  • Virtual host 虚拟主机

    • 用于不同业务模块的逻辑隔离,一个Virtual Host里面可以有若干个Exchange和Queue,同一个VirtualHost 里面不能有相同名称的Exchange或Queue

    • 默认是 /

      • /dev

      • /test

      • /pro

三、交换机

rabbitmq的生产者将消息发送到 Exchange交换机,交换器将消息路由到一个或者多个队列中,交换机有多个类型,队列和交换机是多对多的关系。交换机只负责转发消息,不具备存储消息的能力, 如果没有队列和exchange绑定,或者没有符合的路由规则,则消息会被丢失。

RabbitMQ有四种交换机类型,分别是Direct exchange(点对点)、Fanout exchange(广播)、Topic exchange、Headers exchange(基本不使用)

  • Direct Exchange 定向:将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配

例子:如果一个队列绑定到该交换机上要求路由键 “aabb”,则只有被标记为“aabb”的消息才被转发,不会转发aabb.cc,也不会转发gg.aabb,只会转发aabb。处理路由健

  • Fanout Exchange 广播:只需要简单的将队列绑定到交换机上,一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息

Fanout交换机转发消息是最快的,用于发布订阅,广播形式,中文是扇形。不处理路由健

  • Topic Exchange 通配符:主题交换机是一种发布/订阅的模式,结合了直连交换机与扇形交换机的特点,将路由键和某模式进行匹配。此时队列需要绑定要一个模式上,符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词

例子:因此“abc.#”能够匹配到“abc.def.ghi”,但是“abc.*” 只会匹配到“abc.def”。

  • Headers Exchanges(少用):根据发送的消息内容中的headers属性进行匹配, 在绑定Queue与Exchange时指定一组键值对

当消息发送到RabbitMQ时会取到该消息的headers与Exchange绑定时指定的键值对进行匹配;如果完全匹配则消息会路由到该队列,否则不会路由到该队列。不处理路由键

四、发布订阅模式

发布-订阅模型中,消息生产者不再是直接面对queue(队列名称),而是直面exchange,都需要经过exchange来进行消息的发送, 所有发往同一个fanout交换机的消息都会被所有监听这个交换机的消费者接收到。

rabbitmq发布订阅模型:通过把消息发送给交换机,交互机转发给对应绑定的队列,交换机绑定的队列是排它独占队列,自动删除

五、RabbitMQ的工作模式

  • 简单模式:一个生产、一个消费,不用指定交换机,使用默认交换机

  • 工作队列模式:一个生产,多个消费,可以有轮训和公平策略,不用指定交换机,使用默认交换机

  • 发布订阅模式:fanout类型交换机,通过交换机和队列绑定,不用指定绑定的路由健,生产者发送消息到交换机,fanout交换机直接进行转发,消息不用指定routingkey路由健

  • 路由模式:direct类型交换机,过交换机和队列绑定,指定绑定的路由健,生产者发送消息到交换机,交换机根据消息的路由key进行转发到对应的队列,消息要指定routingkey路由健

  • 通配符模式:topic交换机,过交换机和队列绑定,指定绑定的【通配符路由健】,生产者发送消息到交换机,交换机根据消息的路由key进行转发到对应的队列,消息要指定routingkey路由健

    • 交换机和队列绑定时用的binding使用通配符的路由健

    • 生产者发送消息时需要使用具体的路由健

六、可靠性投递

rabbitmq和rocketmq处理消息的机制不一样,rabbitmq消息投递路径是:生产者-->交换机->队列->消费者

它需要保证生产者到交换机的信息投递和交换机到队列的两布投递。

通过以下两种方式保证

  • 生产者到交换机:通过confirmCallback

  • 交换机到队列:通过returnCallback

开启消息确认机制以后,保证了消息的准确送达,但由于频繁的确认交互, rabbitmq 整体效率变低,吞吐量下降严重,不是非常重要的消息不建议用消息确认机制

七、消费者消息确认

消费者从broker中监听消息,需要确保消息被合理处理

消费者从RabbitMQ收到消息并处理完成后,反馈给RabbitMQ,RabbitMQ收到反馈后才将此消息从队列中删除,如果消费者在处理消息出现了网络不稳定、服务器异常等现象, 那么就不会有ACK反馈,RabbitMQ会认为这个消息没有正常消费,会将消息重新放入队列中。只有当消费者正确发送ACK反馈,RabbitMQ确认收到后,消息才会从RabbitMQ服务器的数据中删除。

注意:队列消息尽量要保证一定的幂等性操作,因为网络不稳定的情况导致broker端接受不到响应的ack会造成重复消费。

消息的ACK确认机制默认是打开的,消息如未被进行ACK的消息确认机制,这条消息被锁定Unacked

手动确认需要打开配置

spring:
  rabbitmq:
    #开启手动确认消息,如果消息重新入队,进行重试
    listener:
      simple:
        acknowledge-mode: manual
                //false表示是否多条确认
        channel.basicAck(msgTag,false);
        //一条消息的确认,最后的参数false表示是否重新入队
        channel.basicNack(msgTag,false,false);
        //多条消息确认是否入队
        channel.basicReject(msgTag,false);

deliveryTag介绍: 表示消息投递序号,每次消费消息或者消息重新投递后, deliveryTag都会增加

basicReject:一次只能拒绝接收一个消息,可以设置是否requeue。

basicNack:方法可以支持一次0个或多个消息的拒收,可以设置是否requeue。

如果人工审核异常消息,通过设置重试阈值,超过后确认消费成功,记录消息,人工处理

八、集群介绍

**节点通信:**集群需要保证各个节点有相同的token令牌,防止非法节点进入盗取信息

erlang.cookie是erlang的分布式token文件,集群内各个节点的erlang.cookie需要相同,才可以互相通信

九、普通集群

默认的集群模式, 比如有节点 node1和node2、node3,三个节点是普通集群,但是他们仅有相同的元数据,即交换机、队列的结构;

发送或者消费消息的时候,会根据集群的规则进行存储,如轮训策略等。

存储介绍:

当队列消息发送过来,存放在了node1上,如果消费者消费的时候是进入到了node1节点获取,则可以直接消费,如果消费者消费的时候进入到的是其它节点,其它节点会把 queue 中的消息从node1中取出, 并经过连接节点转发后再发送给消费者。

问题:

当node1节点发生故障的时候,消息无法被立即消费,不能实现高可用。如果node1做了持久化,等node1进行数据恢复以后才能正常消费;如果node1没有进行持久化,node1的数据就会丢失。

应用场景:

该模式更适合于消息无需持久化的场景,如日志传输的队列

十、镜像集群

队列做成镜像队列,让各队列存在于多个节点中和普通集群比较大的区别就是【队列queue的消息message 】会在集群各节点之间同步,且并不是在 consumer 获取数据时临时拉取, 而普通集群则是临时从存储的节点里面拉取对应的数据

优点:

  • 实现了高可用性,部分节点挂掉后,不影响正常的消费

  • 可以保证100%消息不丢失,推荐3个奇数节点,结合LVS+Keepalive进行IP漂移,防止单点故障

缺点:

由于镜像队列模式下,消息数量过多,大量的消息同步也会加大网络带宽开销,适合高可用要求比较高的项目过多节点的话,性能则更加受影响