一个用过消息队列的人,竟不知为何要用 MQ?

简介: 一个用过消息队列的人,竟不知为何要用 MQ?

在前两天阿里的面试中,面试官问了几个关于MQ的问题:


What


1.为什么要使用 MQ


2.使用了 MQ 之后有什么优缺点


3.怎么保证 MQ 消息不丢失


4.怎么保证 MQ 的高可用性


其实大家平时可能也有用到MQ,但是可能对于 MQ 的理解仅仅停留在会使用 API 能实现生产消息、消费消息就完事了。可能很多人都没有对 MQ 的一些问题思考过。


为什么需要消息队列(MQ)

其实MQ 的场景有很多,但是比较核心的有 3 个:异步处理、削峰填谷、应用解耦。


1.异步处理


用户注册后,需要发送注册邮件和注册短信。假设注册信息加入数据库需要30ms,发送注册邮件需要40ms。发送注册短信需要50ms。总共需要的时间就是30+40+50=120ms。可能用户会感觉太慢了


但是一旦加入 MQ 之后,系统只需要将客户信息放入数据库就可以直接返回给用户注册成功的信息。然后用MQ异步处理短信和邮箱的验证。而短信和邮箱的验证因为网络问题。用户是可以接受一定时间的延迟的。那么算下来用户感知到这个接口的耗时仅仅是30ms,节约了2/3的时间。用户体验那是倍儿爽。


2.削峰填谷


秒杀在我们的日常中相当常见。在秒杀的过程中,系统都发生了什么呢?假设我们的数据库每秒能处理最大的数据量是100条。但是在活动秒杀的时候,数据量激增到每秒一万条。这样一来服务器不堪重负就会gg掉。所以就要考虑优化我们的架构,而MQ正是解决办法之一!具体办法就是将秒杀的信心和数据放入消息队列。系统按照之前的处理速度来从容的处理这些数据。而不是直接将全部数据涌入系统,避免宕机问题的发生。


3.降低系统之间的耦合度


系统A下面有两个子系统,一个 B 一个 C。这两个子系统都高度依赖于系统A,也就是系统A有所改动的话,那么系统B、C也要做相应的改动。万一有一百个子系统呢?想想都累啊。。


所以这时候就要引入MQ作为中间件了。这样一来子系统只依赖消息而不再依赖于具体的接口。只要 A 系统把消息扔给 MQ 就不用管了。这样即使系统 A 增加或者修改服务的时候。都不会影响其子系统。


通过上面的分析,知道了为什么要使用 MQ,以及使用了 MQ 有什么好处。知其所以然,明白了自己的系统为什么要使用 MQ。就不会出现“我们Leader要用 MQ 我们就用了”这样的事情了。


使用了 MQ 之后有什么优缺点

一个使用了MQ的项目,如果连为什么要用MQ问题都没有考虑过,那就给自己的项目带来了风险。我们引入一个新的技术,也要对这个技术的弊端有充分的了解,这样才能做好预防。要记住,不要给自己挖坑!


1.系统可用性降低


你想啊,本来其他系统只要运行好好的,那你的系统就是正常的。现在你非要加个消息队列进去,那消息队列挂了,你的系统不就GG了。因此,系统可用性降低


2.系统复杂性增加


要多考虑很多方面的问题,比如一致性问题、如何保证消息不被重复消费,如何保证保证消息可靠传输。因此,需要考虑的东西更多,系统复杂性增大。


3.数据一致性问题


本来好好的,A 系统调用BC子系统接口,如果子BC系统出错了,会抛出异常,返回给A系统,让A系统知道,这样的话就可以做回滚操作了,但是使用了 MQ 之后,A 系统发送完消息就完事了,就认为成功了。但是刚好 C 在系统写数据库的时候失败了,但是 A 认为 C 已经成功了?这样一来数据就不一致了。


怎么保证 MQ 消息不丢失

一条MQ消息从产生到消费,有没有可能失败?在哪些环节可能失败,如何处理?


1.消息生产失败


一般来说,从生产者到MQ中间件是通过网络调用的,是网络调用就有可能存在失败。消息队列通常使用确认机制,来保证消息可靠传递:当你代码调用发送消息的方法,消息队列的客户端会把消息发送到Broker,Broker接受到消息会返回客户端一个确认。只要Producer收到了Broker的确认响应,就可以保证消息在生产阶段不会丢失。有些消息队列在长时间没收到发送的确认响应后,会自动重试,如果重试再失败,就会一返回值或者异常方式返回给客户端。所以在编写发送消息的代码,需要正确处理消息发送返回值或者异常,保证这个阶段消息不丢失。


2.MQ处理存储失败


消息到达消息中间件之后,通常是会被存储起来的,只有被写入到磁盘中,消息才是真正地被存储,不会丢失。但是,大部分MQ中间件并不是收到消息就立马写入磁盘的,只是由于磁盘的写入速度相对于内存,现得慢得多得多,所以,像Kafka这样的消息系统,是会把消息写到缓冲区中,异步写入磁盘,如果机器在中途突然断电,是有可能会丢失消息的。为了解决这个问题,大部分的MQ都是采用分布式部署,消息会在多台机器上写入缓存中成功才会返回给业务方成功,由于多台机器同时断电的可能性较低,我们可以认为这是比较低成本又可靠的方案。


3.消费者处理失败


