吊打面试官的硬核技能 - 消息队列

面试官:听说你了解MQ?来讲讲你的理解

我:…

面试官:回去等消息

消息中间件 之 MQ

为什么要用消息队列

面试官:为什么要用消息队列?

面试官心理分析:消息队列应用场景

我:解耦、异步、削峰

面试官:好小子,答对了

消息队列的本质

  • 见其名 思其意 。将【消息队列】拆成【消息】和【队列】—— 消息队列其本质是一种“先进先出”的数据结构。
  • 常见的应用场景:解耦、异步、削峰

解耦

  • 提高系统耦合性。系统的耦合性越高,容错率越低。

低耦合:参照下图以电商应用为例,用户创建订单后,如果耦合调用支付系统、库存系统、物流系统按流程执行完毕后用户才会得到结果。如果任何一个子系统出现故障,就会导致整个订单操作异常,影响用户使用。
在这里插入图片描述

高耦合:使用消息队列解耦合,系统的耦合性就会提高。比如物流系统发生故障,需要几分钟才能来修复,在这段时间内,物流系统要处理的数据被缓存到消息队列中,用户的下单操作正常完成。当物流系统回复后,补充处理存在消息队列中的订单消息即可,终端系统感知不到物流系统发生过几分钟故障。
在这里插入图片描述

异步

  • 多个服务交给MQ相应,非同步进行,减少主服务响应时间,提高用户体验。

同步进行:A 系统接收一个请求,需要在自己本地写库,还需要在 B、C、D 三个系统写库,自己本地写库要 3ms,B、C、D 三个系统分别写库要 300ms、450ms、200ms。最终请求总延时是 3 + 300 + 450 + 200 = 953ms,接近 1s,用户非常不好,一般互联网类的企业,对于用户直接的操作,一般要求是每个请求都必须在 200 ms 以内完成,对用户几乎是无感知的,如果用户通过浏览器发起请求,等待个 1s,这几乎是不可接受的。
在这里插入图片描述

异步进行:如果使用 MQ,那么 A 系统连续发送 3 条消息到 MQ 队列中,假如耗时 5ms,A 系统从接受一个请求到返回响应给用户,总时长是 3 + 5 = 8ms,对于用户而言,响应速度大大提升了,改善了用户的体验
在这里插入图片描述

削峰

  • 应用系统如果遇到流量瞬间的猛增,可能系统会直接崩掉,使用削峰限制系统处理最大流量。

未削峰:在没有削峰的应用中,数据流量直接对接到数据库,我们知道,系统最大承受量依赖于服务器性能,如果应用流量达到这个最大限制,系统可能会直接挂掉。
在这里插入图片描述

流量削峰:有了消息队列可以将大量请求缓存起来,分散到很长一段时间处理,这样可以大大提到系统的稳定性和用户体验。一般情况,为了保证系统的稳定性,如果系统负载超过阈值,就会阻止用户请求,这会影响用户体验,而如果使用消息队列将请求缓存起来,等待系统处理完毕后通知用户下单完毕,这样总不能下单体验要好。
在这里插入图片描述

小结

面试官:为什么要用消息队列?

我:解耦、异步、削峰

各种消息队列产品的比较

面试官:各种消息队列产品都有哪些特点?

面试官心理分析:在选择MQ时是否根据不同MQ的产品特点做过对比和取舍?

我:ActiveMQ用的不多,RabbitMQ是开源的,比较稳定,它基于erlang开发,不适合二次改造,RocketMQ是阿里基于Java开发的,稳定和性能都不错,也适合二次开发,Kafka在大数据领域和日志采集使用较多。

面试官:还不错,那你觉得那个更好呢?

面试官心理分析:你在不同的应用场景是如何对选择消息队列产品的?

我:当然是根据实际应用场景选择啊,一般情况下我不推荐ActiveMQ,其他的都有不错的性能指标,例如…

几种MQ的对比

特性ActiveMQRabbitMQRocketMQkafka
开发语言JavaerlangJavascala
单机吞吐量万级万级10万级10万级
时效性ms级us级ms级ms级内
可用性高(主从架构)高(主从架构)非常高(分布式架构)非常高(分布式架构)
功能特性成熟产品,在很多公司得到应用;有较多文档,各种协议支持较好基于erlang开发,所以并发能力很强,性能及其好,延时很低;管理界面丰富MQ功能比较完备,扩展性佳只支持主要的MQ功能,像一些消息查询、消息回溯功能没有提供,毕竟是为大数据准备的,在大数据领域应用广泛

小结

  • ActiveMQ,早起使用的较多,没经过大规模吞吐量场景的验证,社区也不是很活跃,但是现在确实大家用的不多了,不推荐。
  • RabbitMQ,开发语言 erlang 阻止了大量的 Java 工程师去深入研究和掌控它,对公司而言,几乎处于不可控的状态,但是RabbitMQ是开源的,比较稳定的支持,活跃度也高,如不考虑二次开发,追求性能和稳定性,推荐使用。
  • RocketMQ,开发语言是Java,在阿里内部经受过高并发业务的考验,稳定性和性能均不错,考虑后期可能二次开发,推荐使用。
  • Kafka ,大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,社区活跃度很高,推荐使用。大数据领域日志采集等业务推荐使用。

消息队列的优点和缺点

面试官:消息队列的优点和缺点

面试官心理分析:考察面试者在项目引入一个新的技术后,是否考虑考虑过新技术对项目的影响

我:MQ就像一把双刃剑,我们必须要从综合角度考虑项目在引入MQ后会有很大的增益效果,它在带来优点的同时也有很多缺点,例如…

优点

  • 优点就不用再次阐述了:解耦、异步、削峰。

缺点

  • 系统可用性降低

系统引入的外部依赖越多,系统稳定性越差。一旦MQ宕机,就会对业务造成影响。

  • 系统的复杂性提高

MQ的加入大大增加了系统的复杂度,以前系统间是同步的远程调用,现在是通过MQ进行异步调用。

  • 一致性问题

A系统处理完业务,通过MQ给B、C、D三个系统发消息数据,如果B系统、C系统处理成功,D系统处理失败。

小结

  • 通过对MQ的优缺点分析,我们衍生出一系列问题:
系统可用性降低
如何保证系统的高可用
系统的复杂性提高
消息丢失怎么办
重复消息怎么处理
如何保证消息传递的顺序性
一致性问题
如何保证消息数据处理的一致性

如何保证消息队列的高可用

以下按照实际应用例举

RabbitMQ高可用-普通集群

  1. 在多台机器上分别启动RabbitMQ实例。
  2. 多个实例之间可以相互通信。
  3. 创建的Queue只会放在一个RabbitMQ上,其他实例都同步元数据。
  4. 消费的时候,如果连接的没有Queue,那么当前实例会从queue所在实例拉取数据。

在这里插入图片描述

RabbitMQ高可用-镜像集群

  1. 在多台机器上分别启动RabbitMQ实例。
  2. 多个实例之间可以相互通信。
  3. 每次生产者写消息到 queue 的时候,都会自动把消息同步到多个实例的 queue 上。每个RabbitMQ节点上都有Queue的消息数据和元数据。
  4. 某一个节点宕机,其他节点依然保存完整数据,不影响客户端消费。

在这里插入图片描述

RockerMQ高可用-双主双从

  1. 生产者通过Name Server发现Broker
  2. 生产者发送队列消息到2个Broker主节点
  3. Broker主节点分别和各自从节点同步数据
  4. 消费者从主或者从节点订阅消息

在这里插入图片描述

小结

面试官:MQ的高可用如何保证?

我:RabbitMQ的镜像集群,RocketMQ的双主双从。

如何保证消息不丢失

消息丢失的原因

  • 情况一:消息生产者没有成功发送到MQ Broker
  • 情况二:消息发送给MQ Broker后,Broker宕机导致内存中的消息数据丢失
  • 情况三:消费者获取到消息,但消费者还没有来得及处理宕机了,但此时MQ中消息已经删除,消费者重启后不能再消费之前的消息

在这里插入图片描述

确保消息不丢失方案

  1. 消息发送者发送给MQ Broker后,MQ Broker给生产者确认收到
  2. MQ收到消息后进行消息持久化
  3. 消费者收到消息处理完毕后手动进行ack确认
  4. MQ收到消费者ack确认后删除持久化的消息

