• 每日五问(java)


    1.什么是消息队列

    你可以把消息队列理解为一个使用队列来通信的组件。它的本质,就是个转发器,包含发消息、存消息、消费消息的过程。最简单的消息队列模型如下:
    在这里插入图片描述
    我们通常说的消息队列,简称MQ(Message Queue),它其实就指消息中间件,当前业
    界比较流行的开源消息中间件包括:RabbitMQ、RocketMQ、Kafka。

    2… 消息队列有哪些使用场景

    (1)应用解耦
    举个常见业务场景:下单扣库存,用户下单后,订单系统去通知库存系统扣减。传统的做法就是订单系统直接调用库存系统:
    在这里插入图片描述
    如果库存系统无法访问,下单就会失败,订单和库存系统存在耦合关系如果业务又接入一个营销积分服务,那订单下游系统要扩充,如果未来接入越来越多的下游系统,那订单系统代码需要经常修改
    在这里插入图片描述
    引入消息队列就可解决该种问题
    在这里插入图片描述
    订单系统:用户下单后,消息写入到消息队列,返回下单成功
    库存系统:订阅下单消息,获取下单信息,进行库存扣减操作
    (2)流量削峰
    流量削峰也是消息队列的常用场景。我们做秒杀实现的时候,需要避免流量暴涨,打垮应用系统的风险。可以在应用前面加入消息队列。
    在这里插入图片描述
    假设秒杀系统每秒最多可以处理2k个请求,每秒却有5k的请求过来,可以引入消息队列,秒杀系统每秒从消息队列拉2k请求处理得了。有些伙伴担心这样会出现消息积压的问题,
    首先秒杀活动不会每时每刻都那么多请求过来,高峰期过去后,积压的请求可以慢慢处理;
    其次,如果消息队列长度超过最大数量,可以直接抛弃用户请求或跳转到错误页面;
    (3)异步处理
    我们经常会遇到这样的业务场景:用户注册成功后,给它发个短信和发个邮件。
    如果注册信息入库是30ms,发短信、邮件也是30ms,三个动作串行执行的话,会比较耗
    时,响应90ms:
    在这里插入图片描述
    如果采用并行执行的方式,可以减少响应时间。注册信息入库后,同时异步发短信和邮件。如何实现异步呢,用消息队列即可,就是说,注册信息入库成功后,写入到消息队列(这个一般比较快,如只需要3ms),然后异步读取发邮件和短信。

    在这里插入图片描述
    (4)消息通讯
    消息队列内置了高效的通信机制,可用于消息通讯。如实现点对点消息队列、聊天室等。

    3.消息队列如何解决消息丢失问题?

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

    (1)生产者保证不丢消息
    生产端如何保证不丢消息呢?确保生产的消息能到达存储端。
    如果是RocketMQ消息中间件,Producer生产者提供了三种发送消息的方式,分别是:
    同步发送
    异步发送
    单向发送
    生产者要想发消息时保证消息不丢失,可以:采用同步方式发送,send消息方法返回成功状态,就表示消息正常到达了存储Broker。
    如果send消息异常或者返回非成功状态,可以重试。
    可以使用事务消息,RocketMQ的事务消息机制就是为了保证零丢失来设计的
    (2)存储端不丢消息
    如何保证存储端的消息不丢失呢?确保消息持久化到磁盘。大家很容易想到就是刷盘机制。
    刷盘机制分同步刷盘和异步刷盘:
    生产者消息发过来时,只有持久化到磁盘,RocketMQ的存储端Broker才返回一个成功的
    ACK响应,这就是同步刷盘。它保证消息不丢失,但是影响了性能。
    异步刷盘的话,只要消息写入PageCache缓存,就返回一个成功的ACK响应。这样提高了MQ的性能,但是如果这时候机器断电了,就会丢失消息。

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

    4.消息队列如何保证消息的顺序性。

    消息的有序性,就是指可以按照消息的发送顺序来消费。有些业务对消息的顺序是有要求
    的,比如先下单再付款,最后再完成订单,这样等。假设生产者先后产生了两条消息,分别
    是下单消息(M1),付款消息(M2),M1比M2先产生,如何保证M1比M2先被消费
    呢。
    在这里插入图片描述
    为了保证消息的顺序性,可以将M1、M2发送到同一个Server上,当M1发送完收到ack
    后,M2再发送。如图:
    在这里插入图片描述
    这样还是可能会有问题,因为从MQ服务器到消费端,可能存在网络延迟,虽然M1先发
    送,但是它比M2晚到。
    在这里插入图片描述
    那还能怎么办才能保证消息的顺序性呢?将M1和M2发往同一个消费者,且发送M1后,等到消费端ACK成功后,才发送M2就得了。
    在这里插入图片描述
    消息队列保证顺序性整体思路就是这样啦。比如Kafka的全局有序消息,就是这种思想的体
    现: 就是生产者发消息时,1个Topic只能对应1个Partition,一个 Consumer,内部单线程消费。
    但是这样吞吐量太低,一般保证消息局部有序即可。在发消息的时候指定Partition Key,Kafka对其进行Hash计算,根据计算结果决定放入哪个Partition。这样Partition Key相同的消息会放在同一个Partition。然后多消费者单线程消费指定的Partition。
    5.消息队列有可能发生重复消费,如何避免,如何做到幂等?
    消息队列是可能发生重复消费的。
    生产端为了保证消息的可靠性,它可能往MQ服务器重复发送消息,直到拿到成功的ACK。再然后就是消费端,消费端消费消息一般是这个流程:拉取消息、业务逻辑处理、提交消费位移。假设业务逻辑处理完,事务提交了,但是需要更新消费位移时,消费者却挂了,这时候另一个消费者就会拉到重复消息了。如何幂等处理重复消息呢?幂等处理重复消息,简单来说,就是搞个本地表,带唯一业务标记的,利用主键或者唯一性索引,每次处理业务,先校验一下就好啦。又或者用redis缓存下业务标记,每次看下是否处理过了。

  • 相关阅读:
    ESP32网络开发实例-Web服务器RGB LED调光
    【水滴计划】:盛最多水的容器、移除元素
    链栈的基本操作c语言
    爬虫 — Bs4 数据解析
    面对以太坊合并,投资者有哪些参与策略?
    [山东科技大学OJ]1216 Problem D: 编写函数:字符串的复制 之二 (Append Code)
    给LaTeX公式添加优美的注解;日更『数据科学』面试题集锦;大学生『计算机』自学指南;个人防火墙;前沿资料/论文 | ShowMeAI资讯日报
    打造自己的前端组件库(奶妈版,超详细)
    目标跟踪(1)SORT Windows实战+代码解析
    (原创)【MAUI】一步一步实现“悬浮操作按钮”(FAB,Floating Action Button)
  • 原文地址:https://blog.csdn.net/Nicholas_giao/article/details/127978400