【RocketMQ初探篇】初始消息队列 & RocketMQ

614 阅读7分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情


既然要学RocketMQ,那么我们就需要先明白它是做什么的,以及为什么我们要用它,不要为了学习而学习,毕竟时间是很宝贵的。


何为消息中间件

消息队列,也就是常说的MQ(message queue)现在是企业内部系统消息流转的核心手段,它具有以下特点:

  • 低耦合
  • 消息可靠投递
  • 消息传播范围广
  • 可以控制流量(削峰填谷)
  • 数据最终一致性

上面提到的内容我会一一介绍,除此之外,本文还将带领大家从架构的角度理解消息中间件,了解消息在企业系统中的应用,以及MQ的工作原理与实际应用场景。

在这里插入图片描述


为什么要使用MQ

削峰填谷

使用MQ的场景有很多,比如就拿电商场景为例吧,大家都知道,在每年双十一的时候,淘宝的后台服务器都会承载巨大的压力,如果将那一瞬间的流量全部打到业务服务器上,可能瞬间服务就宕机了,但如果我们先把用户们发来的消息堆积起来,具体的业务服务器根据自己的实际情况从消息队列里拿消息再执行对应的操作,就可以避免瞬时压力过大带来的问题,这就是削峰填谷。

在这里插入图片描述


服务解耦

当你在淘宝里点了下单按钮之后,其实后台是做了非常多的工作的:

  • 首先要核对你的基本信息,然后检查商品库存并扣减,然后计算优惠信息,然后拉取支付方式,支付成功后通知卖家发货等等等等,其中每一步的工作量也不小,如果我们将上面的过程全部写到一段代码里面的话,很可能前面某个环节一个小小的问题就会导致整个链路执行失败,用户体验就很差,这就是传统的强耦合的设计。
  • 对此,我们可以借助消息队列来进行解耦,当执行完一步后发送一条消息即可,下游链路读取到对应的消息后再执行进一步的操作,把同步操作变为异步操作,使得其中的一些任务同时执行。

如下图所示,A,B,C,D是让用户发起付款的几个流程,E是通知卖家发货的流程,我们完全可以将E过程解耦,让B,C,D同时进行,来加快整条链路的执行过程:

在这里插入图片描述

我应该怎么做技术选型?

在这里插入图片描述

目前主流的MQ主要有四种:

  • ActiveMQ
  • RabbitMQ
  • Kafka
  • RocketMQ

从上到下技术由旧到新。具体如何做技术选型大家可以参考下表:

ActiveMQRabbitMQKafkaRocketMQ
开发语言JavaErlangScalaJava
单体吞吐量万级万级10万级10万级
时延ms级us级ms级ms级
可用性
特点最经典的产品,很多公司沿用至今,发展时间较长所以有很多文档并发能力强,延时很低只支持主要的MQ功能,在大数据领域应用较广泛继承了Kafka的优秀设计,功能更完备,扩展性好
  • 如果是大数据应用场景,建议使用Kafka
  • 如果是中小型公司,建议使用RabbitMQ,因为软件的数据量并没有那么大,并且它的功能比Kafka完备,缺点是它是用Erlang语言开发的,阻碍了海量Java程序员对其完善
  • 大公司应该在Kafka和RocketMQ之前进行选择,因为大公司具有足够的数据量,也具有充足的资金搭建集群环境,甚至还能有专门的人力针对消息队列进行定制化开发

此外,也可以从以下几点来思考公司到底适合哪一种消息队列:

  1. 性能
  2. 功能完备程度
  3. 开发语言
  4. 是否有公司使用,效果如何?
  5. 社区的活跃程度以及文档详细度
  6. 员工学习成本
  7. 是否支持集群、分布式

谨慎使用消息中间件

上面我们介绍了消息中间件那么多的好处,但并不代表我们所有的项目都要“无脑”引入消息队列,毕竟过犹不及是真理。

一旦我们决定要引入MQ,首先要思考的问题就是它是否会为整个项目带来风险?可以从以下几点角度进行思考:

  1. 系统复杂度:项目引入MQ势必会增加系统的复杂度,比如要考虑如何实现最终一致?如何保证消息不被重复消费?如何保证消息可靠传输?等等等等,我们是否可以接收这样的复杂度提高。

  2. 维护成本:系统复杂度增加之后,就会需要额外的成本来进行架构和技术方案的设计,我们是否接受增加额外的人力成本。

但实际上,当下国内互联网公司往往都是糙快猛的发展模式,产品快速迭代已经成为企业的一个基本要求,所以项目往往采用微服务的架构,这样一来,引入MQ也就成为必然。

这一部分的目的也是要告诉大家,选用MQ时要做好详细的设计


RocketMQ应用场景举例

上面介绍了那么多,可能大家对于如何使用MQ还是一头雾水,这一节就给大家列举一下使用MQ的几个经典案例。

异步处理

假设现在有一个用户登录的需求,由于我们应用的安全级别设置的比较高,所以产品要求所有注册用户必须 手机 + 邮箱 双重验证后才算注册成功。

如果采用串行的方式来设计这个流程的话: 在这里插入图片描述

用户发起登录请求,后台接收到请求之后先发送验证邮件,之后发送验证短信,最后反馈给用户响应,假设一共需要150ms。


如果引入MQ和异步处理的话:

在这里插入图片描述 如果使用了消息队列 + 异步处理,就会使得响应时长变为50ms,分析如下:

  1. 用户发起登录请求
  2. 登录模块在收到请求之后写入一条新消息到MQ里,这个过程基本不耗时间,此时就可以直接返回给用户响应了
  3. 后台系统从MQ中异步读取消息,执行各自的逻辑,用户收到短信后完成操作

所以综合来看,1s时间内能够处理的登录请求从同步时的7次到异步时的20次,性能大约提升了3倍!


应用解耦

还是回到上一部分电商的例子,用户下单后,订单系统需要通知库存系统进行扣减库存的操作,直觉思路是直接在订单系统里调用库存系统,等库存扣减完毕后再执行后续的操作:

在这里插入图片描述

这样的调用方式有一个明显的缺点,那就是一旦库存系统挂了,就会导致订单系统也一直返回失败,用户无法正常下单,两个系统强耦合在一起,对此,我们可以采取如下的方式:

在这里插入图片描述 订单系统在用户下单后写入一条消息后就直接返回;库存系统读取这条消息消费,减去对应商品的库存。

这样一来,即便库存系统挂了也不影响用户下单,因为订单系统在写入消息后就结束了,实现了二者的解耦。

日志处理

在这里插入图片描述 日志收集系统负责采集日志数据,写入MQ;日志处理系统负责处理MQ中的日志数据。

进程间通信

消息队列一般都基于高效通信框架,例如Netty,因此可以用来实现进程间通信: 在这里插入图片描述

分布式事务保证最终一致性

用户A向用户B转账,使用MQ来保证系统的最终一致性: 在这里插入图片描述