RabbitMQ

RabbitMq笔记
 
使用rabbitMQ的好处
1. 解耦
2. 异步
3. 削峰
 

 
RabbitMQ中的broker是 指什么?cluster又是指什么?
broker是指一个或多个 erlang node 的逻辑分组, 且 node上 运行着RabbitMQ应用程序。cluster是在broker的基础上,增加了node之间共享元数据的约束。
 

 
RabbitMQ概念里 channel、exchange和queue是逻辑概念,还是对应着进程实体?分别起什么作用?
queue具有自己的erlang进程;
exchange内部实现为 保存binding关系的查找表;
channel是实际进行路由工作的实体,即负责按照routing_key将message投递给queue
由AMPQP协议描述可知, channel是真实的TCP连接之上的虚拟连接,所有 AMQP命令都是 通过chhannel发送的,且每一个channel有 唯一的ID。一个cchannel只能被单独一个操作系统使用,故投递到特定channel上的message是有序的。但是一个操作系统上允许使用多个channel。
 

 
vhost是什么?起什么作用?
vhost可以理解为虚拟broker, 即mini-RabbitMQ server。其内部均含有独立的 queue、exchange和binding等,但最重要的是,其拥有 独立的权限系统,可以做到vhost范围的用户控制。当然,RabbitMQ的全局角度,host可以作为不同权限 隔离的手段(一个典型的例子就是不同的 应用可以跑在不同的vhost中)。
 

 
RabbitMQ消息 基于 什么传输?
由于TCP连接的创建和销毁开销较大,且并发数 受系统资源限制,会造成性能瓶颈。RabbitMQ使用信道的方式来传输数据。信道是建立在真实的TCP连接内的虚拟连接,且每条TCP连接上的信道数量没有限制。
 

 
消息如何分发?
若该队列至少有一个消费者订阅,消息将以循环(round-robin)的方式发送给消费者。每条消息只会发给一个订阅的消费者(前提是消费者能够正常处理消息并确认)。
 

 
消息怎么路由?
从 概念上来说,消息路由必须有 三部分:交换器、路由、帮i的那个。生产者把消息发布到交换器上;绑定决定了消息如何从路由器路由到特定的队列;消息最终到达队列,并被消费者接收。
1.消息发布到交换器时,消息将 拥有一个 路由键(routing-key),在消息创建时设定。
2.通过队列路由键,可以把队列绑定到交换器上。
3.消息到达交换器后,RabbitMQ会将消息的路由键与队列的路由键进行匹配(针对不同的交换器 有不同的路由规则)。如果能匹配到队列,则消息会投递到相对应队列中;如果不能匹配到任何队列,消息将进入“黑洞 ”。
 
常用的交换器主要为以下三种:
1.direct:如果路由键完全匹配,消息就被投递到相应的队列
2.fanout:如果交换器收到消息,将会广播到所有绑定的队列上
3.topic:可以使来自不同源头的消息能够到达 同一个队列。使用topic交换器时,可以使用 通配符,例如:“ * ” 匹配特定位置的任意文本,“ . ” 把路由键分成了几部分, “ # ” 匹配所有规则等。 特别注意: 发往topic交换器的消息不能随意的设置选择键(routing_key),必须是由 “ . ” 隔开的一系列标识符组成。
 

 
什么是元数据?元数据分为哪些类型?包括哪些内容?与cluster相关的元数据 有哪些?元数据是如何保存的?元数据在cluster中是如何分布的?
在非cluster模式下,元数据主要分为
Queue元数据(queue名字和属性等)
Exchange元数据(exchange名字、类型和属性)
Binding元数据(存放路由关系的查找表)
Vhost元数据(vhost范围内针对前三者名字空间约束和安全属性设置)
 
