写点什么

为何高并发系统中都要使用消息队列?这次彻底懂了!,java 程序设计精编教程第三版课后答案

作者:MySQL神话
  • 2021 年 11 月 28 日
  • 本文字数:1870 字

    阅读完需:约 6 分钟

很多高并发系统中都会使用到消息队列中间件,那么,问题来了,为什么在高并发系统中都会使用到消息队列中间件呢?立志成为资深架构师的你思考过这个问题吗?


场景分析




现在假设这样一个场景,用户下单成功需要给用户发短信,如果没有消息队列,我们会选择同步调用发短信的接口并等待短信发送成功。现在假设短信接口实现出现了问题或者短信发送短时间内达到了上限,这个时候是选择重试几次还是放弃发送呢?这里的设计会很复杂。如果使用了消息队列,我们选择将发短信的操作封装成一条消息发送到消息队列,消息队列通知一个服务去发送一条短信,即使出现了上述的问题,可以选择把消息重新放到消息队列里等待处理。


消息队列的好处




通过上述了例子,我们看到消息队列完成了一个异步解耦的过程,短信发送时我们只要保证短信发到消息队列成功就可以了,接下来就可以去做别的事情;其次,设计变得更简单,在下单的场景下,我们不用过多考虑发送短信的问题,交给消息队列管理就行了,可能短信发送会有延迟,但是保证了最终的一致性。


消息队列特性




  • 业务无关,只做消息分发。

  • FIFO,先投递先到达。

  • 容灾:节点动态增删和消息持久化。

  • 性能:吞吐量提升,系统内部通信效率提高。


高并发系统为何使用消息队列?




(1)业务解耦


成功完成了一个异步解耦的过程。短信发送时只要保证放到消息队列中就可以了,接着做后面的事情就行。一个事务只关心本质的流程,需要依赖其他事情但是不那么重要的时候,有通知即可,无需等待结果。每个成员不必受其他成员影响,可以更独立自主,只通过一个简单的容器来联系。


对于我们的订单系统,订单最终支付成功之后可能需要给用户发送短信积分什么的,但其实这已经不是我们系统的核心流程了。如果外部系统速度偏慢(比如短信网关速度不好),那么主流程的时间会加长很多,用户肯定不希望点击支付过好几分钟才看到结果。那么我们只需要通知短信系统“我们支付成功了”,不一定非要等待它处理完成。


(2)最终一致性


主要是用记录和补偿的方式来处理;在做所有的不确定事情之前,先把事情记录下来,然后去做不确定的事,它的结果通常分为三种:成功,失败或者不确定;如果成功,我们就可以把记录的东西清理掉,对于失败和不确定,我们可以采用定时任务的方式把所有失败的事情重新做一遍直到成功为止。


保证了最终一致性,通过在队列中存放任务保证它最终一定会执行。


最终一致性指的是两个系统的状态保持一致,要么都成功,要么都失败。当然有个时间限制,理论上越快越好,但实际上在各种异常的情况下,可能会有一定延迟达到最终一致状态,但最后两个系统的状态是一样的。


业界有一些为“最终一致性”而生的消息队列,如 Notify(阿里)、QMQ(去哪儿)等,其设计初衷,就是为了交易系统中的高可靠通知。


以一个银行的转账过程来理解最终一致性,转账的需求很简单,如果 A 系统扣钱成功,则 B 系统加钱一定成功。反之则一起回滚,像什么都没发生一样。


然而,这个过程中存在很多可能的意外:


  • A 扣钱成功,调用 B 加钱接口失败。

  • A 扣钱成功,调用 B 加钱接口虽然成功,但获取最终结果时网络异常引起超时。

  • A 扣钱成功,B 加钱失败,A 想回滚扣的钱,但 A 机器 down 机。


可见,想把这件看似简单的事真正做成,真的不那么容易。所有跨 JVM 的一致性问题,从技术的角度讲通用的解决方案是:


  • 强一致性,分布式事务,但落地太难且成本太高。

  • 最终一致性,主要是用“记录”和“补偿”的方式。在做所有的不确定的事情之前,先把事情记录下来,然后去做不确定的事情,结果可能是:成功、失败或是不确定,“不确定”(例如超时等)可以等价为失败。成功就可以把记录的东西清理掉了,对于失败和不确定,可以依靠定时任务等方式把所有失败的事情重新搞一遍,直到成功为止。


回到刚才的例子,系统在 A 扣钱成功的情况下,把要给 B“通知”这件事记录在库里(为了保证最高的可靠性可以把通知 B 系统加钱和扣钱成功这两件事维护在一个本地事务里),通知成功则删除这条记录,通知失败或不确定则依靠定时任务补偿性地通知我们,直到我们把状态更新成正确的为止。


消息可能重复,注意消息的重复和幂等。

最后

作为过来人,小编是整理了很多进阶架构视频资料、面试文档以及 PDF 的学习资料,针对上面一套系统大纲小编也有对应的相关进阶架构视频资料



![]


《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享


(https://static001.geekbang.org/infoq/19/193defad3b966372576d9bc17da90756.png)


本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

用户头像

MySQL神话

关注

还未添加个人签名 2021.11.12 加入

还未添加个人简介

评论

发布
暂无评论
为何高并发系统中都要使用消息队列?这次彻底懂了!,java程序设计精编教程第三版课后答案