01.MQ简介

MQ是干嘛的

当你刚刚为公司的一个Web应用实现了一个很棒的注册模块。它看起来简洁、高效。在你沾沾自喜的时候,你的leader对你说,现在咱们需要在注册成功后对用户发送一条短信。过了一段时间后,你的leader又对你说,现在咱们需要在注册成功后对用户发送一条邮件,点击邮件中的激活链接后才算是真正的注册成功。又过了一段时间,你的leader又对你说,现在咱们需要在注册成功后对用户发送一条成功赠送金币的迎新消息。又过了一段时间后…

世界唯一不变的就是不断变化。对于刚才的应用场景,如果所有的新增业务逻辑都写在注册模块中,不但会有大量的耦合,也会增加后期维护的成本。

江湖传闻应对这种场景对于MQ来说小菜一碟,那我们来看下MQ是怎么做到的。


MQ英文全称Message Queue,中文翻译为消息总线或消息队列,它是一种跨进程的通信机制,用于上下游传递消息。

在互联网架构中,MQ是一种非常常见的上下游逻辑解耦+物理解耦的消息通信服务。使用了MQ之后,消息发送上游只需要依赖MQ,逻辑上和物理上都不用依赖其他服务。

对于刚开始我们提到的问题,如果使用MQ的话,我们只需要在注册完成后向MQ中发送一条消息;对于后面的迭代模块只需要订阅该消息即可。无论后期新增多少模块都不会对原始的注册模块造成影响。

其实,我们可以把MQ想象成一个邮局,当你把你想要投递的邮件放进邮箱时,MQ最终会把邮件投递给你的收件人,当然了,你的收件人可以是一个人或者是一群人,这个MQ都是支持的。

既然MQ这么厉害,为什么不所有的通讯都使用MQ呢?

因为没有一种技术普适于所有差异化的业务场景。就好比,相对论把牛顿的经典力学扩展到更普适的宇宙范围,上升到亚光速和光速层面,打破了经典力学的局限性,但是,它也肯定有局限性,不然也不会显得与量子力学格格不入!那么,MQ的局限性都有哪些呢?

MQ的局限性

  • 多了个组件,会使系统更复杂
  • 消息传递路径更长,延时会增加
  • 消息可靠性和重复性护卫矛盾,消息不丢不重难以同时保证
  • 比较致命的是,上游无法知道下游的执行结果

举个简单的例子,用户的登录,登录页面调用用户中心的登录服务,而登录服务的执行结果将直接影响登录的结果。此处的登录页面登录服务就必须使用调用关系,而不能使用MQ通信。假如使用了MQ,想想都很酸爽。。

正因为MQ局限性的存在,那么,我们什么情况下不使用MQ呢?

因为其局限性,所以,当调用方实时依赖执行结果的业务场景,请使用调用,而不是MQ

我们在了解了什么情况下不宜使用MQ的情况下,我们更应该熟悉MQ常用的几种典型场景。

MQ典型应用场景

数据驱动的任务依赖

所谓的数据驱动的任务依赖,顾名思义,就是指某一个任务的输入数据依赖于另一个任务的输出数据。

比如,很多公司会在凌晨进行一些数据统计业务,而有时候多个统计业务就会有数据依赖的情况。

对于这类需求,常见的实现方式是使用,cron表达式进行人工排执行时间表。

  • task1, 0:00执行,经验执行时间50分钟
  • task2,1:00执行(为task1预留10分钟buffer),经验执行时间也是50分钟
  • task3,2:00执行(为task2预留10分钟buffer)

但是,这种方法有着显著的弊端:

  • 如果有一个任务执行时间超过了预留buffer的时间,将会得到错误的结果,因为后置任务不清楚前置任务是否执行成功,此时要手动重跑任务,还有可能要调整排班表

  • 总任务的执行时间很长,总是要预留很多buffer,如果前置任务提前完成,后置任务不会提前开始

  • 如果一个任务被多个任务依赖,这个任务将会称为关键路径,排班表很难体现依赖关系,容易出错

  • 如果有一个任务的执行时间要调整,将会有多个任务的执行时间要调整

而且,这种方式也是具有很高的耦合性。因此,我们给出的优化方案就是使用MQ。

  • task1准时开始,结束后发一个“task1 done”的消息

  • task2订阅“task1 done”的消息,收到消息后第一时间启动执行,结束后发一个“task2 done”的消息

  • task3同理

ps:此处发送的消息可以理解为,确认任务完成的一个标识消息,而不是任务执行完成后的输出数据

综上所述,在数据驱动的任务依赖的场景下,采用MQ具备了以下优点:

  • 不需要预留buffer,上游任务执行完,下游任务总会在第一时间被执行

  • 依赖多个任务,被多个任务依赖都很好处理,只需要订阅相关消息即可

  • 有任务执行时间变化,下游任务都不需要调整执行时间

上游不关心执行结果

在上面已经说过,如果上游需要关注执行结果,则需要使用调用,如果上游不需要关注执行结果,则可以使用MQ。

此处,我们再次回顾下开篇所说的注册模块,注册成功后,短信模块需要发送一条短信通知,邮件模块需要发送一条邮件通知,金币模块需要发送一条赠送金币通知。这里,我们不关心执行结果,只要执行了就是OK的。

如果采用直接调用

  • 最明显的就是,执行时间增加

  • 其次,下游某一个服务宕机,可能导致注册服务的异常,上下游逻辑+物理依赖严重

  • 最后,如果再新增一个下游,上游必须得修改代码,属于架构设计中典型的依赖倒转

优化后,采用MQ解耦,在注册成功后,向MQ发送一个消息;哪个下游关注注册成功这个事件,就主动去MQ订阅

采用MQ后,上游执行时间只关注本身业务;除了与MQ有物理连接,上下游模块都不相互依赖;新增一个下游消息关注方,上游不需要修改任何代码。

上游关心执行结果,但执行时间很长

有时候上游需要关注执行结果,但执行时间很长。典型的是调用离线处理,或者跨公网调用,经常使用回调网关+MQ来解耦

比如,微信支付,跨公网调用微信的接口。

执行的流程:

  • 调用方直接跨公网调用微信接口

  • 微信返回调用成功,此时并不代表返回成功

  • 微信执行完成后,回调统一网关

  • 网关将返回结果通知MQ

  • 请求方收到结果通知

这里可能会有个疑问,为什么不由回调网关来调用上游来通知结果呢?
因为,如果这样的话,每次新增调用方,回调网关都需要修改代码,仍然会反向依赖,使用回调网关+MQ的方案,新增任何对微信支付的调用,都不需要修改代码啦。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值