我们一起来学RabbitMQ 五:RabbitMQ 应知应会的面试题 | 8月更文挑战

1,876 阅读12分钟

RabbitMQ 相关问题如何解决

MQ 是什么?

MQ(Message Queue)消息队列

用队列机制来实现软件之间的通信,消费者可以到指定队列拉取消息,或者订阅相应的队列,由MQ服务端给其推送消息

什么是队列?

是一种数据结构,遵循 FIFO (先进先出)原则

凭啥要使用 MQ , MQ 有啥优势?

  • 异步通信

将以前也不中不必要的同步操作,优化成异步操作,提高性能

  • 业务解耦

将原有A模块直接调用B模块的接口,优化成,A模块的请求给到MQ,A模块的事情就做完了

MQ会主动推给B模块,或者B模块自己来拉

  • 流量削峰

当某一时间大量的流量打到服务器上,服务器一时间无法承受,会宕机

这个时候,若请求都是从消息队列里面出来,则能够保证这种大流量的情况下,服务器仍然能够有序的稳定的处理请求

MQ 有啥劣势呢?

  • 系统可用性降低,对外部有依赖了
  • 需要考虑 MQ 消息丢失,重复消费的问题
  • 需要花费精力保证消息的顺序性,一致性

常用 MQ 性能对比

ActiveMQRabbitMQRocketMQKafka
开发语言javaerlangjavascala
单机吞吐量万级万级十万级十万级
时效性ms级us级ms级ms级以内
可用性
主从架构

主从架构
非常高
分布式架构
非常高
分布式架构
消息可靠性较低概率丢失消息基本不丢可以做到基本不丢可以做到基本不丢
功能支持支持功能全性能好
延时低
并发能力强
MQ 功能较完善
支持分布式,扩展性好
主要用于大数据和日志采集

MQ 如何避免消息堆积

  • 提高消费速率(集群的方式)
  • 消费者批量获取消息进行消费

MQ 如何避免消费者重复消费(幂等性问题)

  • 全局ID(增加标志位) + 保证业务一致性

MQ 如何保证消息不丢失

  • 消息确认机制
  • 持久化
  • 消息 ACK

MQ 如何保证消息顺序一致性

  • 绑定同一个消费者和队列

MQ 推与拉取架构模型是怎么样的?

  • MQ 服务器与消费者建立长连接后,MQ 服务器会主动推数据给到消费者
  • 当消费者第一次启动的时候,会去找MQ 服务器拉数据

mq有哪些消费模式

  • 推模式 注册一个消费者后,RabbitMQ会在消息可用时,自动将消息进行推送给消费者。这种方式效率最高最及时。

  • 拉模式 属于一种轮询模型,发送一次get请求,获得一个消息。如果此时RabbitMQ中没有消息,会获得一个表示空的回复。

  • 自动确认

消费者消费消息的时候,将自动向RabbitMQ进行确认。

  • 手动确认

消费者消费消息的时候,手动调用相应函数进行ack 应答

  • qos预取模式

在确认消息被接收之前,消费者可以预先要求接收一定数量的消息,在处理完一定数量的消息后,批量进行确认

当然,如果消费者应用程序在确认消息之前崩溃,则所有未确认的消息将被重新发送给其他消费者

RabbitMQ 中既然有了connections 为什么还要有 channel

connection 是什么

connection 是 生产者或消费者与 RabbitMQ Broker 建立的连接,是一个TCP连接

一旦 TCP 连接建立起来,客户端紧接着可以创建一个 AMQP 信道(Channel),每个信道都会被指派一个唯一的 ID

信道是建立在 Connection 之上的虚拟连接,多个信道复用一个TCP连接,可以减少性能开销,同时也便于管理

因为一个应用需要向RabbitMQ 中生成或者消费消息的话,都要建一个TCP连接,TCP连接开销非常大,如果遇到使用高峰,性能瓶颈也随之显现

信道复用连接优势:

  • 复用TCP连接,减少性能开销,便于管理
  • RabbitMQ 保障每一个信道的私密性

当每个信道的流量不是很大时,复用单一的 Connection 可以在产生性能瓶颈的情况下有效地节省 TCP 连接资源

信道本身的流量很大时,这时候多个信道复用一个 Connection 就会产生性能瓶颈,进而使整体的流量被限制了,此时就需要开辟多个 Connection,将这些信道均摊到这些 Connection 中

