中间件之MQ消息队列

一、什么是MQ ?

   MQ(Message Queue)消息队列,是基础数据结构中“先进先出”的一种数据结构。指把要传输的数据(消息)放在队列中,用队列机制来实现消息传递——生产者产生消息并把消息放入队列,然后由消费者去处理。消费者可以到指定队列拉取消息,或者订阅相应的队列,由MQ服务端给其推送消息。
   上面的这个是百度百科对MQ的定义,简单来说MQ就是用来系统之间进行数据传递的。
   eg:原本的功能实现是由系统A直接调用系统B,引入MQ消息中间件后,系统A不会直接去调用系统B,而是将调用B所需要的数据放到了消息队列中,系统B通过监控该消息队列,主动从消息队列中抓取数据进入处理。

二、为什么要学习MQ?

   在分布式系统的架构中,为了减少各个系统之间的耦合,往往会引入消息队列来实现解耦。
   设计测试用例时,直接从业务功能层面出发,测试功能完全正常,但是上线后却可能出现一些意料之外的问题。
例如:消息的生产者产生消息的速度远远大于消息消费者处理的速度时,会造成队列堵塞,此时系统的行为是怎么样的?
要做到系统性全面的测试设计,就必须知道消息队列的基本原理,然后在此基础上去设计针对具体架构的测试用例和场景。

三、MQ的主要作用

MQ消息队列的主要作用:解耦、异步、削峰、通讯

1、解耦

传统模式:
在这里插入图片描述

传统模式的缺点:
系统间耦合性太强,如上图所示,系统A在代码中直接调用系统B和系统C的代码,如果将来D系统接入,系统A还需要修改代码,过于麻烦!

中间件模式:
在这里插入图片描述
中间件模式的的优点:
将消息写入消息队列,需要消息的系统自己从消息队列中订阅,从而系统A不需要做任何修改。

2、异步

传统模式:
在这里插入图片描述
传统模式的缺点:
一些非必要的业务逻辑以同步的方式运行,只能单线程串行,太耗费时间。
中间件模式:
在这里插入图片描述
中间件模式的的优点:
将消息写入消息队列,非必要的业务逻辑以异步的方式运行,加快响应速度

3、削峰

传统模式
在这里插入图片描述
传统模式的缺点:
并发量大的时候,所有的请求直接怼到数据库,造成数据库连接异常

中间件模式:
在这里插入图片描述
中间件模式的的优点:
系统A慢慢的按照数据库能处理的并发量,从消息队列中慢慢拉取消息。在生产中,这个短暂的高峰期积压是允许的。

四、使用消息队列会出现的问题

1.系统可用性降低

MQ若是挂了,容易引起整个服务挂掉。

2.系统复杂性增加

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

3、一致性问题

异步处理会导致的问题:A系统处理完返回成功,页面以为请求成功了,但在BCD系统那边,BC写入成功了,但是D写入失败了,这就造成数据不一致了。

所以消息队列实际是一种非常复杂的架构,引入会有很多好处,但是也得针对它带来的坏处做各种额外的技术方案和架构来规避掉,做好之后,你会发现,系统复杂度提升了一个数量级,也许是复杂了 10 倍。

五、MQ有哪些类型

在这里插入图片描述
ActiveMQ这个只存在于早期的使用,社区现在也不活跃了,目前绝大部分公司是没有用的了;
主流的是RabbitMQ和RocketMQ:
RabbitMQ,基于erlang 语言 ,并发高,性能好,延时低,但也因为erlang语言不容易定制开发,虽然开源,但确实懂的人不多呀。
RocketMQ,阿里出品,基于java语言,吞吐量大,分布式扩展方便,支持定制开发。
kafka,高吞吐量的分布式发布订阅消息系统,可以处理消费者在网站中的所有动作流数据,用于大数据运算、日志采集等,当然缺点就是kafka的稳定性是较差的。

六、MQ常见问题

1、消息丢失问题

出现的场景有:
(1)生产者丢数据
从生产者弄丢数据这个角度来看,RabbitMQ提供transaction和confirm模式来确保生产者不丢消息。
(2)消息队列丢数据
处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。
这个持久化配置可以和confirm机制配合使用,你可以在消息持久化磁盘后,再给生产者发送一个Ack信号。
这样,如果消息持久化磁盘之前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会自动重发。
(3)消费者丢数据
消费者丢数据一般是因为采用了自动确认消息模式。
这种模式下,消费者会自动确认收到信息。这时rahbitMQ会立即将消息删除,这种情况下如果消费者出现异常而没能处理该消息,就会丢失该消息。
至于解决方案,采用手动确认消息即可。

2、重复消费问题

这个问题在rabbitmq和rocketmq出现的场景是差不多的。
出现的场景有:
(1)发送时消息重复
当一条消息已被成功发送到服务端并完成持久化,此时出现了网络闪断或者客户端宕机,导致服务端对客户端应答失败。 如果此时生产者意识到消息发送失败并尝试再次发送消息,消费者后续会收到两条内容相同并且 Message ID 也相同的消息。
(2)投递时消息重复
消息消费的场景下,消息已投递到消费者并完成业务处理,当客户端给服务端反馈应答的时候网络闪断。 为了保证消息至少被消费一次,消息队列 RocketMQ 的服务端将在网络恢复后再次尝试投递之前已被处理过的消息,消费者后续会收到两条内容相同并且 Message ID 也相同的消息。
(3)负载均衡时消息重复(包括但不限于网络抖动、Broker 重启以及订阅方应用重启)
当消息队列 RocketMQ 的 Broker 或客户端重启、扩容或缩容时,会触发 Rebalance,此时消费者可能会收到重复消息。

解决方法:
(1)通过messageId,作为数据库业务主键,重复插入会报错主键冲突问题。
(2)或者通过redis唯一性,messageId作为key存入,去重重复的数据,在从redis中刷到数据库里面。

3、垃圾消息问题

出现消费失败的情况,就会产生垃圾消息。比如:会员系统发送注册消息给用户系统,用户系统由于其他原因没有消费,会员系统收不到回调会一直发送消息,导致产生较多的垃圾消息

解决方法:对消息发送次数进行频次限制。

4、消息堆积与消费延迟问题

消息处理流程中,如果Consumer的消费速度跟不上Producer的发送速度,MQ中未处理的消息会越来越多,这部分消息就被称为 堆积消息。消息出现堆积会导致消费延迟,以下场景需要重点关注消息堆积和消息延迟的问题:

  • 业务系统上下游能力不匹配造成的持续堆积,且无法自行恢复
  • 业务系统对消息的消费实时性要求较高,即使是短暂的堆积造成的消费延迟也无法接受。

解决方法:
(1)处理消息堆积:

  • 单条处理数据改成批量处理数据
  • 增加 Topic 的队列数和消费者数量,注意队列数一定要增加,不然新增加的消费者是没东西消费的。一个Topic中,一个队列只会分配给一个消费者。

(2)处理延迟消费:

  • 使用延迟队列(RocketMQ)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值