发布于 

为什么要使用消息队列?

本站字数:106.9k    本文字数:1.8k    预计阅读时长:6min    访问次数:

消息队列在系统开发的过程中越来越常用了,那么为什么要使用消息队列,又如何在众多消息队列产品中选择合适的消息队列呢?

什么是消息队列?

在传统的单机应用中,消息队列的作用似乎可以被Spring本身自带的事件机制取代 – 发布订阅模型/任务的异步处理。为了能够各个Service代码之间实现解耦,就可以考虑使用Spring本身的事件机制。创建事件源,创建对应的事件监听器,发布事件,这样就可以完成不同代码之间的耦合。

但是,随着单体应用的庞大,不可避免的需要将服务进行划分,应用的架构也变成了微服务分布式架构,对于这样的架构,发布事件,或者说发消息就变成了一件困难的事情。最直接的办法就是,每个微服务专门为此添加相对应的回调接口,然后使用远程代理类;异或是使用Dubbo或者gRPC之类的远程调用框架,实现消息的发布。使用这种解决方案的话,就相当于是单体应用之间的Service类代码发生了严重的耦合,不利于代码的开发。

有一句名言说得好:没什么是中间加一层解决不了的,如果有那就再来一层。

这个问题也是这样,既然服务之间相互耦合严重,也许可以借鉴Spring的发布订阅模型来进行解耦合。发布订阅模型有一个缺点,发布一个消息以后必须立马消费掉,如果失败了没有重来的机会。再一个问题就是,如果发消息很频繁,消息来不及消费就没了,这肯定是不能被允许的。那么一个用来发布消息,存储消息的中间件就很急迫了。

既然市场有需求,那么消息队列应运而生。凭借高效可靠的消息存储,消费,很快就成为了分布式系统中必不可少的中间件。

为什么要使用消息队列?

消息队列既然在分布式系统中这么重要,那么它的消费场景有哪些呢?就拿秒杀系统作为例子,来讲述消息队列的多种好处吧。

异步处理

在设计一个秒杀系统的时候,核心问题是如何利用有限的服务器资源,尽可能多的处理短时间内海量的请求。一个秒杀请求包含了很多步骤:

  • 风险控制
  • 库存锁定
  • 生成订单
  • 短信通知
  • 更新统计数据

对于正常的流程:从APP到网关,依次调用上述的5个过程以后,返回结果给APP。

对于这么长的5个步骤,不说是否能一次成功,单单是这么长的调用过程,就足够让人感到心烦了。所以,为了能够提高效率,可以在完成库存锁定后,向消息队列发送消息,向用户返回秒杀成功的消息。随后,生成订单,短信通知,更新统计数据的服务收到消息后,消费消息最终完成5个过程。

在异步处理的场景中,消息队列的好处是

  • 更快的返回结果
  • 减少等待,自然实现了步骤之间的并发,提升系统的总体性能。

流量控制

那么即使如此,后端的处理能力还是有一个上限,那么如何避免请求过多,压垮秒杀系统呢?

设计思路:使用消息队列隔离网关和后端服务,以达到流量控制和保护后端服务的目的。

加入消息队列以后,整个秒杀流程就变为:

  1. 网关收到请求以后,发送消息到消息队列
  2. 后端服务从消息队列中获取APP请求,完成后续秒杀处理的过程,最后返回结果。

秒杀开始后,短时间的大量请求不会直接打到后端,而是经过网关后保存到消息队列中,后端按照自己最大的消费能力处理消息。对于超时的消息可以直接丢弃,APP超时处理为秒杀失败。运维人员还可以很方便得对后端进行水平扩容,而不用对系统的其他部分做出任何修改。

但是这样的代价就是,中间加一层以后,执行链路会变得很长。而且上下游系统都要将同步消息改为异步消息,增加了系统的复杂度。

第二套方案就是使用令牌桶控制流量:单位时间内只发放固定数量的令牌,规定服务在处理请求信息的时候,必须从令牌桶中拿出一个令牌,如果没有令牌那就拒绝请求。这样就可以保证单位时间内,能处理的请求不超过发放令牌的数量。起到了流量控制的作用。

服务解耦

消息队列的另外一个作用就是应用之间的解耦。比如订单服务,在创建一个订单时,需要支付系统发起支付流程,风控系统需要审核订单的合法性等等。

这些订单下游的系统,都需要实时获得订单的数据。随着业务发展,这些下游系统不断变化,不断增加,每一个系统可能仅仅需要订单数据的一个子集,那么订单系统就需要应对不断变化的下游系统。每一次下游接口变更,都需要订单模块重新上线,这对于一个核心系统来说,不可接受。

引入消息队列以后,订单服务在订单发生变化时,发送同一条消息到消息队列的一个主题Order中,所有的下游系统都订阅这个主题Order,这样每个下游系统都可以获得一份实时完整的订单数据,而且下游服务无论怎么变化,订单服务都无需为之更改,实现了订单服务和下游服务的解耦。

消息队列的优缺点

优点:

  • 作为发布订阅系统实现一个微服务系统之间的观察者模式
  • 连接六计算任务和数据
  • 用于将消息广播给大量接收者

缺点:

  • 引入消息队列带来链路过长,以及自身带来的延迟问题
  • 增加了系统的复杂度
  • 可能产生数据不一致的问题

怎么选取合适的消息队列?

作为一款及格的消息队列产品,必须具备以下的几个特征:

  • 消息可靠传递
  • Cluster:支持集群,确保不会因为某几个节点宕机导致不可用,也不能丢消息
  • 性能:必须具备优良的性能,能满足绝大多数的场景需求