面试-消息队列

创作不易,大家点点关注🌹🌹🌹

1.什么是消息队列?

你可以把消息队列理解为一个使用队列来通信的组件。它的本质,就是个转发器,包含发消息、存消息、消费消息的过程。

这里可以以一种更加容易理解的方式解释消息队列:

想象一下,你经营着一家非常火爆的餐厅。顾客们源源不断地进来点餐(这就好比是系统中的各种请求或事件发生,产生了需要处理的 “消息”)。

以前,服务员(就像系统里直接处理请求的部分)得同时兼顾接待新顾客、记录菜单、把菜单送到厨房,还得关注每个菜品做没做好、给顾客上菜,忙得晕头转向。要是顾客太多,服务员就可能手忙脚乱,甚至把订单弄混或者忘记处理。

后来,你想出了一个办法,在餐厅入口放了一个专门记录订单的本子(这就是消息队列)。顾客进来后,服务员只需要快速把顾客点的餐写在本子上(生产者往消息队列里发送消息),然后就可以去招呼下一位顾客了。

厨房的厨师(消费者)呢,就按本子上记录的顺序,一道一道地做菜(从消息队列里按顺序取出消息并处理)。这样一来,服务员不用再操心每个订单处理得怎么样了,专心接待新顾客就行;厨师也不用被服务员催来催去,可以有条不紊地做菜。即使突然来了一大批顾客,订单都写在本子上,也不会出现混乱,大家都能各司其职。

2.消息队列的选择

Kafka、ActiveMQ、RabbitMQ、RocketMQ来进行不同维度对比。

特性ActiveMQRabbitMQRocketMQKafka
单机吞吐量万级万级10 万级10 万级
时效性毫秒级微秒级毫秒级毫秒级
可用性高(主从)高(主从)非常高(分布式)非常高(分布式)
消息重复至少一次至少一次至少一次 最多一次至少一次最多一次
消息顺序性有序有序有序分区有序
支持主题数千级百万级千级百级,多了性能严重下滑
消息回溯不支持不支持支持(按时间回溯)支持(按offset回溯)
管理界面普通普通完善普通

3.消息队列的使用场景

  • 解耦:可以在多个系统之间进行解耦,将原本通过网络之间的调用的方式改为使用MQ进行消息的异步通讯,只要该操作不是需要同步的,就可以改为使用MQ进行不同系统之间的联系,这样项目之间不会存在耦合,系统之间不会产生太大的影响,就算一个系统挂了,也只是消息挤压在MQ里面没人进行消费而已,不会对其他的系统产生影响。

  • 异步:加入一个操作设计到好几个步骤,这些步骤之间不需要同步完成,比如客户去创建了一个订单,还要去客户轨迹系统添加一条轨迹、去库存系统更新库存、去客户系统修改客户的状态等等。这样如果这个系统都直接进行调用,那么将会产生大量的时间,这样对于客户是无法接收的;并且像添加客户轨迹这种操作是不需要去同步操作的,如果使用MQ将客户创建订单时,将后面的轨迹、库存、状态等信息的更新全都放到MQ里面然后去异步操作,这样就可加快系统的访问速度,提供更好的客户体验。

  • 削峰:一个系统访问流量有高峰时期,也有低峰时期,比如说,中午整点有一个抢购活动等等。比如系统平时流量并不高,一秒钟只有100多个并发请求,系统处理没有任何压力,一切风平浪静,到了某个抢购活动时间,系统并发访问了剧增,比如达到了每秒5000个并发请求,而我们的系统每秒只能处理2000个请求,那么由于流量太大,我们的系统、数据库可能就会崩溃。这时如果使用MQ进行流量削峰,将用户的大量消息直接放到MQ里面,然后我们的系统去按自己的最大消费能力去消费这些消息,就可以保证系统的稳定,只是可能要跟进业务逻辑,给用户返回特定页面或者稍后通过其他方式通知其结果。

4.消息重复消费怎么解决?

只有让消费者的处理逻辑具有幂等性,保证无论同一条消息被消费多少次,结果都是一样的,从而避免因重复消费带来的副作用。

对于已经消费成功的消息,本地数据库表或Redis缓存业务标识,每次处理前先进行校验,保证幂等。

5.消息丢失怎么解决的?

