【消息队列】


前言

在现代分布式系统中,消息队列已经成为了一种非常重要的组件。消息队列可以实现异步通信、解耦、削峰填谷等功能,可以提高系统的可靠性、可扩展性和可维护性。目前市面上常见的消息队列中间件主要有ActiveMQ、RabbitMQ、Kafka、RocketMQ这几种,在架构技术选型的时候一般根据业务的需求选择合适的中间件:比如中小型公司,低吞吐量的一般用ActiveMQ、RabbitMQ较为合适,大数据高吞吐量的大型公司一般选用Kafka和RocketMQ。以下总结了MQ最基础的知识点, 希望通过阅读后,可以对MQ有一个基本的认知;


一、MQ是什么?

消息队列Message Queue,简称MQ。是一种应用间的通信方式,主要由三个部分组成
在这里插入图片描述

  • 生产者(Producer ) : 消息的产生者与调用端(通过API调用直接发送消息来向队列发送消息),主要负责消息所承载的业务信息的实例化是一个队列的发起方;
  • 代理(Broker):主要的处理单元,负责消息的存储、投递、及各种队列附加功能的实现,是消息队列最核心的组成部分
  • 消费者(Consumer ):一个消息队列的终端也是消息的调用端,具体是根据消息承载的信息,处理各种业务逻辑。

二、MQ的应用场景及案例分析

1. 异步处理
主要应用于对实时性要求不严格的场景,比如:用户注册发送验证码、下单通知、发送优惠券等等。服务方只需要把协商好的消息发送到消息队列,剩下的由消费消息的服务去处理,不用等待消费服务返回结果。
在这里插入图片描述

  • 1.1 使用消息队列的异步处理和使用多线程的区别?
    使用消息队列时,生产者将消息发送到队列中,消费者从队列中获取消息并进行处理。这种方式可以实现解耦,因为生产者和消费者之间没有直接的依赖关系。消息队列还可以提供可靠性和可扩展性,因为它们可以处理高负载和高并发的情况。
    使用多线程时,应用程序可以同时执行多个任务。这些任务可以在同一进程中运行,也可以在不同的进程中运行。多线程可以提高应用程序的响应速度和吞吐量,因为它们可以同时处理多个请求。因此,使用消息队列和多线程的选择取决于具体的应用场景。如果需要**解耦和可靠性,可以使用消息队列。如果需要提高响应速度和吞吐量,可以使用多线程。**当然,这两种方式也可以结合使用,以实现更高效的异步处理。

  • 1.2 案例分析
    我们经常会遇到这样业务场景:用户注册成功后,给它发个短信和发个邮件。
    如果注册信息入库30ms,发短信30ms、邮件也30ms,三个动作串行执行的话,会比较耗时,响应 90ms
    在这里插入图片描述
    如果采用并行执行的方式,可以减少响应时间。注册信息入库后,同时异步发短信和邮件。如何实现异步呢,用消息队列即可,注册信息入库成功后,写入到消息队列(这个一般比较快,如只需要 3ms),然后异步读取发邮件和短信。
    在这里插入图片描述

2. 应用解耦
应用解耦可以看作是把相关但耦合度不高的系统联系起来。比如订单系统与WMS(库存系统),
有关联但不哪么紧密,每个系统之间只需要把约定的消息发送到MQ,另外的系统去消费即可。解决了各个系统可以采用不同的架构、语言来实现,从而大大增加了系统的灵活性。

  • 2.1 案例分析:
    举个常见业务场景:下单扣库存,用户下单后,订单系统去通知库存系统扣减。
    传统做法就订单系统直接调用库存系统:
    在这里插入图片描述

  • 如果库存系统无法访问,下单就会失败,订单和库存系统存在耦合关系;

  • 如果业务又接入一个营销积分服务,那订单下游系统要扩充,如果未来接入越来越多下游系统,那订单系统代码需要经常修改
    在这里插入图片描述
    **如何解决这个问题呢?**可以引入消息队列
    在这里插入图片描述

  1. 订单系统:用户下单后,消息写入到消息队列,返回下单成功。
  2. 库存系统:订阅下单消息,获取下单信息,进行库存操作。

3. 流量削峰
流量削峰一般应用在大流量入口且短时间内业务需求处理不完的服务中心,为了权衡高可用,把大量的并行任务发送到MQ中,依据MQ的存储及分发功能,平稳的处理后续的业务,起到一个大流量缓冲的作用。
在这里插入图片描述

  • 3.1 案例分析:
    流量削峰也是消息队列的常用场景。我们做秒杀实现的时候,需要避免流量暴涨,打垮应用系统风险。可以在应用前面加入消息队列。
    在这里插入图片描述
    假设秒杀系统每秒最多可以处理 2k个请求,每秒却有 5k请求过来,可以引入消息队列,秒杀系统每秒从消息队列拉 2k 请求处理。
    有些伙伴担心这样会出现消息积压问题,
  • 首先秒杀活动不会每时每刻都那么多请求过来,高峰期过去后,积压请求可以慢慢处理;
  • 其次,如果消息队列长度超过最大数量,可以直接抛弃用户请求或跳转到错误页面;