一般的MQ都有MQ重试机制,如果处理失败,就会尝试重复消费这个MQ。这个带来的问题就是,MQ可能已经成功消费了,但是在通知MQ中间件的时候失败了,这个时候带来的结果就是消息重复消费。同理,在生产者重试的时候,也会遇到消息重复消费的问题。这个时候,就要求我们尽量把接口设计得有幂等性,这个时候即便是重复消费,也不用担心什么问题了


怎样保证MQ的高可用性

RabbitMQ 是比较有代表性的,因为是基于主从做高可用性的,我们就以他为例子讲解第一种 MQ 的高可用性怎么实现。RabbitMQ有三种模式:单机模式、普通集群模式、镜像集群模式。


1.单机模式就是 demo 级别的,就是说只有一台机器部署了一个 RabbitMQ 程序。这个会存在单点问题,宕机就玩完了,没什么高可用性可言。一般就是你本地启动了玩玩儿的,没人生产用单机模式。


2.普通集群模式,意思是多台机器启动多个RabbitMQ实例,每个机器启动一个。你创建的queue,只会放在一个RabbitMQ实例上。但是每个实例会同步queue的元数据(可以理解queue的配置信息)。即使你消费的时候连接到了另一个实例,那么那个实例会从queue所在实例上拉取数据过来


其实并没有做到所谓的分布式,还是普通集群。因为会导致你要么消费者每次随机连接一个实例然后拉取数据,要么固定连接那个queue所在实例消费数据。前者有数据拉取的开销,后者会导致单实例性能瓶颈。


如果放queue的实例宕机了,则会导致其他实例都没有办法进行拉取。如果你开启了消息持久化,让RabbitMQ落地存储消息的话,消息不一定会丢。得等这个实例恢复了,然后才可以继续从这个queue拉取数据。


3.镜像集群模式才是所谓的rabbitmq的高可用模式,跟普通集群模式不一样的是,你创建的queue,无论元数据还是queue里的消息都会存在于多个实例上,然后每次你写消息到queue的时候,都会自动把消息到多个实例的queue里进行消息同步。


这样的话,好处在于你任何一个机器宕机了,没事儿,别的机器都可以用。


坏处在于这个性能开销也太大了吧,消息同步所有机器,导致网络带宽压力和消耗很重!


这么玩儿,就没有扩展性可言了,如果某个queue负载很重,你加机器,新增的机器也包含了这个queue的所有数据,并没有办法线性扩展你的queue那么怎么开启这个镜像集群模式呢?


这里简单说一下,避免面试人家问你你不知道,其实很简单rabbitmq有很好的管理控制台,就是在后台新增一个策略,这个策略是镜像集群模式的策略,指定的时候可以要求数据同步到所有节点的,也可以要求就同步到指定数量的节点,然后你再次创建queue的时候,应用这个策略,就会自动将数据同步到其他的节点上去了。


看完本文有收获?请转发分享给更多人

相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
2月前
|
消息中间件 C语言 RocketMQ
消息队列 MQ操作报错合集之出现"Connection reset by peer"的错误,该如何处理
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
2月前
|
消息中间件 Java C语言
消息队列 MQ使用问题之在使用C++客户端和GBase的ESQL进行编译时出现core dump,该怎么办
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
4天前
|
消息中间件
手撸MQ消息队列——循环数组
队列是一种常用的数据结构,类似于栈,但采用先进先出(FIFO)的原则。生活中常见的排队场景就是队列的应用实例。在数据结构中,队列通常用数组实现,包括入队(队尾插入元素)和出队(队头移除元素)两种基本操作。本文介绍了如何用数组实现队列,包括定义数组长度、维护队头和队尾下标(front 和 tail),并通过取模运算解决下标越界问题。此外,还讨论了队列的空与满状态判断,以及并发和等待机制的实现。通过示例代码展示了队列的基本操作及优化方法,确保多线程环境下的正确性和高效性。
11 0
手撸MQ消息队列——循环数组
|
30天前
|
消息中间件 存储 Java
【揭秘】RocketMQ内部运作大揭秘:一探究竟,原来消息队列是这样工作的!
【8月更文挑战第19天】RocketMQ是一款高性能、高可用的消息中间件,在分布式系统中至关重要。它采用发布/订阅模式,支持高吞吐量的消息传递。核心组件包括管理元数据的NameServer、存储消息的Broker以及Producer和Consumer。RocketMQ支持发布/订阅与点对点两种模型,并具备复杂的消息持久化和路由机制。通过Java API示例,可轻松实现消息的发送与接收。RocketMQ凭借其出色的特性和可靠性,成为大型分布式系统首选的消息解决方案。
50 5
|
2月前
|
消息中间件 Java 物联网
消息队列 MQ操作报错合集之建立连接时发生了超时错误,该如何解决
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
消息队列 MQ操作报错合集之建立连接时发生了超时错误,该如何解决
|
1月前
|
消息中间件 网络架构
RabbitMQ消息队列常见面试题
这篇文章总结了RabbitMQ的常见面试题,涵盖了消息模型、使用场景、实现功能、消息幂等性、顺序性、堆积和丢失的避免方法,以及推模式和拉模式的区别。
43 0
|
1月前
|
消息中间件 Java Kafka
MQ 消息队列 比较
MQ 消息队列 比较
29 0
|
2月前
|
消息中间件 JavaScript Linux
消息队列 MQ操作报错合集之客户端在启动时遇到了连接错误,是什么原因
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
2月前
|
消息中间件 Java 开发工具
消息队列 MQ使用问题之如何使用DefaultMQPushConsumer来消费消息
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
2月前
|
消息中间件 运维 Go
消息队列 MQ使用问题之如何配置生产环境
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。

热门文章

最新文章