使用一个消息队列,其实就分为三大块:生产者、中间件、消费者,所以要保证消息就是保证三个环节都不能丢失数据。

  • 生产者的消息确认:生产者在发送消息时,需要通过消息确认机制来确保消息成功到达。

  • 存储消息:broker收到消息后,需要将消息持久化到磁盘上,避免消息因内存丢失。

  • 消费者的消息确认:消费者在处理完消息后,再向消息队列发送确认(ACK),如果消费者未发送确认,消息队列需要重新投递该消息。

除此之外,如果消费者持续消费失败,消息队列可以自动进行重试机制或将消息发送到死信队列(DLQ)或通过日志等其他手段记录异常的消息,避免因一时的异常导致消息丢失。

6.消息队列的核心术语

  • 生产者:负责向消息队列中发送消息的应用程序或服务。生产者将消息发送到指定的队列或主题,供消费者消费。

  • 消费者:从消息队列中读取和处理消息的应用程序或服务。消费者根据业务逻辑处理收到的消息,并可以向消息队列发送确认。

  • Broker:消息队列的核心组件,负责接收、存储和分发消息。

  • 队列:存储消息的容器,消息按照先进先出的顺序在队列中存储。队列中的每条消息通常只能被一个消费者消费一次。

  • 主题 (Topic):用于在发布/订阅模型中,消息生产者将消息发布到一个主题,多个订阅该主题的消费者可以接收到相同的消息。

  • 死信队列 (Dead Letter Queue):当消息因为消费失败、多次重试后未成功处理、消息过期或队列达到最大长度等原因被丢弃时,消息可以被转移到死信队列中。

7.如何保证消息的有序性?

单一生产者和单一消费者:

  • 使用单个生产者发送消息到单个队列,并由单个消费者处理消息。可以确保消息按照生产者的发送顺序消费。

  • 方法简单但是容易性能瓶颈,无法利用并发的优势。

顺序队列:

  • 一些消息队列(如RabbitMQ)支持顺序队列,消息在队列中的存储顺序与土地顺序一致。如果使用单个顺序队列,消息将按顺序被消费。

  • 可以使用多个顺序队列来提高并发处理能力,并使用特定规则将消息分配到不同的顺序队列中。

分区:

  • Kafka 可以通过将消息划分到同一个分区(Partition)来保证消息在分区内是有序的,消费者按照分区顺序读取消息就可以保证消息顺序。

  • 这也可能会限制消息的并行处理程度,需要在顺序性和吞吐量之间进行权衡。

8.如何处理消息积压问题

消息积压是因为生产者的生产速度,大于消费者的消费速度。遇到消息积压问题时,我们需要先排查,是不是有bug产生了。

如果不是bug,我们可以优化一下消费的逻辑,比如之前是一条一条消息消费处理的话,我们可以确认是不是可以优为批量处理消息。如果还是慢,我们可以考虑水平扩容,增加Topic的队列数,和消费组机器的数量,提升整体消费能力。

常见有以下几种方式提升消费者的消费能力

  1. 增加消费者线程数量:提高并发消费能力。

  2. 增加消费实例:在分布式系统中,可以水平扩展多个消费实例,从而提高消费速率。

  3. 优化消费者逻辑:检查消费者代码,减少单个消息的处理时间。例如:减少I/O操作、使用批量处理等。

除此之外还可以进行限流和降级处理

  • 对消息生产端进行限流,降低生产速率,避免消息积压进一步恶化。

  • 对非关键消息进行丢弃或延迟处理,只保留高优先级的消息,提高系统的响应速度。

9.消息队列设计成推消息还是拉消息?

推模式(Push):消息队列将消息主动推送给消费者,适合实时性要求高、消费者能够及时处理消息的场景。

  • 优点:实时性好,消息可立即送达消费者。

  • 缺点:难以控制消费速度,容易导致消费者过载,尤其是在高并发时。

拉模式(Pull):消费者主动从消息队列中拉取消息,适合消费能力有限、需要根据自身处理能力调控速率的场景。

  • 优点:消费者可以根据自身负载决定拉取速率,避免过载;更适合批量处理。

  • 缺点:可能会导致消息延迟,实时性不如推模式,尤其是拉取频率较低时。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值