RabbitMQ面试题总结

425 阅读11分钟

MQ是什么

MQ (message queue)消息队列

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

什么是队列

是一种数据结构,遵守先进先出原则

MQ的优势

  • 异步通信

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

  • 业务解耦

    将原有一个模块直接调用另外一个模块,优化成,把请求给到MQ,MQ会主动推送给其他模块,

  • 流量削峰

    当某一时间大量的流量打到服务器上,服务器一时间无法承受,会宕机,这个时候可以用MQ进行削峰处理,请求都是消息队列里面出来,泽能够包装这种大流量的情况下,服务器仍然能够有序的稳定的处理请求。

MQ有什么劣势

  • 系统可用性降低,对外部有依赖了
  • 需要考虑效率丢失,重复消费的情况
  • 需要保证消息的顺序性,一致性

常用的MQ性能对比

ActiveMQRabbitMQRocketMQKafka
开发语言javaerlangjavascala
单机吞吐量万级万级十万级十万级
时效性msusmsms以内
可用性高 主从架构高主从架构非常高 分布式架构非常高 分布式架构
消息可靠性较低概率丢失基本不丢可以做到基本不丢可以做到基本不丢
功能支持支持功能全性能好 延迟低 并发能力强MQ功能完善 支持分布式,扩展性好主要用于大数据的日志采集

MQ如何避免消息堆积

  • 提高消费者的速率
  • 消费者批量获取消息进行消费

MQ如何避免重复消费

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

MQ如何保证消息不丢失

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

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

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

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

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

MQ有哪些消费模式

  • 推模式注册一个消费者后,RabbitMQ会在消息可用时,自动将消息镜像推送给消费者,这种方式效率最高最及时
  • 拉模式属于一种轮询模型,发送一次get请求,获得一个消息,如果此时RabbitMQ中没有消息,会获得一个表示空的回复。
  • 自动确认 消费者消费消息的时候,将自动向RabbitMQ确认
  • 手动确认 消费者消费消息的时候手动调用相应函数进行确认
  • pos预取模式 在确认纤细被接受之前,消费者可以预先接受一定数量的消息。在处理完一定数量的消息后,批量进行确认,当然,如果消费者应用程序在确认消息之前崩溃,则所有为确认的消息将被重新发送给其他消费者

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

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

一旦TCP 连接建立起来,客户端紧接着可以创建一个AMQP通道(channel),每个通道会被指派一个唯一的id,通道的建立是在connection 之上的虚拟连接,多个信道服用一个TCP 连接,可以减少性能开销,同时也便于管理,因为一个应用需要向RabbitMQ 中生成消费消息的话,都要建一个TCP连接,TCP连接开销非常大,如果遇到使用高峰,性能也会下降。

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

image-20210803155647926

当每个通道流量不是很大是,复用单一的connection 可以产生性能瓶颈的情况下有效的节省TCP连接资源,信道本身流量很大时,这个时候多个信道复用一个connection 就会产生瓶颈,是整体的流量被限制,此时会开辟多个connection 将这些信道均摊到这些connection中

RabbitMQ的作用

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

为什么选择RabbitMQ

市面上有什么消息队列为什么选择

  • rabbitmq是唯一实现了AMQP标准的消息服务器
  • 可靠性,支持持久化,保证了消息的稳定性
  • 高并发,rabbitmq是用的erlang语言开发的,erlang 是为电话交换机开发的语言,天生自带高并发光环和高可用特性
  • 集群是简单
  • 社区活跃度高

RabbitMQ的特点是什么

  • 可靠 rabbitmq使用如持久化,传输确认及发布确认等机制来保证可靠性
  • 灵活的路由 通过交换机来路由消息 对于典型的路由功能,rabbitmq已经提供了一些内置的交换机来实现。针对复杂的路由功能,可以将多个交换器绑定在一起。可以通过插件来实现
  • 扩展性 多rabbitmq节点可以组成一个集群,也可以根据实际业务情况动态的扩展集群中的节点
  • 高可用性 队列可以在集群中的机器上设置镜像,使得在部分节点出现问题的情况下附列仍然可用
  • 支持的协议多 rabbitmq除了支持AMQP协议,还支持STOMP,MQTT等多种消息中间件协议
  • 多语言客户端 几乎支持所有常用的语言 go、java、Python、PHP、.net等
  • web管理界面 提供了一个易用的用户界面,是的用户可以监控和管理消息,集群中的节点等
  • 命令插件机制 rabbitmq提供了很多插件,以实现从多方面进行扩展,当然也可以自己编写自己的插件

生产者producer和消费者consumer有哪些知识点?

生产者

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

消费者

  • 消费消息,接受消息
  • 消费者连接到rabbitmq服务器,并订阅到队列 消费消息时只消费消息体,丢弃标签

RabbitMQ消息持久化中的坑

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

那就是做持久化,持久化需要满足3个条件可以回复rabbitmq 的数据

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

持久化的工作原理

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

持久化的优缺点

  • 优点:数据持久化,数据不丢失
  • 缺点:对性能有影响,写入硬盘比内存性能低,从而降低服务的吞吐量

rabbitmq的ack应答机制

ack应答分为手动和自动

  • 如果消息不重要,丢失也没有关系,那么自动ack会比较方便
  • 如果消息非常重要,不容丢失,那个最好在完成消费之后手动ack,否则如果业务处理失败消息也会丢失

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 里进行消息同步