在现代系统设计中,消息队列的使用为我们提供了几种显著的优势,这些优势包括:

  1. 异步处理机制
  2. 削峰与限流能力
  3. 降低系统耦合性

除了上述三个主要优点外,消息队列在其他许多场景中也得到了广泛应用,如实现分布式事务、确保顺序处理和数据流管理。

如果在面试过程中,面试官询问这个问题,通常是因为你在简历中提到了与消息队列相关的经验。建议结合自己的项目经历来详细回答。

异步处理机制

图片

通过异步处理来提升系统性能

在用户请求中涉及的耗时操作,可以通过消息队列实现异步处理。具体而言,当消息被发送到消息队列后,系统可以立即返回响应,从而减少用户的等待时间并提高用户体验。随后,系统会对消息进行处理。

尽管用户请求已经发送到消息队列并得到确认,但在后续的业务逻辑校验或数据库写入中,可能会出现失败的情况。因此,采用消息队列进行异步处理时,业务流程需要进行相应的调整。例如,在用户提交订单后,订单信息会写入消息队列,此时并不立即向用户返回订单提交成功的消息,而是等待消息队列中的订单消费者进程真正处理完该订单后,再通过电子邮件或短信通知用户订单成功,以避免潜在的交易纠纷。这种流程类似于我们在手机上订购火车票或电影票的体验。

削峰和限流能力

将短时间内高并发产生的事务消息先存储在消息队列中,后端服务则可以根据自身的处理能力逐步消费这些消息,从而避免对后端服务造成压力。

例如,在电子商务相关的秒杀或促销活动中,合理利用消息队列可以有效抵御活动开始时大量订单涌入对系统的冲击,如下图所示:

图片

降低系统耦合性

使用消息队列能够显著降低系统之间的耦合性。我们知道,如果模块之间没有直接调用关系,那么添加或修改某个模块对其他模块的影响就会较小,这无疑增强了系统的可扩展性。

在这样的架构中,生产者(客户端)将消息发送到消息队列,消费者(服务端)则按需从消息队列中获取消息进行处理。这种设计显然提高了系统的扩展性。

图片发布/订阅(Pub/Sub)模型

在消息队列中,采用发布-订阅模式进行操作,消息的发送者(生产者)负责发布消息,而一个或多个消息的接收者(消费者)则可以订阅这些消息。 从上图可以看出,消息发送者与消息接收者之间并没有直接的耦合关系。消息发送者将消息发送至分布式消息队列后即完成了对该消息的处理,而消息接收者则从分布式消息队列中获取消息进行后续处理,完全不需要了解消息的来源。对于新增的业务,只需对相关消息进行订阅,而不对原有系统或业务造成任何影响,从而实现网站业务的可扩展性设计。

例如,在我们的商城系统中,服务模块包括用户、订单、财务、仓储、消息通知、物流和风控等多个部分。当用户完成下单后,系统需要同时调用财务(进行扣款)、仓储(进行库存管理)、物流(进行发货)、消息通知(通告用户发货)和风控(进行风险评估)等服务。通过使用消息队列,下单操作与后续的扣款、发货和通知等操作是解耦的。用户下单时,会发送一个消息到消息队列,相关服务只需订阅该消息即可获取信息。

图片为防止消息队列服务器宕机导致消息丢失,成功发送到消息队列的消息会被保留在消息生产者的服务器上,直到消息被消费者服务器处理后再删除。当消息队列服务器宕机时,生产者可以选择在分布式消息队列服务器集群中的其他服务器上发布消息。

备注: 不要误以为消息队列仅支持发布-订阅模式。在某些特定业务环境下,为了实现解耦才采用这种模式。除了发布-订阅模式,还有点对点订阅模式(即每条消息仅有一个消费者)等其他模式。我们常用的还是发布-订阅模式。此外,JMS提供了这两种消息模型,而AMQP协议还提供了另外五种消息模型。

实现分布式事务

解决分布式事务的一种方案就是MQ事务。

如RocketMQ、Kafka、Pulsar和QMQ等都提供与事务相关的功能。事务允许事件流应用将消费、处理和生产消息的整个过程定义为一个原子操作。

RocketMQ的事务消息原理如下图所示:

图片

顺序保证

在许多应用场景中,数据处理的顺序至关重要。消息队列能够确保数据按照特定顺序进行处理,非常适合那些对数据顺序有严格要求的环境。大部分消息队列,如RocketMQ、RabbitMQ、Pulsar和Kafka,均支持顺序消息功能。

延时和定时处理

消息在发送后不会被立即消费,而是会被设定一个时间,待时间到达后再进行消费。大多数消息队列,如RocketMQ、RabbitMQ、Pulsar和Kafka,都支持定时和延时消息的处理。

图片

数据流处理

对于分布式系统产生的大量数据流,比如业务日志、监控数据和用户行为等,消息队列可以实时或批量收集这些数据,并将其导入大数据处理引擎中,实现高效的数据流管理和处理。