为什么要使用消息队列?
本站字数:108k 本文字数:1.8k 预计阅读时长:6min 访问次数:次消息队列在系统开发的过程中越来越常用了,那么为什么要使用消息队列,又如何在众多消息队列产品中选择合适的消息队列呢?
什么是消息队列?
在传统的单机应用中,消息队列的作用似乎可以被Spring本身自带的事件机制取代 – 发布订阅模型/任务的异步处理。为了能够各个Service代码之间实现解耦,就可以考虑使用Spring本身的事件机制。创建事件源,创建对应的事件监听器,发布事件,这样就可以完成不同代码之间的耦合。
但是,随着单体应用的庞大,不可避免的需要将服务进行划分,应用的架构也变成了微服务分布式架构,对于这样的架构,发布事件,或者说发消息就变成了一件困难的事情。最直接的办法就是,每个微服务专门为此添加相对应的回调接口,然后使用远程代理类;异或是使用Dubbo或者gRPC之类的远程调用框架,实现消息的发布。使用这种解决方案的话,就相当于是单体应用之间的Service类代码发生了严重的耦合,不利于代码的开发。
有一句名言说得好:没什么是中间加一层解决不了的,如果有那就再来一层。
这个问题也是这样,既然服务之间相互耦合严重,也许可以借鉴Spring的发布订阅模型来进行解耦合。发布订阅模型有一个缺点,发布一个消息以后必须立马消费掉,如果失败了没有重来的机会。再一个问题就是,如果发消息很频繁,消息来不及消费就没了,这肯定是不能被允许的。那么一个用来发布消息,存储消息的中间件就很急迫了。
既然市场有需求,那么消息队列应运而生。凭借高效可靠的消息存储,消费,很快就成为了分布式系统中必不可少的中间件。
为什么要使用消息队列?
消息队列既然在分布式系统中这么重要,那么它的消费场景有哪些呢?就拿秒杀系统作为例子,来讲述消息队列的多种好处吧。
异步处理
在设计一个秒杀系统的时候,核心问题是如何利用有限的服务器资源,尽可能多的处理短时间内海量的请求。一个秒杀请求包含了很多步骤:
- 风险控制
- 库存锁定
- 生成订单
- 短信通知
- 更新统计数据
对于正常的流程:从APP到网关,依次调用上述的5个过程以后,返回结果给APP。
对于这么长的5个步骤,不说是否能一次成功,单单是这么长的调用过程,就足够让人感到心烦了。所以,为了能够提高效率,可以在完成库存锁定后,向消息队列发送消息,向用户返回秒杀成功的消息。随后,生成订单,短信通知,更新统计数据的服务收到消息后,消费消息最终完成5个过程。
在异步处理的场景中,消息队列的好处是
- 更快的返回结果
- 减少等待,自然实现了步骤之间的并发,提升系统的总体性能。
流量控制
那么即使如此,后端的处理能力还是有一个上限,那么如何避免请求过多,压垮秒杀系统呢?
设计思路:使用消息队列隔离网关和后端服务,以达到流量控制和保护后端服务的目的。
加入消息队列以后,整个秒杀流程就变为:
- 网关收到请求以后,发送消息到消息队列
- 后端服务从消息队列中获取APP请求,完成后续秒杀处理的过程,最后返回结果。
秒杀开始后,短时间的大量请求不会直接打到后端,而是经过网关后保存到消息队列中,后端按照自己最大的消费能力处理消息。对于超时的消息可以直接丢弃,APP超时处理为秒杀失败。运维人员还可以很方便得对后端进行水平扩容,而不用对系统的其他部分做出任何修改。
但是这样的代价就是,中间加一层以后,执行链路会变得很长。而且上下游系统都要将同步消息改为异步消息,增加了系统的复杂度。
第二套方案就是使用令牌桶控制流量:单位时间内只发放固定数量的令牌,规定服务在处理请求信息的时候,必须从令牌桶中拿出一个令牌,如果没有令牌那就拒绝请求。这样就可以保证单位时间内,能处理的请求不超过发放令牌的数量。起到了流量控制的作用。
服务解耦
消息队列的另外一个作用就是应用之间的解耦。比如订单服务,在创建一个订单时,需要支付系统发起支付流程,风控系统需要审核订单的合法性等等。
这些订单下游的系统,都需要实时获得订单的数据。随着业务发展,这些下游系统不断变化,不断增加,每一个系统可能仅仅需要订单数据的一个子集,那么订单系统就需要应对不断变化的下游系统。每一次下游接口变更,都需要订单模块重新上线,这对于一个核心系统来说,不可接受。
引入消息队列以后,订单服务在订单发生变化时,发送同一条消息到消息队列的一个主题Order中,所有的下游系统都订阅这个主题Order,这样每个下游系统都可以获得一份实时完整的订单数据,而且下游服务无论怎么变化,订单服务都无需为之更改,实现了订单服务和下游服务的解耦。
消息队列的优缺点
优点:
- 作为发布订阅系统实现一个微服务系统之间的观察者模式
- 连接六计算任务和数据
- 用于将消息广播给大量接收者
缺点:
- 引入消息队列带来链路过长,以及自身带来的延迟问题
- 增加了系统的复杂度
- 可能产生数据不一致的问题
怎么选取合适的消息队列?
作为一款及格的消息队列产品,必须具备以下的几个特征:
- 消息可靠传递
- Cluster:支持集群,确保不会因为某几个节点宕机导致不可用,也不能丢消息
- 性能:必须具备优良的性能,能满足绝大多数的场景需求