RabbitMQ 的作用

  • 削峰填谷
  • 生产者和消费者业务解耦
  • 服务间异步通信
  • 定时任务
  • 顺序消费

为什么选择 RabbitMQ

现在的市面上有很多 MQ 可以选择,比如 ActiveMQ、ZeroMQ、Appche Qpid为什么要选择 RabbitMQ

  • 除了 Qpid,RabbitMQ 是唯一一个实现了 AMQP 标准的消息服务器
  • 可靠性,RabbitMQ 的持久化支持,保证了消息的稳定性
  • 高并发,RabbitMQ 使用了 Erlang 开发语言,Erlang 是为电话交换机开发的语言,天生自带高并发光环,和高可用特性
  • 集群部署简单,正是应为 Erlang 使得 RabbitMQ 集群部署变的超级简单
  • 社区活跃度高,根据网上资料来看,RabbitMQ 也是首选

RabbitMQ 的特点是什么?

  • 可靠

RabbitMQ 使用 如持久化、传输确认及发布确认等机制来保证可靠性

  • 灵活的路由

通过交换器来路由消息

对于典型的路由功能, RabbitMQ 己经提供了一些内置的交换器来实现

针对更复杂的路由功能,可以将多个 交换器绑定在一起,这个就需要通过插件来实现了

  • 扩展性

多个 RabbitMQ 节点可以组成一个集群,也可以根据实际业务情况动态地扩展集群中节点

  • 高可用性

队列可以在集群中的机器上设置镜像,使得在部分节点出现问题的情况下队列仍然可用

  • 支持的协议多

RabbitMQ 除了原生支持 AMQP 协议,还支持 STOMP, MQTT等多种消息中间件协议

  • 多语言客户端

RabbitMQ 几乎支持所有常用语言,比如 GO、 Java、 Python、 Ruby、 PHP等

  • WEB 管理界面

RabbitMQ 提供了一个易用的用户界面,使得用户可以监控和管理消息、集群中的节点等

  • 命令插件机制

RabbitMQ 提供了许多插件 , 以实现从多方面进行扩展,当然也可以编写自己的插件

生产者Producer和消费者Consumer 有哪些知识点?

生产者

  • 消息生产者,投递消息
  • 消息一般包含两个部分:消息体(payload)和标签(Label)

消费者

  • 消费消息,接收消息

  • 消费者连接到 RabbitMQ 服务器,并订阅到队列

    消费消息时只消费消息体,丢弃标签

RabbitMQ 消息持久化中的坑

默认情况下重启服务器会导致消息丢失,我们如何保证重启 RabbitMQ 不丢失数据?

那就是做持久化,持久化需要满足如下三个条件才可以恢复 RabbitMQ 的数据

  • 投递消息的时候 durable 设置为 true,消息持久化
  • 消息已经到达持久化交换器上
  • 消息已经到达持久化的队列上

持久化的工作原理

Rabbit 会将持久化消息写入磁盘上的持久化日志文件,等消息被消费之后,Rabbit 会把这条消息标识为等待垃圾回收

持久化的优缺点

优点

  • 数据持久化,数据不丢失

缺点

  • 对性能有影响,写硬盘比写内存性能低,从而降低服务的吞吐量

RabbitMQ ACK 应答机制

ACK 应答分为手动和自动,各有优劣

  • 如果消息不太重要,丢失也没有影响,那么自动 ACK 会比较方便

  • 如果消息非常重要,不容丢失。那么最好在消费完成后手动 ACK

    否则接收消息后就自动 ACK,RabbitMQ 就会把消息从队列中删除。若此时消费者宕机或处理业务失败,那么消息就丢失了

ACK 机制的开发注意事项

如果忘记了 ACK,那么后果很严重

当 Consumer 退出时候,Message 会一直重新分发。然后 RabbitMQ 会占用越来越多的内容,由于 RabbitMQ 会长时间运行,这个” 内存泄漏” 是致命的

为什么需要限流,消费者流量控制

  • 某一时刻,生产者在 RabbitMQ 队列中堆积了很多消息,此时有一个消费者启动,大量的消息会推送到消费者上面,这种瞬时大流量会把消费者打挂
  • 生产者和消费者效率不平衡的情况,会导致消费者端性能下降,服务端卡顿或者崩溃

