消息队列常见面试题总结

文章目录

    • [1 消息队列有什么用 ?](#1 消息队列有什么用 ?)
    • [2 使用消息队列会带来哪些问题](#2 使用消息队列会带来哪些问题)
    • [3 如何保证 RabbitMQ 消息的顺序性?🔥](#3 如何保证 RabbitMQ 消息的顺序性?🔥)
    • [4 RabbitMQ-如何保证消息不丢失🔥](#4 RabbitMQ-如何保证消息不丢失🔥)
    • [5 RabbitMQ 消息的重复消费问题如何解决的🔥](#5 RabbitMQ 消息的重复消费问题如何解决的🔥)
    • [6 RabbitMQ 延迟队列⭐](#6 RabbitMQ 延迟队列⭐)
    • [7 RabbitMQ 消息怎么传输?](#7 RabbitMQ 消息怎么传输?)
    • [8 RabbitMQ 消息怎么路由?](#8 RabbitMQ 消息怎么路由?)
    • [9 如果有100万消息堆积在 MQ , 如何解决 ?🔥](#9 如果有100万消息堆积在 MQ , 如何解决 ?🔥)
    • [10 如何保证 RabbitMQ 高可用的?](#10 如何保证 RabbitMQ 高可用的?)
    • [11 那出现丢数据怎么解决呢?](#11 那出现丢数据怎么解决呢?)
    • [12 Kafka 高性能和高吞吐量的原因:](#12 Kafka 高性能和高吞吐量的原因:)
    • [13 常见消息队列的区别🔥](#13 常见消息队列的区别🔥)

本文作者:夏日

1 消息队列有什么用 ?

  1. 异步处理:将用户请求中的耗时操作,通过消息队列实现异步处理。将对应的消息发送到消息队列之后就立即返回结果,减少响应时间,提升用户体验。
  2. 削峰/限流:先将短时间高并发产生的事务消息存储在消息队列中,然后后端服务再慢慢根据自己的能力去消费这些消息,这样就避免直接把后端服务打垮掉。
  3. 降低系统耦合性:生产者发送消息到消息队列中去,需要消费的系统直接去消息队列取消息进行消费即可而不需要和其他系统有耦合。
  4. 延迟任务:大部分消息队列都支持延时消息,例如30分钟后取消未支付订单。

2 使用消息队列会带来哪些问题

  • 系统可用性降低: 系统可用性在某种程度上降低,在加入 MQ 之前,你不用考虑消息丢失或者说 MQ 挂掉等等的情况,但是,引入 MQ 之后就需要去考虑了!
  • 系统复杂性提高: 加入 MQ 之后,需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题。
  • 一致性问题: 消息队列带来的异步可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息就会导致数据不一致的情况。

3 如何保证 RabbitMQ 消息的顺序性?🔥

  • 拆分多个消息队列,每个消息队列对应一个消费者。这样消息队列会多一些,可以在消费者内部采用多线程的方式进行消费;
  • 或者就一个消息队列对应一个消费者,然后这个消费者内部用内存队列做排队,然后分发给底层不同的 worker (某个线程)来处理。这里消费者并不直接消费消息,而是将消息根据关键值(比如:订单 id)进行哈希,哈希值相同的消息保存到了相同的内存队列里。每个内存队列有且只有一个对应的 worker。也就是说,需要保证顺序的消息会按照进入的顺序被这个唯一的 worker 处理。

4 RabbitMQ-如何保证消息不丢失🔥

消息丢失的三种情况:生产者发消息到 MQ 的过程中丢失,MQ 中丢失,MQ 到消费者的过程中丢失。

  • 生产者到 RabbitMQ:
    • 可以用 RabbitMQ 提供的事务机制,就是生产者发送数据之前开启 RabbitMQ 事务,然后发送消息,如果消息没有成功被 RabbitMQ 接收到,那么生产者会收到异常报错,此时就可以回滚事务,然后重试发送消息。
    • 或者使用 confirm 机制,如果消息写入了 RabbitMQ 中,RabbitMQ 会回传一个 ack 。如果 RabbitMQ 没能处理这个消息,会告诉生产者消息接收失败。或者超过一定时间后还没收到 ack 就重新发送。
    • 注意:事务机制(同步,会阻塞)和 Confirm 机制(异步,推荐)是互斥的,两者不能共存。
  • RabbitMQ 自身:开启 RabbitMQ 的持久化,就是消息写入之后会持久化到磁盘,哪怕是 RabbitMQ 自己挂了,恢复之后会自动读取之前存储的数据。
  • RabbitMQ 到消费者:RabbitMQ 提供了消息确认机制。在声明队列时,可以指定 noAck 参数,当 noAck=false 时,RabbitMQ 会等待消费者显式发回 ack 后,才会移除消息。

5 RabbitMQ 消息的重复消费问题如何解决的🔥

  • 生产者发送每条消息的时候,里面加一个全局唯一的 id,比如课程 id 。消费者拿到消息后,先根据这个 id 查一下之前消费过吗。如果没有消费过,再处理消息。
  • 基于数据库的唯一约束来保证不会重复插入多条数据,重复数据插入会报错,不会导致数据库中出现脏数据。

6 RabbitMQ 延迟队列⭐

延迟队列就是用到了死信交换机和 TTL(消息存活时间)实现的。

在我们发消息的时候可以按照需求指定 TTL 的时间,如果消息超时未消费就会变成死信,在 RabbitMQ 中如果消息成为死信,会被发送到死信交换机 ,死信交换机将过期的消息路由到死信队列,消费者监听死信队列中的消息,一旦收到消息,执行相应的业务逻辑,比如取消订单操作。这样就实现了延迟队列的功能了。

RabbitMQ 还提供了一个延迟队列插件,设置交换机的类型为 x-delayed-message。延迟队列插件根据消息的延时时间,将消息放入延迟队列 中,并设定消息的过期时间。一旦消息过期,延迟队列插件会将消息发送到指定的目标队列中。消费者监听目标队列中的消息,一旦收到消息,执行相应的业务逻辑,比如取消订单操作。

7 RabbitMQ 消息怎么传输?

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

8 RabbitMQ 消息怎么路由?

生产者把消息发送到 RabbitMQ 的交换机上。交换机把收到的消息根据路由规则发给绑定的队列。最后再把消息投递给订阅了这个队列的消费者,从而完成消息的异步通讯。

常用的交换机主要分为以下三种:

  • fanout:会把发送到该交换机的消息路由到所有与它绑定的队列中
  • direct:会把消息路由到那些 Bindingkey 与 RoutingKey 完全匹配的队列中
  • topic:与 direct 类似,但匹配规则可以使用通配符。

9 如果有100万消息堆积在 MQ , 如何解决 ?🔥

  • 提高消费者的消费能力,可以使用多线程消费任务
  • 增加更多消费者,提高消费速度
  • 扩大队列容积,提高堆积上限,可以使用 RabbitMQ惰性队列 ,惰性队列的好处主要是
    • 接收到消息后直接存入磁盘而非内存
    • 消费者要消费消息时才会从磁盘中读取并加载到内存
    • 支持数百万条的消息存储

10 如何保证 RabbitMQ 高可用的?

RabbitMQ 有三种模式:单机模式、普通集群模式(提高吞吐量但无高可用)、镜像集群模式

可以使用镜像集群模式。镜像队列结构是一主多从,所有操作都是主节点完成,然后同步给镜像节点,如果主节点宕机后,镜像节点会替代成新的主节点,不过在主从同步完成前,主节点如果宕机,可能出现数据丢失

11 那出现丢数据怎么解决呢?

我们可以采用仲裁队列,与镜像队列一样,都是主从模式,支持主从数据同步,主从同步基于 Raft 协议,强一致。

并且使用起来也非常简单,不需要额外的配置,在声明队列的时候只要指定这个是仲裁队列即可

12 Kafka 高性能和高吞吐量的原因:

  1. 顺序写磁盘: Kafka 采用顺序写磁盘的方式来存储消息,而不是随机写磁盘。现代操作系统对顺序写的磁盘操作进行了大量优化,使得顺序写的速度接近内存写的速度。

  2. 零拷贝技术: Kafka 使用了 Linux 的零拷贝(zero-copy)技术,减少了数据在内存和磁盘之间的拷贝次数。这大大降低了 CPU 的使用率,并提高了数据传输的效率。

  3. 分布式架构: Kafka 是分布式消息系统,支持将数据分片(partition)存储在不同的 broker 上,每个分片可以独立写入和读取,极大地提高了系统的并发处理能力。

  4. 消息的批量处理: Kafka 在数据传输时支持批量发送和拉取消息,减少了网络请求的频率,从而提高了整体吞吐量。批量处理使得单次网络开销能够分摊到多条消息上。

  5. 内存映射文件: Kafka 使用了操作系统的内存映射文件技术(mmap),将磁盘文件直接映射到内存中,这样在读取消息时,不需要频繁从磁盘读取数据,提升了性能。

  6. 高效的数据压缩: Kafka 支持多种压缩算法(如 Snappy、GZIP 等),用户可以选择启用消息压缩,从而减少消息传输中的带宽消耗,进一步提高系统吞吐量。

  7. 分区并行: Kafka 的分区机制允许消费者可以并行消费不同分区的数据,这极大提高了消费的并发性和吞吐量,特别是在高负载场景下。

  8. 异步复制机制: Kafka 允许在数据写入后异步将数据复制到其他副本,从而在保证数据可靠性的同时,不影响写入性能。

13 常见消息队列的区别🔥

  1. RabbitMQ 基于 Erlang 开发,吞吐量方面虽然稍逊于 RocketMQ 和 Kafka,但是延迟很低,能达到微秒级。如果是中小型公司,基础架构研发能力较弱,采用 RabbitMQ 是不错的选择,简单易用。
  2. RocketMQ 阿里开源的项目,基于 Java 开发,适用于需要极高可靠性的场景。对于基础架构研发实力较强的大公司,可以采用 RocketMQ,因为开源所以可以定制自己公司的 MQ。
  3. 如果是大数据领域的实时计算、日志采集等场景 ,用 Kafka 是业内标准的,仅仅提供较少的核心功能,但是具备极高的吞吐量分布式扩展能力。
相关推荐
言、雲几秒前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
TT哇7 分钟前
【数据结构练习题】链表与LinkedList
java·数据结构·链表
汪洪墩30 分钟前
【Mars3d】设置backgroundImage、map.scene.skyBox、backgroundImage来回切换
开发语言·javascript·python·ecmascript·webgl·cesium
云空35 分钟前
《QT 5.14.1 搭建 opencv 环境全攻略》
开发语言·qt·opencv
Yvemil736 分钟前
《开启微服务之旅:Spring Boot 从入门到实践》(三)
java
Anna。。37 分钟前
Java入门2-idea 第五章:IO流(java.io包中)
java·开发语言·intellij-idea
.生产的驴1 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
我曾经是个程序员1 小时前
鸿蒙学习记录
开发语言·前端·javascript
爱上语文1 小时前
宠物管理系统:Dao层
java·开发语言·宠物
王ASC2 小时前
SpringMVC的URL组成,以及URI中对/斜杠的处理,解决IllegalStateException: Ambiguous mapping
java·mvc·springboot·web