消息队列 | 青训营

110 阅读3分钟

消息队列的前世今生

应用场景

案例一:系统崩溃

例如,在抖音直播间购买商品背后的操作流程。

graph LR
搜索直播间 --> 搜索行为记录 --> 点击商品 -->点击行为记录;
搜索行为记录 --> 记录存储;
点击行为记录 --> 记录存储;

当我们搜索抖音直播间时,会产生搜索行为的记录;当我们点击商品时,会产生点击行为记录;我们需要将搜索行为和点击行为的记录存储在远端服务器上。

但是,如果用于存储记录的服务器出现故障,就会导致「记录存储」环节失效,进而导致整个操作链路无法正常运行。那么我们该如何处理系统崩溃的情况?

案例二:过量请求

例如,当我们选择好商品准备发起订单购买的时候,可能会有多个用户同时发起订单请求购买同一件商品,但是我们的处理订单的服务端只有同时处理10个订单请求的能力,这就超出了我们的业务能力范围,导致出现服务过载,表现在用户身上就是漫长的等待与卡顿。

graph LR
客户1 --> 发起订单
客户2 --> 发起订单
客户3 --> 发起订单
发起订单 --> 处理订单

我们该如何解决短时间内高并发导致服务过载的情况?

案例三:链路耗时长尾

当用户发起订单后,处理订单的服务端的处理流程如下:

graph LR
用户 --> 发起订单 --> 库存记录-1 --> 订单记录+1 --> 通知商家 --> 用户

服务端在发起订单,更新库存记录,更新订单记录的过程中耗时较短,但是在通知商家的过程中需要消耗较长的时间,因此,在订单处理的操作链路上,链路的尾部消耗了过长的时间,导致用户需要等待,使用户体验大大降低。

我们如何处理链路耗时出现长尾的情况?

案例四:日志存储

我们需要一个服务来存储服务器的日志,用于将服务器恢复系统崩溃之前的状态,这也是我们需要考虑的问题。

解决方案

案例一:解耦

我们可以将所有的行为记录发送到消息队列上,然后让存储服务对消息队列中的内容进行消费,此时行为记录和存储服务是异步处理的。在这种情况下,如果存储服务出现故障,行为记录也可以不受影响地将数据发送到消息队列中,而不会使用户操作流程发生阻塞;当存储服务重新上线后,也可以继续消费消息队列中积压的内容。

graph LR
搜索直播间 --> 搜索行为记录 --> 点击商品 -->点击行为记录;
搜索行为记录 --> 消息队列;
点击行为记录 --> 消息队列;
消息队列 --> 存储服务

案例二:削峰

我们将大量的订单请求先发送到消息队列中,然后再根据服务的处理能力对消息队列中的订单请求进行消费,消息队列起到了缓存的作用。

graph LR
客户1 --> 发起订单
客户2 --> 发起订单
客户3 --> 发起订单
发起订单 --> 消息队列
消息队列 --> 处理订单

案例三:异步

我们可以使用消息队列收集订单请求,然后并发进行订单记录修改、库存记录修改和通知商家三个操作,将同步操作变为异步操作,避免用户端出现过长的等待时间。

graph LR
用户 --> 发起订单 --> 消息队列
消息队列 --> 库存记录-1 
消息队列 --> 订单记录+1
消息队列 --> 通知商家

案例四:日志存储

使用消息队列存储本地日志,再通过日志处理组件处理日志。

graph LR
Log --> 消息队列 --> LogStash --> ES --> Kibana

消息队列

保存消息的一个容器,本质是一个队列,并且需要支持高吞吐、高并发、高可用。

graph LR
生产 --> Message1Message2Message3Message4 --> 消费

主流的消息队列有:Kafka、BMQ、RocketMQ、Pulsar

  • Kafka:分布式、分区、多副本的日志提交服务
  • RocketMQ:低延迟、强一致、高性能、高容量、灵活性的实时消息队列
  • Pulsar:云原生分布式消息流平台,具有轻量化函数式计算功能
  • BMQ:高吞吐的离线业务场景