RabbitMQ 概念理解

概念模型:

消息模型

  所有的 MQ 产品从模型抽象上来说都是一样的过程:

  消费者(consumer) 订阅某个队列。 生产者(producer) 创建消息,然后发布到队列(queue) 中, 最后将消息发送到监听的消费者。

RabbitMQ 基本概念

 

 

  1、Message

    消息,消息是不具名的,它由消息头和消息体组成。 消息体是不透明的,而消息头则由一系列的可选属性组成,包括routing-key(路由健)、 priority(相对于其他消息的优先权)、      delivery-mode(指出该消息是否需要持久性存储)

  2、Publisher

    消息的生产者,也是一个向交换器发布消息的客户端应用程序

  3、Exchange

    交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列,只能转发,不具备存储消息的能力。

  4、Binding

    绑定,用于消息队列和交换器质检的关联。 一个绑定就是基于路由键(routing key) 将交换器和消息队列连接起来的路由规则, 所以可以将交换器理解成一个由绑定构成的路由表。

    Routing key :一个路由规则,虚拟机可以用它来确定如何路由一个特定消息

  5、Queue

    消息队列,用来保存消息直到发送给消费者。 它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者链接到这个队列将其取走

  6、Connection

    网络连接,比如一个TCP链接

  7、Channel

    信道, 多路复用链接中的一条独立的双向数据流通道。 信道是建立在真实的TCP链接内的虚拟逻辑链接,AMQP 命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,几乎所有的操作,这些动作都是通过信道完成。如果应用程序支持多线程,通常每个thread 创建单独的channel 进行通讯,AMQP method 包含了channel id 帮助客户端和message broker 识别channel, 所以channel 指甲钳时完全隔离的。因为对于操作系统来说建立和销毁TCP都是非常昂贵的开销,所以引入了信道的概念,以复用一条TCP链接

  8、Consumer

    消息的消费者,表示一个从消息队列中取得消息的客户端应用程序

  9、Virtual Host

    虚拟主机,表示一批交换机、消息队列和相关对象。 虚拟主机是共享相同的身份认证和加密环境的独立服务器域。 每个vhost 本质就是一个mini版的RabbitMQ服务器,拥有自己的队列、交换器、绑定和权限机制。 vhost 是AMQP概念的基础,必须在连接时指定, RabbitMQ 默认的vhost 是 /。

  10、 Broker

    表示消息队列服务器实体。

AMQP 中的消息路由

  生产者把消息发布到Exchange上, 消息最终到达队列并被消费者接收,而binding 决定交换器的消息应该发送到哪个队列。

  

 

 exchange 类型

  Exchange 分发消息是根据类型的不同分发策略有区别,目前有四种类型: direct、fanout、topic、headers。 headers 匹配 AMQP 消息的header 而不是路由健,此外 headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了。

  1、direct

    消息中的路由健(routing key) 如果和 Binding 中的 binding key 一致, 交换器就将消息发到对应的队列中。 路由健与队列名完全匹配,如果一个队列绑定到交换机要求路由健为“dog", 则只转发routing key 标记为“dog" 的消息,不会转发"dog.keggy",也不会转发"dog.hasiky"等。 它是完全匹配、单播的模式。

  2、fanout

    每个发到fanout类型交换器的消息都会分道所有绑定的队列上去。fanout 交换器不处理路由健,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定到所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。 fanout 类型转发消息是最快的。

  3、topic

    topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配, 此时队列需要绑定到一个模式上。它将路由键和绑定键的自付切分成单词,这些单词之间用点隔开。它同样也会识别两个通配符: “#”  和 “*”。 “#” 匹配0个或者多个单词,“*” 匹配不多不少一个单词

 

RabbitMQ 集群

  RabbitMQ 最优秀的功能之一是内建集群,这个功能设计的目的是允许消费者和生产者在节点崩溃的情况下继续运行,以及通过添加更多的节点来线性扩展消息通信吞吐量。RabbitMQ 内部利用 Erlang 提供的分布式通信框架 OTP 来满足上述需求,使客户端在失去一个 RabbitMQ 节点连接的情况下,还能够重新连接到集群中的任何其他节点继续生产、消费消息。

