关于MQ面试题侧重点你知道哪些?

什么是MQ?

全程message Queue(消息队列),是在消息传输的过程中保存消息的容器。多用于分布式之间的通信,主要功能业务解耦。常见的产品:RabbitMQ,RocketMQ,kafka

为什么使用MQ(MQ的作用)

异步、解耦、削峰

①异步处理

场景说明:用户注册后,需要发注册邮箱和注册短信。传统做法有:1.串行方式 2.并行方式

串行方式:将注册的信息写到数据库后,发送注册邮件方式,再发送注册的短信,以上三个任务全部完成返回给客户端。但是存在一个问题,这些短信和邮箱不是必须的,它仅仅只是一个通知,而以这种串行的做法会让客户端等待没有必要等待的东西。
在这里插入图片描述

并行方式:将注册信息写入到数据库后,发送邮件的同时发送短信。以上三个任务完成后,返回给客户端,并行的方式能提高处理的时间。

在这里插入图片描述

消息队列:假设三个业务节点分别使用50ms,串行使用150ms,并行使用100ms.虽然并行在一定程度上提高处理时间,但是邮件和短信对正常使用的网站并没有影响。所以,最好的方式就是用户写入数据库就返回

在这里插入图片描述

②应用解耦

场景说明:双11是购物狂节日,用户下单后,订单系统需通知库存系统。传统做法是订单系统调用库存系统的接口

在这里插入图片描述

缺点:当库存系统出现故障的时候,订单会失败。订单系统和库存系统高耦合

加入消息队列:

在这里插入图片描述

*订单系统:*用户下单后,订单系统完成持久化处理,将消息写入消息队列。返回用户订单,下单成功。

*库存系统:*订阅下单の的信息,获取下单信息,进行拆订单操作。就算库存出现故障,消息队列也能保证消息投递的可靠投递,不会导致消息丢失

③流量削峰

场景说明:秒杀活动,会因为流量过大,导致应用挂掉,为了解决该问题,一般在应用的前端加入队列

作用:1. 控制活动人数,超过一定阈值的订单直接丢掉

2. 可以缓解短时间的高流量压垮应用

交换机类型

①Direct Exchange

直连交换机,根据Routing Key(路由键)路由到不同队列

②Fanout Exchange

扇形(广播)交换机,该交换机没有路由概念,即使绑定了路由键也会无视,这个交换机在接收到消息后,会直接转发到绑定到它上面的所有队列

③Topic Exchange

主题交换机,与直连交换机流程类似。特点:路由键和绑定键之间是有规则的。

占位符:

*:表示一个必须出现的单词。

#:表示0个或者多个单词。

如何保证消息不丢失

使用死信队列

常见产生死信的场景

  1. 消息被拒绝访问,即使消费者返回basicNack的信号时,或者拒绝basicReject

  2. 消费者发生异常,超过重试次数。(其实spring框架调用的就是basicNack)

  3. 消息的Expiration 过期时长或队列的TTL过期。.ttl(20*1000)进入的是 先进业务队列的数据

  4. 消息队列达到最大容量 .maxLength(5)

什么是死信队列

死信队列就是用于存储死信的消息队列,在死信队列中,有且只有死信构成,不会存在其余类型的消息。

死信队列在RabbitMQ中并不会单独存在,往往死信队列都会绑定一个普通的业务消息队列,当所绑定的消息队列中,有消息变成了死信了,那么这个消息就会重新被死信交换机路由到指定的死信队列中,我们可以通过对该死信队列进行监听,从而手动的去对这个消息进行补偿。即人工干预

Rabbitmq如何保证消息的可靠性

生产端(包括MQ)消息可靠性保证

生产者把消息发给mq的过程中,把消息弄丢了

①消息持久化:

当生产者发布消息时,可以选择将其标记为持久化(persistent).这将意味着即使RabbitMQ服务器重启,消息也不会丢失,因为它们会存储到磁盘上。

②确认(confirm)机制:

开启一个confirm回调模式后,RabbitMQ会在消息成功写入到磁盘后并至少被一个交换机接收后,向生产者发送一个确认(acknowledgement)。若消息丢失或者无法投递给任何一个队列,RabbitMQ将会发送一个否定确认(nack).生产者可以根据这些确认信号判断消息是否成功送达并采取相应的重试策略。

RabbitMQ作为消息的中间件并启用publisher confirms(发布者确认)与publisher returns(发布者退回)机制时,可以确保消息从生产者到交换机的投递过程得到更准确的状态反馈

消费端消息可靠性保证

①消息确认(Acknowledgments):

消费者在接收消息后,默认情况下RabbitMQ会自动确认消息(autoAck=true).为保证消息的可靠性,可以设置autoAck=false,使得消费者在处理完消息后手动发送确认(basicAck)。如果消费者在处理过程中发生异常或者未完成处理就终止运行,那么消息在超时时间内将不会被删除,会再次被RabbitMQ投递给其他的消费者。

缺点:代码冗余多,容易出现死循环

②死信队列(Dead Letter Queue):

当消息不能被正常消费时(比如达到最大重试次数),可以通过设置TTL(Time To Live)或者死信交换机(Dead Letter Exchange)将消息路由到死信队列中,从而有机会后续分析和处理这些无法正常消费的消息。(人工干预)

如何保证消息的幂等性

数据库幂等性

在不考虑数据更新/删除的情况下,多次查询始终是一个结果,此时查询具备天然的幂等性。

增删改查幂等性案例:

在这里插入图片描述

非幂等性案例:每次执行的结果都不一致

在这里插入图片描述

接口幂等性

接口幂等性,指用户对于同一操作发起的一次请求或者多次请求,其操作结果都是一致的,并不会以为多次请求产生副作用。这里的副作用,可以认为在多次请求操作时,每一次请求对数据的状态都会产生影响。这里的一致性并非要求接口返回的结果是一致的,而是要求被操作的数据状态是一致的。例如:

update order money=100
where
orderId=20240201

上面的操作无论执行多少次,被操作的数据状态都是一致的。

MQ出现非幂等性的情况

①生产者重复生产:

即生产者重复发消息给MQ

生产者把消息发给MQ之后,MQ收到消息再给生产者返回ack的时候,网络中断了。这时候MQ明明已经接收到消息了,但是生产者没接收到确定的消息,就会认为MQ没有接收到消息。因此,在网络重新连接后,生产者会把已经发送给MQ的消息再次发送给MQ,如果MQ没有去重措施的话,那么就会接收到生产者重复发过来的消息

②MQ重试机制:

即MQ重复发送消息给消费者

消费者从MQ中拉取消息进行消费,当消费者已经消费了消息,但是还没有向MQ返回ack的时候,消费者宕机或者网络断开了。所以消费者成功消费了的消息,此时的MQ并不知道,当消费者重启或者网络重连了之后,消费者再次去请求MQ拉取消息的时候,MQ会把已经消费的消息再次发送给消费者,如果消费者没有去重就直接消费,那么就会造成重复消费的现象。会造成数据不一致。

MQ幂等性解决方案

保证幂等性的办法

①针对生产者重复生产:

可以先进行状态的检查:在消息发送之前,先检查数据库,确认此消息是否已经被处理过了(一般通过单据状态)。如果已经处理过,则直接忽略;否则,继续处理,并在处理完之后更新消息状态为已处理。

如: 订单状态10 已支付 20已推送仓库

如果需要再次推送,只需要推送状态是10的订单

②针对MQ重试机制:

唯一标识:每个消息都携带一个业务ID(BizId),如订单号,交易流水号等,以便在消费端能够识别重复的消息

RabbitMQ中如何解决消息堆积问题

①增加更多消费者,提高消费速度

②在消费者内开启线程池加快消息处理速度

③扩大队列容积,提高堆积上限,采用惰性队列

  1. 在声明队列的时候可以设置属性x-queue-mode为lazy,即为惰性队列
  2. 基于磁盘存储,消息上限高
  3. 性能比较稳定,但基于磁盘存储,受限于磁盘IO,时效性会降低
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值