消息队列
消息队列
Yc消息队列面试题
- 为什么要使用消息队列
- 消息队列有什么优点和缺点
- Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什么区别、适合哪些场景使用
分析
首先我们来分析下面试官问出这些问题时他想问你的或者说他想知道你了解的关于消息队列的什么?
- 1、是否知道你所开发的项目中为什么要用到消息队列
很多人在面试时候经常会说自己项目里用了Redis、MQ,但是其实他自己并不知道为什么要用这些东西,其实就是为了用而用,或者说是别人设计的架构,但是自始至终都没有自己思考过。 - 2、既然用到了消息队列这个东西,是否知道在使用消息队列时候有什么好处与坏处
如果为了用而用盲目的在系统中使用MQ,后面出了问题就会是很大的坑。如果一个开发人员从来没考虑过引入一个技术可能存在的弊端和风险,如果我作为面试官我是肯定不会招这样的技术的,因为招进来后很可能会给公司项目挖坑。 - 3、在选择技术中间件时是否做过调研
比如Kafka、ActiveMQ、RabbitMQ、RocketMQ,在选择上是盲目的选择还是通过它们的优点和缺点来进行评估。每一个MQ都不是说有绝对的好处和坏处,需要看在哪个业务场景下更适用,或者不适用。
面试题剖析
为什么使用消息队列
这个问题其实就是想问我们消息队列都有哪些场景,你在自己项目中使用的场景是什么,如果在这个场景下没有使用消息队列有什么样的麻烦或者说使用消息队列在项目中解决了你的什么问题
使用场景
其实消息队列的使用场景有很多种,比较核心的常见的场景有三个:解耦、异步、削峰
- 解耦
下面这个场景,A 系统发送数据到BCD三个系统,通过接口调用的形式发送。但是某一时刻如果E系统也要这个数据呢?如果C系统现在不需要了呢?A系统负责人几乎崩溃……
在这个场景中A系统跟其他系统严重耦合,A系统产生一条关键数据,很多系统都需要A系统将这个数据发送过来。A系统要时刻考虑BCD系统如果宕机该怎么办,要不要重发,要不要把消息存起来。
如果使用MQ,A系统产生一条数据,发送到MQ里面去,哪个系统需要数据则自己去MQ里面消费,如果新系统需要数据,直接从MQ里消费即可。如果某个系统不需要数据了,就取消对MQ消息的消费即可。这样下来,A系统不需要考虑要给谁发送数据,不需要维护代码,也不需要其他系统是否调用成功、失败、超时等情况。
总结:通过一个MQ,Pub/Sub发布订阅消息这种模型,A系统就跟其他系统彻底解耦了。
面试技巧:你需要去考虑一下你负责的系统中是否有类似的场景,如一个系统或者一个模块,调用了多个系统或者模块,互相之间的调用很复杂,维护起来很麻烦。但是其实这个调用是不需要直接同步调用接口的,如果用MQ给它异步化解耦,也是可以的,你就需要去考虑在你的项目里,是不是可以运用这个MQ去进行系统的解耦。
- 异步
再来看一个场景,A系统接收一个请求,需要在自己本地入库,还需要在BCD三个系统入库,自己本地写库要3ms,BCD 三个系统分别写库要 300ms、450ms、200ms。最终请求总延时是3 + 300 + 450 + 200 = 953ms,接近 1s。用户发起请求仅这个业务就需要等待1s
一般互联网类的企业,对于用户直接的操作,一般要求是每个请求都必须在 200 ms 以内完成,对用户几乎是无感知的。
如果使用 MQ,A系统连续发送3条消息到MQ队列中,假如耗时5ms,A系统从接受一个请求到返回响应给用户,总时长是3+5 = 8ms,对于用户而言,其实感觉上就是点个按钮,8ms以后就直接返回了。
- 削峰
假设每天0:00到12:00A系统风平浪静,每秒并发请求数量就50个。结果每天一到12:00到13:00,每秒并发数量突然会暴增到5k+条。系统基于Mysql,大量的请求涌入Mysql,每秒对Mysql执行约5k条SQL语句。
一般的Mysql,扛到2k请求就差不多了,如果每秒请求到5k的话,可能直接就挂了,导致系统崩溃,用户也就无法使用系统了。
但是高峰期一过,到了下午时,就成了低峰期,可能也就1w用户同时在线操作,每秒的请求数量可能也就50个请求,对于系统来说毫无压力。
如果使用MQ每秒5k个请求写入MQ,A系统每秒钟最多处理2k个请求,因为MySQL每秒钟最多处理2k个。A 系统从MQ中慢慢拉取请求,每秒钟就拉取 2k个请求,不要超过自己每秒能处理的最大请求数量就可以,这样下来哪怕是高峰期的时候,A系统也绝对不会挂掉。而MQ每秒钟5k个请求进来,就2k个请求出去,结果就导致在中午高峰期(1 个小时),可能有几十万甚至几百万的请求积压在 MQ 中。
这个短暂的高峰期积压是ok的,因为高峰期过了之后,每秒钟就50个请求进MQ,但是A系统依然会按照每秒2k个请求的速度在处理。所以说,只要高峰期一过,A系统就会快速将积压的消息给解决掉。
消息队列有什么优缺点
优点其实上面已经提到了,就是在特殊场景下有其对应用的好处,解耦、异步、削峰。
缺点有以下几个:
- 系统可用性降低
系统引入的外部依赖越多,越容易挂掉。本来是A系统调用BCD三个系统的接口就好了,加了个MQ进来万一MQ挂掉整套系统崩溃 - 系统复杂度提高
硬生生加个MQ进来如何保证消息没有重复消费,如何处理消息丢失的情况,怎么保证消息传递的顺序性 - 一致性问题
A系统处理完了直接返回成功了,用户以为这个请求成功了,但是如果BCD三个系统里,BD两个系统入库成功了,结果C系统入库失败了,就会导致数据不一致。
所以消息队列实际是一种非常复杂的结构,引入它有很多好处,但是也得针对它带来的坏处做各种额外的技术方案和架构来规避。
Kafka、ActiveMQ、RabbitMQ、RocketMQ优缺点对比
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|---|
单机吞吐量 | 万级,比RocketMQ、Kafka低一个数量级 | 同ActiveMQ | 10万级,支撑高吞吐 | 10万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景 |
topic数量对吞吐量的影响 | topic可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topic | topic从几十到几百个时候,吞吐量会大幅度下降,在同等机器下,Kafka尽量保证topic数量不要过多,如果要支撑大规模的 topic,需要增加更多的机器资源 | ||
时效性 | ms 级 | 微秒级,这是RabbitMQ的一大特点,延迟最低 | ms 级 | 延迟在ms级以内 |
可用性 | 高,基于主从架构实现高可用 | 同ActiveMQ | 非常高,分布式架构 | 非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
消息可靠性 | 有较低的概率丢失数据 | 基本不丢 | 经过参数优化配置,可以做到0丢失 | 同RocketMQ |
功能支持 | MQ领域的功能极其完备 | 基于erlang开发,并发能力很强,性能极好,延时很低 | MQ 功能较为完善,还是分布式的,扩展性好 | 功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用 |
综上各种对比之后,有如下建议:
一般的业务系统要引入MQ,最早大家都用ActiveMQ,但是现在确实大家用的不多了,没经过大规模吞吐量场景的验证,社区也不是很活跃,所以还是算了吧,个人不推荐用这个了;
后来大家开始用RabbitMQ,但是确实erlang语言阻止了大量的Java工程师去深入研究和掌控它,对公司而言,几乎处于不可控的状态,但是确实人家是开源的,比较稳定的支持,活跃度也高;
不过现在确实越来越多的公司会去用RocketMQ,确实很不错,毕竟是阿里出品,但社区可能有突然黄掉的风险(目前 RocketMQ 已捐给 Apache,但GitHub上的活跃度其实不算高)对自己公司技术实力有绝对自信的,推荐用RocketMQ,否则回去老老实实用RabbitMQ吧,人家有活跃的开源社区,绝对不会黄。
所以中小型公司,技术实力较为一般,技术挑战不是特别高,用RabbitMQ是不错的选择;大型公司,基础架构研发实力较强,用RocketMQ是很好的选择。
如果是大数据领域的实时计算、日志采集等场景,用Kafka是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。