消息队列的前世今生
应用场景
案例一:系统崩溃
例如,在抖音直播间购买商品背后的操作流程。
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:高吞吐的离线业务场景