RabbitMQ 集群中的一些概念

  RabbitMQ 会始终记录以下四种类型的内部元数据:

  1、队列元数据

    包括队列名称和他们的属性,比如是否可持久化,是否自动删除

  2、交换器元数据

    交换器名称、类型、属性

  3、绑定元数据‘

    内部是一张表格记录如何将消息路由到队列

  4、vhost 元数据

    为vhost 内部的队列、交换器、绑定提供命名空间和安全属性

  在单一节点中,RabbitMQ 会将所有这额信息存储在内存中,同时将标记为可持久化的队列、交换器、绑定存储到硬盘上。存储到硬盘上可以确保队列和交换器在节点重启后能够重建。而在集群模式下也同样提供两种选择: 存到硬盘上(独立节点的默认配置), 存在内存中。

  如果在集群中创建队列,集群只会在单个节点而不是所有节点上创建完整的队列信息(元数据、状态、内容)。结果是只有队列的所有者节点知道有关队列的所有信息,因此当集群节点崩溃时,该节点的队列和绑定就消失了,并且任何匹配该队列的绑定的新消息也丢失了。还好RabbitMQ 2.6.0 之后提供了镜像队列以避免集群节点故障导致的队列内容不可用。

  RabbitMQ 集群中可以共享 user、vhost、exchange 等,所有的数据和状态都是必须在所有节点上复制的,里外就是上面所说的消息队列。 RabbitMQ 节点可以动态的加入到集群中。

  当在集群中声明队列、交换器、绑定的时候,这些操作会直到所有集群节点都成功提交元数据变更后才返回。集群中有内存节点和磁盘节点两种类型,内存节点虽然不写入磁盘,但是他的执行比磁盘节点要好。 内存节点可以提供出色的性能,磁盘节点能保障配置信息在节点重启后仍然可用,那集群中如何平衡这两者呢?

  RabbitMQ 只要求集群中至少有一个磁盘节点,所有其他节点可以是内存节点,当节点加入火离开集群时,他们必须要将该变更通知到至少一个磁盘节点。如果只有一个磁盘节点,刚好又是该节点崩溃了,那么集群可以继续路由消息,但不能创建队列、创建交换器、创建绑定、添加用户、更改权限、添加或删除集群节点。 也就是说集群中唯一磁盘节点崩溃的话,集群仍然可以运行,但直到该节点恢复,否则无法更改任何东西。

  

消息确认机制

  消息一旦被消费者接收,队列中的消息就会被删除,如果消费者收到了消息却还没执行就挂了,rabbitmq 却不知道,这个消息就丢失了。 所以RabbitMQ 有一个ACK 机制,当消费者获取消息后,会向 RabbitMQ 发送回执ACK, 告知消息已经被接收。

  回执ACK 分两种情况:

    自动ACK: 消息一旦被接收,消费者自动发送ACK【场景:消息不太重要】

    手动ACK: 消息接收后,不会发送ACK, 需要手动调用 【场景:消息很重要】

 

如何避免消息堆积

  消息的发送速率远远大于消息消费速率的时候会造成消息堆积。

  采用workqueue,多个消费者监听同一队列。

  接收到消息以后,可以通过线程池,进行异步消费。

  .....

  根据实际情况 优化消费者处理速度、根据消息重要程度、事前规避、事中解决等情况采用不同的方案

 

订阅模型的特点

  可以有多个消费者

  每个消费者有自己的 queue (队列)

  每个队列都要绑定到Exchage (交换机)

  生产者发送到消息,只能发送到交换机,交换机来决定要发给哪个队列,生产者无法决定

  交换机把消息发送给绑定过的所有队列

  队列的消费者都能拿到消息。实现一条消息被多个消费者消费

订阅模型-Fanout(广播模式)

  

  在这种订阅模式中,生产者发布消息,所有消费者都可以获取所有消息。

订阅模型-Direct(路由模式)

  在这汇总给你订阅模式中,生产者发布消息,消费者有选择性的接收消息。队列与交换机的绑定,不能是任意绑定了,而是需要制定一个RoutingKey(路由key)。消息的发送方再向Exchagne 发送消息是,也必须指定消息的 routing key。

订阅模型-Topic(通配符模式)

 

  Topic 类型的Exchange 与 Direct相比,都是可以根据 RoutingKey 把消息路由到不同的队列,只不过 Topic 类型 Exchange 可以让队列在绑定 RoutingKey 的时候使用通配符。

  RoutingKey 一般都是有一个或多个单词组成,多个单词之间以 "." 分割 。

 

如何避免消息丢失?

  消费者的ACK机制

    ACK机制可以防止消费者丢失信息,但是无法仿制MQ 丢失信息,解决办法就是对消息进行持久化  

  消息进行持久化

    将消息持久化,前提是: 队列、Exchange 都持久化

    

 

参考抄录:https://www.jianshu.com/p/79ca08116d57/

      https://mp.weixin.qq.com/s?__biz=MzIxOTc2MjUyNw==&mid=2247485485&idx=1&sn=b6c7450fabb8b7ae18e618ff8634e8bc&chksm=97d7121da0a09b0b76bf51d2bbf8547a198604f6322b7e3914a9c863e05f1c61a16edf90f108&scene=21#wechat_redirect

posted @ 2022-01-13 15:39  长弓射大狗  阅读(158)  评论(0)    收藏  举报