在cluster模式下还包括cluster中node位置信息和node关系信息。元数据按照erlang node的类型 确定是仅保存于RAM中、还是下图 所示queue的元数据在单node和cluster两种模式下的分布图。

 

 

 
在单 node系统和多node构成的cluster系统中声明queue、exchange,以及进行binding会有什么不同吗?
当在单node上生命queue时,只要该node上相关元数据 进行了变更,就可以得到Queue.Declare-ok 回应;
而在cluster声明queue,则要求cluster上的全部node 都要进行元数据成功更新,才会得到 Queue.Declaer-ok回应。
另外,若node 类型为RAM node 则变更的数据仅保存在内存中 ,若类型为 disk node 则还要变更保存在系统上的数据。
 

 
死信队列&死信交换器
DLX全称(Dead-Letter-Exchange),称之为死信交换器, 当消息变成一个死信之后,如果这个消息所在的队列存在x-dead-letter-exchange 参数,那么它将会被发送到x-dead-letter-exchange对应值的交换器上,这个交换器就称之为死信交换器,与这个死信交换器绑定的队列就是死信队列。
 

 
如何确保消息正确地发送至RabbitMQ
RabbitMQ使用发送方 确认模式,确保消息正确的发送到RabbitMQ。发送方确认模式:将信道设置成confirm模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的ID。一旦消息被投递到目标队列后,或者消息被写入磁盘后(可持久化的消息),信道 将会 发送一个确认给生产者(包含消息唯一ID)。如果RabbitMQ发生内部错误从而导致消息丢失,会发送一条nack(not acknowledged,未确认)消息。发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。当确认消息到达生产者应用程序,生产者应用程序的回调方法就会被触发来处理消息。
 

 
如何确保消息接收方消费了消息?
接收方消息确认机制:消费者接收到每一条消息后都必须进行确认(消息接收 和消息确认 是两个不通操作)。只有消费者确认了消息,RabbitMQ才能安全的把消息从队列中删除。这里并没有用到超时机制,RabbitMQ仅通过Consumer的连接中断来确认是否需要从新发送消息。也就是说,只要连接不中断,RabbitMQ给了Consumer足够长的时间来处理消息
下面罗列几种特殊情况:
如果消费者接收到消息,再确认之前断开了连接或取消订阅,RabbitMQ会认为消息没有被 分发,然后重新分发给下一个订阅的消费者(可能存在消息重复消费的隐患,需要根据bizId去重)。
 

 
 
如何解决丢数据的问题?
 
生产者丢数据
RabbitMQ提供了 transaction 和 confirm 模式 来确保生产者 不丢消息
transaction 事务机制,发送消息前开启事务,发送消息,如果发送过程中出现什么异常,事务就会 回滚,如果发送成功则 提交事务。
缺点吞吐量下降了。因此,生产上用confirm模式的居多。一旦 channel进入confirm模式,所有在 该信道上面 发布的消息将会被指派一个ID(从1开始),一旦消息被投递到所有匹配的队列之后,RabbitMQ就会发送一个Ack给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了,如果RabbitMQ没有处理改消息,则会发送一个Nack消息给生产者
 
消息队列丢数据
处理消息队列 丢数据的情况一般是开启持久化磁盘配置。 这个持久化配置可以和confirm机制配合使用,可以在消息持久化磁盘后,再给生产者发送一个Ack信号。这样,如果消息持久化磁盘之前,RabbitMQ宕机了,那么生产者收不到Ack信号,生产者会自动重发。
将queue的持久化标识 durable设置为 true,则代表是一个持久化的队列
发送消息的 时候将deliveryMode=2
这样设置后,rabbitMQ就算宕机了,重启后也恢复数据。在消息还没有持久化硬盘时,可能 服务 已经 死掉了,这种情况可以通过引用 mirrored-queue即镜像队列 ,但是也不能保证消息百分之百不丢失(整个集群宕机)
 
消费者丢数据
启用 手动确认模式解决这个问题
自动确认模式,消费者挂掉 ,待Ack的消息回归到队列中。消费者抛出异常,消息会不断地被重发,直到处理成功。不会丢失消息,即便服务挂掉,没有处理完成的消息会重回队列,但是异常会让消息不断的重试。
手动确认模式,如果消费者来不及处理就死掉时,没有相应Ack时会重发送一条消息给其他消费者;如果监听程序异常了,且未对异常进行捕获,会一直重复接收消息,然后一直抛出异常;如果对异常进行了捕获,但是没有在finally里Ack,也会一直 重复发送消息(重试机制)。
不确认模式,acknowledge=“none” 不使用确认机制,只要消息发送完成就会立即在队列移除,无论客户端异常还是断开,只要发送完就 移除,不会 重发。
 

 
死信队列和延迟队列的使用
死信消息:
消息被拒(Basic.Reject或Basic.Nack)并且设置 参数为false
消息过期了
队列达到最大的长度
过期消息:
在 RabbitMQ中存在 2 种方式可设置消息的过期时间,第一种通过队列进行设置,这种设置后,该队列中所有的消息都存在相同的过期时间,第二种 通过对消息本身进行设置,那么 每条消息的过期时间都不一样。 如果同时使用这两种方法,那么过期时间小的数值为准。当消息到达 过期时间还没有被消费,那么那个消息就成了一个死信消息
 
延时队列:
在RabbitMQ中不存在延时队列但是我们可以通过设置消息的过期时间和死信队列 来模拟出延时队列。消费者监听死信交换器绑定的队列,而不要监听消息发送的队列。
 
 
 
 
posted @ 2022-11-10 16:21  茄子777  阅读(36)  评论(0编辑  收藏  举报