面试官:你的项目为什么要用消息队列?
共 2315字,需浏览 5分钟
·
2023-10-23 22:01
今天我们探讨一种广泛使用的中间件:消息队列。
消息队列由来已久,通常用于不同系统之间的通信。下图以星巴克的工作方式为例,来说明消息队列的概念。
在星巴克,收银员接受订单并收钱,然后把顾客的名字写在咖啡杯上,交给下一个步骤。咖啡制作师拿起订单和杯子制作咖啡。然后,顾客到柜台领取咖啡。这三个步骤同步进行。收银员只需将订单以咖啡杯的形式放入,无需等待订单完成。咖啡制作师只需将制作完成的咖啡放在柜台上,就可以去制作下一杯咖啡了,无需等待顾客取走。
这个过程的美妙之处在于每个步骤都是独立运行的,很像一个异步系统。
这种异步处理(每一步都无需等待前一步完成)大大提高了系统的吞吐量。例如,收银员在接受另一份订单之前,无需等待您的饮料制作完成。
01
一个秒杀的案例
我们来看一个真实系统的例子:电商中经常出现的秒杀。由于秒杀期间用户活跃度激增,会给系统带来很大压力。消息队列通常在后端优化中起着关键作用。
下图列出了一个简化的电子商务秒杀架构。这时我们还没有对其进行优化,只是简单列出了数据流。
-
步骤 1 和 2:客户向订单服务下订单。
-
步骤 3:在处理付款之前,订单服务会锁定该用户占用的库存。
-
步骤 4:订单服务向支付服务发送支付指令。支付服务向 3 个服务发送消息:支付渠道、通知服务和数据分析。
-
步骤 5.1 和 6.1:支付服务向外部支付通道发送支付指令。支付通道与外部支付服务提供商(Payment Service Provider, PSP)对话,最终完成交易。
-
步骤 5.2 和 6.2:支付服务向通知服务发送消息,然后通知服务通过电子邮件或短信向客户发送通知。
-
步骤 5.3:支付服务向数据分析服务发送交易详情。
在秒杀期间,无缝的用户体验至关重要。为了在高流量情况下保持服务响应速度,可以在系统多个阶段集成消息队列,以确保最佳性能。
02
使用消息队列优化秒杀系统
我们下面一步一步地优化这个秒杀系统,来看看消息队列给系统带来了什么好处。
扇出
扇出(fan out)这个概念来源于电子电路,是指由一个逻辑门的输出驱动几个下游逻辑门的输入,从而连接形成更复杂的电路。
支付服务将消息发送到三个下游服务,分别用于不同的目的:支付渠道、通知服务和数据分析。生产者(支付服务)只需将信息放到队列中,不同的消费者就可以按照自己的节奏处理信息。这种扇出简化了系统架构。
异步处理
以星巴克为例,正如收银员不会等待咖啡煮好一样,订单服务也不会等待付款最终完成。支付指令被置于队列中,一旦最终完成,客户就会收到通知。
流控
在秒杀活动中,可能会有数以万计的用户同时下订单。如何在满足客户需求和保持系统稳定之间取得平衡至关重要。
一种常见的方法是在特定时间段内对收到的请求数量设置上限,使其与系统容量相匹配。过多的请求可能会被拒绝或被要求在短暂延迟后重试。这种方法可确保系统保持稳定,不会不堪重负。对于成功通过的请求,消息队列可确保它们得到高效、有序的处理。如果系统的某个部分暂时滞后,订单也不会丢失。它将被保留在队列中,直到可以处理为止。
服务解耦
我们的设计在多处使用了消息队列。服务之间使用定义明确的消息接口进行交互,而不是彼此紧密依赖。每个服务都可以独立修改和部署。每个组件都可以用不同的编程语言开发。这为架构设计带来了灵活性。
横向可扩展性
由于服务是解耦的,因此我们可以根据业务需求对它们进行独立扩展。每个服务都能以不同的容量提供服务,因此我们可以根据其计划的 QPS(query per second)或 TPS(transaction per second)进行扩展。
消息持久性
消息队列也可用作存储消息的中间件。如果上游服务崩溃,下游服务总能从消息队列中拾取消息进行处理。这样,恢复功能就从每个服务中转移出来,交由消息队列负责。
批量处理
我们有时需要进行批量数据的处理。例如,当支付服务向数据分析服务发送消息时,数据分析服务并不需要执行实时更新,而是设置一个滚动窗口来批量处理窗口内的数据。批量处理是下游服务的要求,因此支付服务无需知道,只需将消息放入队列即可。消息定序 秒杀活动的库存商品数量是有限的。例如,秒杀只提供 10 部 iPhone,但下单的用户超过 10,000 人。我们该如何决定订单顺序呢?用消息队列来保存所有订单会有一个自然的顺序:队列中的前 10 位将获得 iPhone。
下图中显示了所有的优化点。服务通过消息队列连接并解耦。这样,架构就能实现更高的吞吐量。
历史好文: