消息队列 - RabbitMQ - 拓展

1. Message 状态

Message 在投递时,如果当前 Queue 没有 Message,且有 Consumer 已经订阅了这个 Queue,那么该 Message 会直接发送给 Consumer,不会经过 Queue 存储 Message 的这一步

当 Message 无法直接投递给 Consumer 时,Message 会存储在 Queue 中;在 RabbitMQ 中,Queue 中存储的 Message 有4种状态,且 Message 随着系统的变化而不断更新自己的状态


四种状态:

  • alpha:消息索引和消息内容都存在内存中
  • beta:消息索引存内存,消息内存存磁盘
  • gama:消息索引内存和磁盘都有,消息内容存磁盘
  • delta:消息索引和内容都存磁盘

alpha 状态:由于所有的东西都保存在内存中,所以这种状态下最消耗内存
delta 状态:由于所有的东西都保存在磁盘中,也就意味着在读取消息时,每次都要进行 I/O 操作;在这种状态下,最消耗 CPU 中的资源
gama 状态:只有持久化消息才会有该种状态

RabbitMQ 会根据负载和 Message 传递的速度,定期的计算在内存中可以存放 Message 的最大数量,当 alpha 状态的 Message 超过计算的最大数量时,就会引起状态的变化

2. 惰性队列

2.1 简介

惰性队列尽可能地将消息存入磁盘中,并在消费者消费到相应的消息的时候才会被加载到内存中

默认情况下,当 Producer 将 Message 发送到 RabbitMQ 的时候,Queue 中的 Message 会尽可能地存在内存中,这样可以更快的将 Message 发送给 Consumer,即便是持久化消息也会在内存中保持一个副本
而当 RabbitMQ 所占用的内存超过限额时,就需要释放内存,此时会将内存中保存的 Message 写到磁盘中;在这个过程中,队列将无法接收到新的消息

而对于惰性队列来说,接收到 Message 之后,会直接将其写入磁盘中,不管此条 Message 是持久化还是非持久化。在使用惰性队列时,会降低内存的消耗,但是不可避免的是频繁的 I/O 操作
但是要注意的是,惰性队列如果存储非持久化的消息,重启后会丢失

当 Message 是持久化消息时,更适合惰性队列
也适合于消费者不能正常消费 还能保证消息接收的吞吐量的场景

2.2 与普通队列对比

普通队列占用内存较多,惰性队列占用内存较少

当对于相同的大量消息来对比的话,惰性队列的耗时会比普通队列的要少。因为普通队列当消息过多的存储在内存中时,会触发将消息写入磁盘的动作。上面有提到,当内存不足,消息写入磁盘时,队列会阻塞

3. 警告和流控

当内存占用超过配置的值或磁盘剩余空间低于配置的值时,RabbitMQ 会暂时阻塞所有 Producer 的连接,并停止接收 Producer 发来的消息,以免服务崩溃。与此同时客户端与服务端的心跳检测也会失效


心跳检测:用来检测通信的对端是否存活
当客户端与 RabbitMQ 之间一段时间没有进行交互,那么服务器将会自动断开与客户端之间的 TCP 连接;心跳检测就是用于检测当前的 TCP 连接是否还在进行交互
其原理是,向客户端发送一个心跳检测包,如果在一段时间内没有回应的话,那么就会断掉本次的 TCP 链接


心跳检测实际上是启用两个进程,分别检测两种情况:

  • 定时检测 TCP 连接上是否有数据发送
    如果在一段时间内没有数据发送给客户端,则会发送一个心跳包给客户端,然后循环进行下一次检测
  • 定时检测 TCP 连接上是否有数据接收
    如果一段时间内没有收到任何数据,则判定为心跳超时,最终会关闭 TCP 连接

3.1 内存警告

在默认情况下,当内存低于40%的时候,RabbitMQ 中的所有 Producer 就会停止发送消息,然后触发将内存中的消息写进磁盘的动作,从而释放内存空间

3.2 磁盘警告

默认情况下,当磁盘剩余空间低于50M的时候,RabbitMQ 会阻塞所有的 Producer ,同时停止将内存中的消息写进磁盘的操作

磁盘空间的检查频率并不是固定的,他会随着上一次的检查结果而变化
当检测到上一次的剩余空间接近临界值时,那么检查的频率会加快,反之

3.3 流量控制

上面的内存警告和磁盘警告中,当低于阈值时发生的动作是针对所有的 Connection 做出的处理;而流量控制是针对单个 Connection

流量控制用来避免消息发送过快而导致服务器难以处理的情况


Connection 在 RabbitMQ 中存在5种状态:

  • running:运行中
  • flow:流控
  • idle:空闲
  • blocked:阻塞
  • unblocked:未阻塞

当 Connection 的状态为 flow 时,意味着 Connection 的状态在 blocked 和 unblocked 中来回切换
flow 状态其实和 running 状态较大的区别其实只有他们的发送效率

4. 镜像(Mirror)队列

4.1 背景

在现在的高并发场景中,队列一般都是以集群的方式来部署的;但是如果集群中只存在一个 Broker 节点的话,该节点一旦失效,将会导致整体服务也不可用,且会造成消息的丢失

此时应该会有人想到,如果消息都是持久化的消息,是不是当节点失效时,也不会导致消息的丢失呢?
其实不是的,的确是可以将消息设置为可持久化消息,但是在上一篇关于 RabbitMQ 的文章有说过,写入文件的操作不是立刻执行的,具体的触发条件在上一篇文章已经说过,此处不再赘述。在消息发送之后,接着写入磁盘会有一定的时间间隔,我们称其为“时间窗”。如果在这个时间窗内节点发送故障,那么也会导致消息的丢失

所以引入镜像队列,将队列镜像到其他节点上。此时如果集群中一个节点不可用之后,队列会自动切换到另一个镜像队列上,保证服务的可用

在镜像队列的使用中,对每一个配置了镜像的队列都会包含一个主节点(master)和多个从节点(slave)

4.2 工作原理

当消息发送到配置了镜像的队列时,消息会同时往自己的 slave 节点进行同步
如果因为某些原因,master 变成不可用,但是因为消息同步给了 slave ,所以消息并不会丢失,只需等待其中的一个 slave 节点被推举为 master 之后,服务将会重新变成可用

推举的规则也很简单,哪一个 slave 存在的时间最长,那么就会推举他为新的 master

配置了镜像的队列,其发布确认机制也会和普通的队列不同。镜像队列要所有的节点都发送了确认消息之后,才真正的算“确认”

要注意的是,虽然是配置了 slave ,但是平常的所有读写工作,也都是由 master 来完成,slave 只做一个备份数据的工作。哪怕是有 TCP 与 slave 建立了链接,slave 也不会直接对其进行处理,而是将请求做一个转发的动作,让 master 来完成本次链接的请求

如果在一个已存在的镜像队列中添加一个新的节点,默认情况下,新的节点不会接收到数据的同步
除非服务器显示的调用同步数据的命令,那么此时所有的队列都会进入阻塞状态,等待数据同步完给新的节点时,才会恢复正常

在镜像队列启动的时候,也是 master 先启动;如果是 slave 先启动的话,slave 会进入等待状态,如果在指定时间内发现 master 没有启动,那么已经启动的 slave 会自动停止。这个原理只要大家玩过集群,我想应该都会知道的

4.3 宕机原理

当 slave 挂掉之后,与该 slave 相连的客户端全部断开之外,不会有其他的影响


当 master 挂掉之后,会进行如下动作:

  • 与 master 的全部客户端断开
  • 选举存活时间最长的 slave 作为新的 master,如果此时 slave 未同步,那么未同步的消息会丢失
  • 新的 master 重新入队所有未确认的消息,因为可能 master 未能同步已确认的消息,所以有些消息会被重复消费

4.4 架构图

在这里插入图片描述

5. 仲裁(Quorum)队列

5.1 背景

RabbitMQ 3.8 版本中的重要特性
在 3.8 版本之前,实现高可用队列的方式只有上面的镜像队列

镜像队列其实解决的问题是:消息同步,其实实现的过程,简单的说就是将消息从 master 复制一份去 slave

但是有没有想过一个问题:一个节点宕机,然后一段时间之后,该节点重新上线,重新上线的节点以前的所有数据都会丢失;此时会面临一个问题,我们要不要将数据重新同步到该队列中?
如果同步的话,同步的过程中,所有的队列都会处于阻塞状态,此时就会堆积大量的消息
如果不同步的话,仅仅让新的消息复制到这个重新上线的队列中,老的消息不进行同步;那么当现在的 master 宕机之后,该队列没有同步所有的消息,会增加消息丢失的风险

