当前位置: 首页 > news >正文

消息队列常见面试题总结

文章目录

    • 1 消息队列有什么用 ?
    • 2 使用消息队列会带来哪些问题
    • 3 如何保证 RabbitMQ 消息的顺序性?🔥
    • 4 RabbitMQ-如何保证消息不丢失🔥
    • 5 RabbitMQ 消息的重复消费问题如何解决的🔥
    • 6 RabbitMQ 延迟队列⭐
    • 7 RabbitMQ 消息怎么传输?
    • 8 RabbitMQ 消息怎么路由?
    • 9 如果有100万消息堆积在 MQ , 如何解决 ?🔥
    • 10 如何保证 RabbitMQ 高可用的?
    • 11 那出现丢数据怎么解决呢?
    • 12 Kafka 高性能和高吞吐量的原因:
    • 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 是业内标准的,仅仅提供较少的核心功能,但是具备极高的吞吐量分布式扩展能力。

相关文章:

  • Linux复习--系统管理类(权限优化、备份策略、RAID、资源查看、启动流程、系统优化)
  • 灵当CRM index.php接口SQL注入漏洞复现 [附POC]
  • [uni-app]小兔鲜-02项目首页
  • 菱形继承、菱形虚拟继承、菱形继承中多态问题、菱形虚拟继承中多态问题
  • 2024外研社综合能力大赛第一场真题
  • 【redis-02】深入理解redis中RBD和AOF的持久化
  • 数据科学基石:解析属性类型体系——从标称到比率,全面洞察数据分类机制
  • 快速开发拍卖平台,成品源码如何满足你的需求?
  • python测试开发---前后端交互Axios
  • Apache Iceberg构建高性能数据湖
  • 软件开发人员需要了解的知识
  • 代码随想录算法训练营第十四天|递归 226.翻转二叉树 101. 对称二叉树 104.二叉树的最大深度 111.二叉树的最小深度
  • vue3【实战】响应式主题(实时获取页面比例,指定尺寸内按比例缩放,超过指定尺寸保持高度不变的图片)
  • 云原生|浅谈云原生中的对象存储之MinIO 的使用
  • 回归预测 | Matlab基于SO-SVR蛇群算法优化支持向量机的数据多输入单输出回归预测
  • 2017-08-04 前端日报
  • Angular6错误 Service: No provider for Renderer2
  • CSS 三角实现
  • ES6简单总结(搭配简单的讲解和小案例)
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • Laravel Mix运行时关于es2015报错解决方案
  • learning koa2.x
  • Linux快速复制或删除大量小文件
  • Mocha测试初探
  • vue的全局变量和全局拦截请求器
  • 对象管理器(defineProperty)学习笔记
  • 检测对象或数组
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 使用docker-compose进行多节点部署
  • 小程序滚动组件,左边导航栏与右边内容联动效果实现
  • 从如何停掉 Promise 链说起
  • 关于Android全面屏虚拟导航栏的适配总结
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • # 利刃出鞘_Tomcat 核心原理解析(七)
  • (0)Nginx 功能特性
  • (2009.11版)《网络管理员考试 考前冲刺预测卷及考点解析》复习重点
  • (2024)docker-compose实战 (8)部署LAMP项目(最终版)
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (层次遍历)104. 二叉树的最大深度
  • (二)Linux——Linux常用指令
  • (二刷)代码随想录第15天|层序遍历 226.翻转二叉树 101.对称二叉树2
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (每日一问)计算机网络:浏览器输入一个地址到跳出网页这个过程中发生了哪些事情?(废话少说版)
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (轉貼) VS2005 快捷键 (初級) (.NET) (Visual Studio)
  • (总结)Linux下的暴力密码在线破解工具Hydra详解
  • .htaccess配置重写url引擎
  • .net 7和core版 SignalR
  • .NET delegate 委托 、 Event 事件,接口回调
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .netcore 获取appsettings
  • .NET命令行(CLI)常用命令