消息队列
介绍
消息中间件(MessageQueue)是基于队列与消息的传递技术,在网络环境中为应用程序提供同步或者异步、可靠的消息传输性的软件系统,多用于分布式系统中的通信。
应用场景
场景1:应用解耦
用户下单,需要调用订单系统的服务,而订单系统需要调用 库存系统、支付系统、物流系统 等服务。
-
问题1:当库存系统宕机,订单系统无法请求到库存系统的服务,就会一直等待服务响应,最后订单系统也会随之瘫痪,用户最终会得到 下单失败 的结果。
-
问题2:当有新的需求到来,比如说要增加 一个 X 系统(如下图所示),那么程序员需要到订单系统取修改相应的代码,以调用X系统的服务。当又要增加一个 Y 系统,类似的,程序员又需要到订单系统去修改相应的代码,以调用Y系统的服务,这个时候可以发现整个系统的耦合度是非常高的,容错性非常低,可维护性也非常底。
以上两个问题,总而言之,就是应用系统之间耦合度太高带来的问题。 -
利用MQ解决问题
订单系统面向MQ发送消息,而 库存系统、支付系统、物流系统 面向MQ获取消息,也就是说,订单系统只是向MQ发送消息即可,库存系统、支付系统、物流系统 只是从MQ中获取消息即可。
整个过程中,订单系统无需和 库存系统、支付系统、物流系统 接触,不管它们处于怎样的状态(宕机或者正常运行),订单系统都不会受到影响,这样达到了 解耦合 的目的。
当有增加系统模块的需求,只需要将新增X系统设置成从MQ中获取消息即可,订单系统无需改动,提高了系统的 可维护性。
场景2:异步提速
用户下单,需要请求 订单系统的服务,订单系统首先需要将 订单 存储到DB 中,然后将订单信息发送给 库存系统、支付系统、物流系统,当全部的流程完成之后,这个用户下单的过程才算完成。
- 问题:首先这是一种同步调用的方式,订单系统首先需要将订单存储到DB中,然后,向库存系统发送订单信息,当库存系统处理完之后,再向支付系统发送订单信息,等支付系统完成之后,最后向物流系统发送订单信息,当物流系统完成之后,将结果返回给用户,总耗时 20 + 300 + 300 + 300 = 920ms,这是一个非常慢的速度,对于一个互联网系统来说,是无法接受的。
以上的问题关键在于 同步通讯方式 和 异步通讯方式
简单介绍一下 同步通讯方式 和 异步通讯方式
- 同步通讯方式:每次进行消息传递的时候,需要等待接收者 完成接收 或者 处理完相应的业务 才会继续整个流程的工作,类似于 打电话,你说一句,需要等待对方回复一句,你才会继续说下一句话。
- 异步通讯方式:每次进行消息传递的时候,只需要关注将消息发送出去,无需等待对方的回应,然后继续整个流程的工作,类似于 发邮件,我们只需要将信息通过邮箱发送出去,之后我们就可以继续干别的事情,不用等待。
综上所述,整个问题的关键在于使用的是 同步通讯的方式,这样会大大浪费时间,因此采用异步通讯的方式可以大大优化整个服务响应的速度。
- 利用MQ解决问题
订单系统只需要将 订单信息 发送到MQ,无需等待 库存系统、支付系统、物流系统的处理时间,用户得到订单系统的响应只需要 20 + 5 = 25ms,而库存系统、支付系统、物流系统 只需要从MQ中获取相应的订单信息,然后处理即可,整个过程类似于并行处理。这样整个工作流程的时间就是 20 + 5 + 5 + 300 = 330ms,这样即可大大的减少时间,同时提高 用户体验 和 系统的吞吐量。
场景3:流量削峰
我们知道,某些时刻,用户的订单量会瞬间增大(双11 秒杀活动),这个时候如果请求数超过了系统的请求处理能力,会导致系统宕机或者瘫痪。
- 问题:当某些时刻,系统接收到请求数量远远大于系统本身能够承担的请求量,这个时候系统往往容易崩溃或者产生其他的问题。
- 利用MQ解决问题
A系统是直接接触不到用户的大量请求的,而是MQ将用户的大量请求存储到队列中,而A系统则可以根据自身的能力,从MQ中拉取用户的请求,按照自己的处理能力对请求进行处理,简而言之就是,MQ帮助系统承担了用户请求的压力,而系统只需要按照自己的能力去完成请求处理。
小结
- 应用解耦:提高系统的 容错率 和 可维护性。
- 异步提速:提升 用户体验 和 系统吞吐量 。
- 流量削峰:提高系统 稳定性。
局限性(缺点)
- 系统可用性降低:假设一个分布式系统中,没有用到MQ,只有A、B两个系统,我们只需要保证A、B两个系统正常运行,整个分布式系统就能正常运行,而当我们使用了MQ这样的消息中间件,我们就需要保证 A、B、MQ 三者正常运行,才能保证整个分布式系统正常运行。(如何保证MQ高可用?)
- 系统复杂度提高:MQ 的加入大大增加了系统的复杂度,以前系统间是同步的远程调用,现在是通过 MQ 进行异步调用。(如何保证消息没有被重复消费?怎么处理消息丢失情况? 那么保证消息传递的顺序性?)
- 一致性问题:A 系统处理完业务,通过 MQ 给B、C、D三个系统发消息数据,如果 B 系统、C 系统处理成功,D 系统处理失败。如何保证消息数据处理的一致性?
MQ的适用场景
- 生产者不需要从消费者处获得反馈。引入消息队列之前的直接调用,其接口的返回值应该为空,这才让明明下层的动作还没做,上层却当成动作做完了继续往后走,即所谓异步成为了可能。
- 容许短暂的不一致性,之前在场景2中我们提到,订单系统并没有等待 库存系统、支付系统、物流系统完成工作就响应给了用户 下单成功 的反馈,这个时候的反馈结果和事实是存在不一致性的。
- 确实是用了有效果。即解耦、提速、削峰这些方面的收益,超过加入MQ、管理MQ的成本。