而仲裁队列的出现,旨在解决镜像队列之间的性能和同步问题

5.2 工作原理

每个仲裁队列都有多个副本,其中包含一个主副本和多个从副本
每个副本都在不同的 RabbitMQ 节点上

和镜像队列一样,生产者和消费者都只会和主副本进行交互,从副本仅仅作为一个数据的备份
在主副本所在的节点宕机后,在另外节点的从副本才会被选举为新的主副本,然后继续提供服务

之所以叫做仲裁队列,是因为消息的同步和主副本的选举,都要超过半数的副本同意
当生产者发送一条消息的时候,要超过半数的副本将消息写入磁盘以后,才会向生产者发送确认信号;这也意味着,有些比较慢的副本不会影响整个队列的速度

为什么说仲裁队列解决了镜像队列的同步问题?
细心的人应该有看见,副本是将消息写入磁盘的,也就是说,仲裁队列中的消息都是持久化的;当节点重新上线时,直接从上次中断的地方开始在磁盘中复制消息,且复制的过程是非阻塞的。而镜像队列中的消息因为不全是持久化的消息,所以才会出现不同步的问题

要注意的是,如果超过半数的副本丢失,那么队列的数据就代表永久丢失;虽然还存在一些副本,但是队列是没有办法恢复的,只能被强制删除

5.3 带来的问题

5.3.1 磁盘使用

如果有一条消息是要投递到多个队列中,比如使用的交换机的主题交换机或扇形交换机:

普通的队列只会将消息在磁盘中存储一次,其他的队列只会保存这条消息的引用;也就是说,只会对磁盘进行一次写入操作
而在仲裁队列中,每个副本都会将这条消息写入磁盘;也就是说,有多少个副本,就会对磁盘进行多少次的写入操作

所以,在仲裁队列的使用中,要注意磁盘的写入次数,因为 IO 的操作是很消耗性能的
在这个例子中,也可以看出,仲裁队列并不适合与扇形交换机一起使用

5.3.2 内存使用

仲裁队列中的消息虽然都是持久化的,但是所有的消息也会一直保存在内存中
如果不及时的进行消费,内存会一直处于负荷状态,可能会导致生产者停止工作

6. 死信(Dead-Letter)队列

6.1 简介

“死信”:其实也是消息的一种,只不过满足了一些条件之后的一种称呼

消息变成死信,有如下三种情况:

  • 消息被拒绝消费
  • 消息过期
  • 队列达到了最大长度

当消息满足上面的三种条件的其中一种之后,消息就会被定义成“死信”,然后被重新发送到另一个交换机中,这个交换机也被叫做“死信交换机(DLX)”,用于绑定的队列,也被称之为“死信队列
DLX 与其他正常的交换机没有什么区别,只是用于存放一些 “死信“

其设计目的是为了存储没有被正常消费的消息,便于排查和重新投递

6.2 架构图

在这里插入图片描述

7. 延时(Delay)队列

7.1 简介

延时队列存储的是延时消息

不是所有的消息在发送之后,都需要立刻被消费的,要看具体的使用场景
举个很常见的例子:淘宝下单,大家应该都有那种下单之后,但是没有支付,然后跳转到另一个界面;界面里有个倒计时,显示请在多少分钟内完成支付
这其实就是一种延时处理消息的例子

当向延时队列添加元素的时候,会给元素设置上一个延迟时间(Delay)
队列会根据延迟时间作为排序条件,较小的元素会优先放在队列的首部
队列中的元素只有到了设置的延迟时间,才允许从队列中取出

7.2 架构图

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
RabbitMQ交换机的扩展参数用于扩展AMQP协议的定制化使用。 所谓扩展参数,指的是在交换机属性中的Arguments字段,它可以接受一些额外的参数来自定义交换机的行为。这些参数可以根据具体的需求来设置,例如根据业务逻辑定制化消息的路由规则、过滤消息、设置优先级等。扩展参数的具体使用方式可以参考AMQP协议的相关文档。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [RabbitMQ交换机详解](https://blog.csdn.net/a1034996/article/details/106520394)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [RabbitMQ学习记录(八)-交换机](https://blog.csdn.net/cuierdan/article/details/124147813)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [1.6 RabbitMQ-Exchange内容详解](https://download.csdn.net/download/weixin_38564826/14035505)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

LF3_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值