在这里插入图片描述

小结

  • 消息丢失的原因:发送方、MQ、消费方故障都有可能导致消息丢失。

面试官:如何保证消息不丢失?

我:发送方的可靠发送、MQ消息的持久化、消费方消费完毕进行ACK确认再删除本地消息。

MQ消息的重复问题和幂等性保证?

重复消息的产生原因

  1. 发送消息时重复:当一条消息已被成功发送到服务端,此时出现了网络闪断,导致服务端对客户端应答失败。 如果此时生产者意识到消息发送失败并尝试再次发送消息,消费者后续会收到两条内容相同的消息。
    在这里插入图片描述

  2. 消费消息时重复:消息消费的场景下,消息已投递到消费者并完成业务处理,当消费方给MQ服务端反馈应答的时候网络闪断。 为了保证消息至少被消费一次,MQ服务端将在网络恢复后再次尝试投递之前已被消费方处理过的消息,此时消费者就会收到两条内容相同的消息。

在这里插入图片描述

消息幂等性

  1. 消息发送者发送消息时携带一个全局唯一的消息id
  2. 消费者获取消费后先根据id在redis/db中查询是否存在消费记录
  3. 如果没有消费过就正常消费,消费完毕后写入redis/db
  4. 如果消息消费过就直接舍弃

小结

  • MQ消息的重复问题和幂等性保证?

消息重复原因:网络不可达,不可避免。

幂等性:消息携带全局ID,消费方接到消息时先查再处理,根据全局ID做判重操作。

如何保证消息消费的顺序性

  • 消息有序指的是可以按照消息的发送顺序来消费。

例如:一笔订单产生了 3 条消息,分别是订单创建、订单付款、订单完成。
消费时,要按照顺序依次消费才有意义。
与此同时多笔订单之间又是可以并行消费的。

普通模型

模型一
  • 不能保证消息的顺序到达MQ
  • 不能保证消息的顺序消费

M1、M2按照先后顺序发送到2台Server,被2个消费者分别消费
在这里插入图片描述

模型二
  • 可以保证消息的顺序到达MQ。
  • 消费方如果出现网络延迟问题,不能严格保证消息的顺序消费。

M1、M2按照先后顺序发送到1台Server,被2个消费者分别消费
在这里插入图片描述

模型三
  • 可以保证消息顺序到达MQ
  • 可以保证消息顺序消费

生产者:MQ Server:消费者=1:1:1
在这里插入图片描述

  • 模型三属于全局的顺序消费,不常见
  • 吞吐量降低
  • 容错性降低
模型四
  • 生产者根据消息ID将同一组消息发送到一个Queue中。
  • 多个消费者同时获取Queue中的消息进行消费。
  • MQ使用分段锁保证单个Queue中的有序消费。

局部顺序消费
在这里插入图片描述

小结

什么是消息的顺序消费

  • 消费方按照消息发送的顺序进行消费,分为全局顺序消息和局部顺序消息
  • 常见的是局部顺序消费

如何保证消息的顺序消费?

  • 全局顺序消息,生产者:MQ:消费者=1:1:1
  • 局部顺序消息:
    1. 生产者将同一组消息发送到单个队列
    2. 多个消费者并行对消息进行消费
    3. Queue通过分段锁保证消息消费的顺序性

基于MQ的分布式事务实现

  • 本质上来说,分布式事务就是为了保证不同数据库的数据一致性。

  • 例如

  1. 用户提交订单。
  2. 库存服务操作库存DB,减库存。
  3. 订单服务操作订单DB,生成订单数据
  4. 库存服务和订单服务要么同时成功,要么同时失败。

在这里插入图片描述

  • 消息发送方:
  1. 处理业务逻辑
  2. 保存消息到本地数据库
  3. 发送消息给MQ
  4. 监听MQ消息方通知消息,更改消息状态为已处理
  5. 定时任务将长期未处理消息重新发送到MQ
  • 消息消费方:
  1. 监听MQ中间件消息
  2. 判断消息是否重复,重复就丢弃
  3. 消息未重复,执行本地业务
  4. 业务处理完毕,写消息记录到本地数据库
  5. 发送通知消息到MQ

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值