为什么使用消息队列?引入MQ会为我们带来哪些优势?

3,695 阅读6分钟

我相信消息队列(MQ)对于Java程序员来说应该都不陌生,如果感到陌生,可能你接触的项目都比较小,传统项目没有拆分服务,当业务越来越多的时候就会拆分多个微服务,让我们先来看一个业务场景。

以我们公司APP用户下单为例,用户请求首先到达订单服务,然后去库存服务扣减库存成功之后,通知商户执行业务,再去优惠券系统结算优惠券,然后去积分系统结算积分。

image.png

假设每个微服务接口的响应时间是 200ms,那么这几个服务调用就要 600ms 的时间,加上订单服务自己的业务处理时间 200ms,整个提交订单接口就是将近 1s 的响应时间。如果后续随着业务发展再接入其他系统,这个时间久越来越长。一个接口一秒钟响应,这个吞吐量是非常低的。当系统的QPS稍微高一些,服务器资源就不够用了,当资源不够用的时候,后来的用户请求就会等待服务器释放资源处理,用户就会觉得卡。用户一旦觉得卡,就很可能会回退页面刷新,或者再次点击提交订单,然后请求又过来,又访问数据库,就会更卡。系统最后可能就瘫痪了。

仔细思考一下会发现,其实商户业务、优惠券业务、积分业务这几个操作是可以并行执行的,没必要串行一个个去请求。如果这几个并行就能节省掉很多时间,所以我们可以考虑使用 MQ。

引入 MQ

在引入MQ之前,我们需要了解MQ的模型,MQ作为消息中间件,用于连接两端微服务:生产者和消费者。

image.png

生产者异步把完成某个功能的消息发送给MQ,MQ把消息推送给消费者,消费者执行自己的业务。

image.png

上图是使用 MQ 之后的流程,我们只需要访问订单服务,然后在订单服务里面要做的事情我发个消息让相应的服务去做就好了,比如我要结算优惠券,我就发个消息给优惠券服务,我要扣减增加积分,发个消息给积分系统。这样一来只有订单服务需要花费 200ms 时间,发消息到 MQ 只需要大概 5ms,接口的吞吐量大大提高。而且 200ms 的响应对于用户是无感知的。所以就反应了消息队列的第一大优势:异步

也许你会说,我使用多线程,甚至再使用线程池去做不也能达到异步的效果吗?先别急,乍一看使用线程的确能达到异步效果,但是你可以想一下,一个下单请求要涉及多少个系统就要开启多少个线程。假设现在有 50 个人下订单,那么就要开启 50 * 5 = 250 个线程来处理业务,我们都知道线程是需要消费 CPU 资源的,而且这样还涉及很多线程上下文切换的操作。使用 MQ,我们以后新的业务需要接入新系统的话,直接发个消息通知新系统就行了,几乎不用改任何订单代码,这种系统级别的解耦真的非常 NICE。这就是 MQ 的第二大优势:解耦

以第一个图为例,之前我们说一个下单接口串行一系列微服务要 1s的响应。假设用户量很大的情况下并发下单,或者直接考虑秒杀接口场景。瞬间几万甚至几十万的流量过来,如果照之前的吞吐量这个服务器瞬间就被击垮了,即使你服务集群很多,不会垮,那你数据库也顶不住这么多请求吧。引入消息队列之后,我们将瞬间的流量全部都甩给了MQ,MQ是专业接受高并发的,一般不会被击垮,然后下游子系统分批均衡的从MQ消费,把瞬间的流量峰值给顶住,等到高峰期过了之后,依然保持缓慢的速度消费,这就引入了MQ的第三大优势:削峰填谷

以上就是使用 MQ 的几个好处,我相信在面试的时候大家都能说出 MQ 的优势,异步、解耦、削峰。但是面试官不是想听这几个字的,肯定希望你结合你的项目中的业务场景来说。而且当你说完之后,面试官肯定还会问后续的问题,一般是灵魂四问:

  • 你们项目中哪里用到了MQ,用它解决了什么问题?
  • 你说了使用 MQ 的好处,知不知道使用它又产生了哪些问题?
  • 你怎么解决引入 MQ 产生的这些问题的?
  • 你们选择的是哪款 MQ 产品?为什么?

引入 MQ 带来的问题

使用 MQ 确实解决了一些问题,但无缘无故多了个 MQ 服务进来,肯定要考虑维护,而且首先必须保证 MQ 的高可用。

  • 不然 MQ 挂了,消息没发出去。我创建订单后面几个优惠券、积分的下游系统全都没有执行业务结算怎么办?
  • MQ 是高可用的,消息发出去了,但是优惠券结算业务报错了怎么办?因为这个是异步的,也不好去回滚,这个问题有没有考虑过?
  • 消息正常发出去,消费者也接收到了,商户系统、优惠券系统都正常执行完了,积分业务报错了导致积分没结算,那这个订单的数据就不一致了,这个问题怎么解决呢?
  • 积分系统重复消费了消息,导致结算了两次怎么办? 所以引入了 MQ 之后,系统的复杂性提高了,要考虑上面很多问题。那面试官肯定会问你怎么解决,或者怎么避免上面的几个问题,等下一篇~~~~

MQ 产品选择

这个东西我到是没什么经验,毕竟工作经验尚浅,的确没有去深入研究过,不过可以参考网上给出的几款流行 MQ 产品的对比

属性RabbitMQActiveMQRocketMQKafka
开发语言ErlangJavaJavaScala
客户端支持语言官方支持Erlang,Java,Ruby等,社区产出多种API,几乎支持所有语言Java,C, C++,Python,PHP,Perl,.net等Java,C++官方支持Java,社区产出多种API,如PHP,Python等
单机吞吐量万级(其次)万级(最差)十万级(最好)十万级(次之)
消息延迟微秒级毫秒级毫秒级毫秒以内
功能特性并发能力强,性能极其好,延时低,社区活跃,管理界面丰富老牌产品,成熟度高,文档较多MQ功能比较完备,扩展性佳只支持主要的MQ功能,毕竟是为大数据领域准备的。

我们公司业务量不是很大,暂时也没有在 MQ 上二次开发的需求,然后考虑整合简单,消息延迟低,最后选择了 RabbitMQ,使用 SpringCloud-Stream 整合 RabbitMQ 使用非常方便~~~

如果这篇文章对你有帮助,可以帮忙点个赞哦~~