RabbitMQ 的组成

  • 生产者 producer
  • 消费者 consumer
  • 交换机 exchange

用于接受、分配消息

  • 消息 message
  • 队列 queue

用于存储生产者的消息

  • 信道 channel AMQP

消息推送使用的通道

  • 连接 connections

生成者或者消费者与Rabbit 建立的TCP 连接

  • 路由键 routingKey

用于把生成者的数据分配到交换器上

  • 绑定键 BindingKey

用于把交换器的消息绑定到队列上

  • 连接管理器 ConnectionFactory

应用程序与 Rabbit 之间建立连接的管理器,程序代码中使用

  • VHost

vhost 可以理解为虚拟 broker,即虚拟机

其内部均含有独立的 queue、exchange 和 binding 等

拥有独立的权限系统,做到资源隔离,资源高效利用

RabbitMQ 的六种模式

  • single

简单的生产者生产消息,放入队列,消费者消费消息

  • work

当生产者生产消息的速度大于消费者消费的速度,就要考虑用 work 工作模式,这样能提高处理速度提高负载

work 模式与 single 模式类似, 只是work 模式比 single 模式多了一些消费者

  • publish

应用场景:简单消息队列的使用,一个生产者一个消费者

  • routing

消息生产者将消息发送给交换机按照路由判断,路由是字符串(info) 当前产生的消息携带路由字符(对象的方法),交换机根据路由的key

只能匹配上路由key对应的消息队列,对应的消费者才能消费消息

  • topic

话题模式,一个消息被多个消费者获取,消息的目标 queue 可用 BindingKey 以通配符

  • rpc

通过远程过程调用的方式实现

存储机制

  • 持久化消息

持久化的消息在到达队列时就被写入磁盘,持久化的消息也会在内存中保存一份备份,这样可以提高一定的性能,当内存吃紧的时候会从内存中清除

  • 非持久化消息

一般只保存在内存中,在内存吃紧的时候会被换入到磁盘中,以节省内存空间

RabbitMQ中消息可能有的几种状态

  • alpha

消息内容(包括消息体、属性和 headers) 和消息索引都存储在内存中

  • beta

消息内容保存在磁盘中,消息索引保存在内存中

  • gamma

消息内容保存在磁盘中,消息索引在磁盘和内存中都有

  • delta

消息内容和索引都在磁盘中

RabbitMQ 的队列结构?

  • rabbit_amqqueue_process

负责协议相关的消息处理,即接收生产者发布的消息、向消费者交付消息、处理消息的确认等

  • backing_queue

是消息存储的具体形式和引擎,并向 rabbit_amqqueue_process 提供相关的接口以供调用

交换器无法根据自身类型和路由键找到符合条件队列时,会如何处理?

我们对交换机设置参数的时候,有一个标志叫做 mandatory

  • 当mandatory标志位设置为true时

如果exchange根据自身类型和消息routingKey无法找到一个合适的queue存储消息,那么broker就会调用basic.return方法将消息返还给生产者

  • 当mandatory设置为false时

前置条件和上述保持一致,此时 broker会直接将消息丢弃

如何保证消息可靠性嘞?

  • 消息从生产者到 MQ

由事务机制,确认机制 来保障

  • MQ 自身可靠性

由持久化、集群、普通模式、镜像模式来保证

  • MQ 消息到消费者

由basicAck机制、死信队列、消息补偿等机制来保证

集群中的节点类型有哪些?

  • 内存节点

ram,将变更写入内存。

  • 磁盘节点

disc,磁盘写入操作

RabbitMQ中 要求最少有一个磁盘节点

如何保证 RabbitMQ 消息队列的高可用?

RabbitMQ中有三种模式来保证:

  • 单机模式

一般是本地启动,自己学习和测试使用,不会用在生产环境上

  • 普通集群模式

在多台机器上启动多个 RabbitMQ 实例,每个机器启动一个

  • 镜像集群模式

RabbitMQ的高可用模式

跟普通集群模式不一样的是,创建的 queue,无论元数据(元数据指 RabbitMQ 的配置数据)还是 queue 里的消息都会存在于多个实例上,

然后每次写消息到 queue 的时候,都会自动把消息到多个实例的 queue 里进行消息同步

参考资料:

RabbitMQ Tutorials

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是小魔童哪吒,欢迎点赞关注收藏,下次见~