三、消息队列如何解决消息丢失问题?

一个消息从生产者产生,到被消费者消费,主要经过这 3 个过程:
在这里插入图片描述
因此如何保证 MQ 不丢失消息,可以从这三个阶段阐述:

  • 生产者保证不丢消息
  • 存储端不丢消息
  • 消费者不丢消息

3.1 生产者保证不丢消息
生产端如何保证不丢消息呢?确保生产的消息能到达存储端。如果RocketMQ 消息中间件,Producer 生产者提供了三种发送消息的方式,分别为:

  • 同步发送
  • 异步发送
  • 单向发送
    生产者要想发消息时保证消息不丢失,可以:
  • 采用同步方式发送,send 消息方法返回成功状态,就表示消息正常到达了存储端Broker。
  • 如果 send 消息异常或者返回非成功状态,可以重试。
  • 可以使用事务消息,RocketMQ 事务消息机制就为了保证零丢失来设计。

3.2 存储端不丢消息
如何保证存储端消息不丢失呢? 确保消息持久化到磁盘。大家很容易想到就刷盘机制。
刷盘机制分同步刷盘异步刷盘

  • 生产者消息发过来时,只有持久化到磁盘,RocketMQ 存储端 Broker 才返回一个成功 的ACK 响应,这就同步刷盘。它保证消息不丢失,但影响了性能。
  • 异步刷盘话,只要消息写入 PageCache 缓存,就返回一个成功的 ACK(确认消息) 响应。这样提高了 MQ 的性能,但是如果这时候机器断电了,就会丢失消息。

Broker 一般集群部署,有 master 主节点和 slave 从节点。消息到Broker 存储端,只有主节点和从节点都写入成功,才反馈成功 ack 给生产者。这就是同步复制,它保证了消息不丢失,但降低了系统吞吐量。与之对应的就是异步复制,只要消息写入主节点成功,就返回成功ack,它速度快,但是会有性能问题。

3.3 消费阶段不丢消息
消费者执行完业务逻辑,再反馈会 Broker 说消费成功,这样才可以保证消费阶段不丢消息。


四、消息队列如何保证消息的顺序性

消息的有序性,就是指可以按照消息的发送顺序来消费。有些业务对消息的顺序有要求,比如先下单再付款,最后再完成订单,这样等。假设生产者先后产生了两条消息,分别是下单消息(M1),付款消息(M2),M1 比 M2先产生,如何保证 M1 比 M2 先被消费呢?
在这里插入图片描述为了保证消息的顺序性,可以将将 M1、M2 发送到同一个 Server 上,当 M1发送完收到 ack 后,M2 再发送, 这样确保了M1优先比M2进入消息队列。如下图
在这里插入图片描述
这样还可能会有问题,因为从 MQ 服务器到服务端,可能存在网络延迟,虽然 M1 先发送,但是它比 M2 晚到,如下图
在这里插入图片描述
那还能怎么办才能保证消息的顺序性呢?将 M1 和 M2 发往同一个消费者,且发送M1 后,等到消费端 ACK 成功后,才发送M2 就可以了;
在这里插入图片描述
消息队列保证顺序性整体思路就这样啦。比如 Kafka 的全局有序消息,就是这种思想的体现: 生产者发消息时,1 个 Topic只能对应 1 个 Partition, 一个 Consumer,内部单线程消费。但是这样吞吐量会低,一般保证消息局部有序即可。在发消息的时候指定Partition Key,Kafka 对其进行Hash 计算,根据计算结果决定放入哪个Partition。这样 Partition Key 相同的消息会放在同一个 Partition。然后多消
费者单线程消费指定的Partition。

五、如何理解消息队列中的ACK

在消息队列中,ack是指确认消息已经被消费者(或者订阅者)成功接收的信号。当一个消费者从消息队列中获取一条消息时,它需要对这条消息进行处理,处理完成后需要向消息队列发送一个ack信号,告诉消息队列这条消息已经被成功处理了。这个过程也被称为消息确认。

消息队列中的ack机制可以确保消息的可靠性和一致性。如果一个消费者在处理消息时出现了错误,它可以选择不发送ack信号,这样消息队列就会认为这条消息没有被成功处理,然后将它重新发送给其他消费者。这样可以确保消息不会丢失,并且可以保证每条消息只会被处理一次。

需要注意的是,不同的消息队列实现可能会有不同的ack机制。例如,有些消息队列可能会使用显式的ack机制,而有些消息队列可能会使用隐式的ack机制。在使用消息队列时,需要了解具体的实现细节,以便正确地处理消息确认。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值