MQ面试题

为什么要使用消息队列?

优点:解耦、异步、流量削峰
缺点:可用性降低、复杂性提高、一致性问题

为什么选择了RabbitMQ而不是其它的MQ?

kafka是以吞吐量高而闻名,不过其数据稳定性一般,而且无法保证消息有序性。我们公司的日志收集也有使用,业务模块中则使用的RabbitMQ。
阿里巴巴的RocketMQ基于Kafka的原理,弥补了Kafka的缺点,继承了其高吞吐的优势,其客户端目前以Java为主。但是我们担心阿里巴巴开源产品的稳定性,所以就没有使用。
RabbitMQ基于面向并发的语言Erlang开发,吞吐量不如Kafka,但是对我们公司来讲够用了。而且消息可靠性较好,并且消息延迟极低,集群搭建比较方便。支持多种协议,并且有各种语言的客户端,比较灵活。Spring对RabbitMQ的支持也比较好,使用起来比较方便,比较符合我们公司的需求。
综合考虑我们公司的并发需求以及稳定性需求,我们选择了RabbitMQ。

activeMQRabbitMQRocketMQKafka
性能6000/单机12000/单机10万/单机100万/单机
持久化都支持(性能会下降)都支持(性能会下降)天生支持天生支持
多语言支持主流都支持主流都支持只支持Java主流都支持
优缺点缺乏大规模运用,不推荐消息可靠性高,功能全面,吞吐量比较低,消息积累会影响性能高吞吐,高性能,高可用,功能全面。缺点:会丢数据、功能单一
使用场景缺乏大规模运用,不推荐企业内部小规模系统调用几乎全场景,特别适合金融级mq场景日志分析、大数据采集

RabbitMQ一个queue中存放的message是否有数量限制?

默认情况下一般无限制。
但是可以通过x-max-length对队列中消息的条数进行限制;
x-max-length-bytes对队列中消息的总量进行限制,比如200mb。

RabbitMQ事务机制?

RabbitMQ事务机制和确认机制

public class RabbitMqTransactionExample {
    private static final String QUEUE_NAME = "queue_name";

    public static void main(String[] args) {
        try {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("localhost");
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();

            // 开启事务
            channel.txSelect();

            String message = "Hello, RabbitMQ!";

            // 发布消息到队列
            channel.basicPublish("", QUEUE_NAME, null, message.getBytes());

            // 提交事务
            channel.txCommit();
            System.out.println("Message sent successfully");
        } catch (Exception e) {
            // 回滚事务
            channel.txRollback();
            System.out.println("Failed to send message");
            e.printStackTrace();
        }
    }
}

RabbitMQ确保消息可靠性传输?

Rabbitmq 的持久化分为队列持久化、消息持久化和交换机持久化。

1,队列持久化

在定义队列时的通过 durable 参数来决定的
在这里插入图片描述

2,交换机持久化

durable:持久话标志位, durable 设置为 true 表示持久化, 反之为非持久,与队列持久化相同

3,消息持久化

deliveryMode=1 代表不持久化,deliveryMode=2 代表持久化

@Component
public class MessageSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendMessage(String message) {
        MessageProperties properties = new MessageProperties();
        properties.setDeliveryMode(MessageDeliveryMode.PERSISTENT); // 设置消息持久化
        Message rabbitMessage = new Message(message.getBytes(), properties);
        rabbitTemplate.send("exchangeName", "routingKey", rabbitMessage);
    }
}

4,主从备份

消息到达队列后,MQ宕机也可能导致丢失消息,RabbitMQ提供了持久化功能,集群的主从备份功能

5,生产者消息确认:publisher confirm机制、publisher return机制

5.1,修改publisher服务中的application.yml文件

spring:
   rabbitmq:
	 username: guest
	 password: guest
	 virtual-host: /
	 host: 123.123.123.123
	 port: 5672
	 publisher-confirm-type: simple
	 publisher-returns: true
	 listener:
	   simple:
	     acknowledge-mode: auto # 手动应答
	     prefetch: 1 #每次从队列中取一个,轮询分发,默认是公平分发
	     retry:
	       enabled: true # 开启重试
	       initial-interval: 1000 # 初识的失败等待时长为1秒
	       multiplier: 2 # 失败的等待时长倍数
	       max-attempts: 5 # 重试次数
	   

publish-confirm-type:开启publisher-confirm,这里支持两种类型:
simple:同步等待confirm结果,直到超时
correlated:异步回调,定义ConfirmCallbackMQ返回结果时会回调这个ConfirmCallback

publish-returns:开启publish-return功能,同样是基于callback机制,不过是定义ReturnCallback
template.mandatory:定义消息路由失败时的策略。true,则调用ReturnCallbackfalse:则直接丢弃消息

5.2,ReturnCallback,交换机到队列

@Slf4j
@Configuration
public class CommonConfig implements ApplicationContextAware {
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 获取RabbitTemplate
        RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);
        // 设置ReturnCallback
        //alt+enter 可以将匿名内部类改成lamda表达式
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            // 投递失败,记录日志
            //当发送时设置错误的routingKey;成功到交换机但未到队列
            // 消息成功投递到交换机!消息ID: 4ccec7ec-a95e-4660-afe3-1370bcde7904
            // 消息发送到队列失败,响应码:312, 失败原因:NO_ROUTE, 交换机: amq.topic, 路由key:ssimple.test
            log.info("消息发送失败,应答码{},原因{},交换机{},路由键{},消息{}",
                     replyCode, replyText, exchange, routingKey, message.toString());
            // 如果有业务需要,可以重发消息
        });
    }
}

5.3,定义ConfirmCallback,发送端到交换机

@Component
public class RabbitMQMessageSender  implements MQMessageSender, RabbitTemplate.ConfirmCallback{
  private final RabbitTemplate rabbitTemplate;
  Log log = LogFactory.getLog(RabbitMQMessageSender.class);
  @Autowired
  public RabbitMQMessageSender(RabbitTemplate rabbitTemplate) {
    this.rabbitTemplate = rabbitTemplate;
  }

  @PostConstruct
  public void init(){
    rabbitTemplate.setConfirmCallback(this);
  }

  @Override
  public void confirm(CorrelationData correlationData, boolean ack, String cause) {
    if(!ack){
      log.error("消息接收失败" + cause);
      // 我们这里要做一些消息补发的措施
      System.out.println("id="+correlationData.getId());
    }
  }

  public void send(String routingKey, MQMessage msg) {
    String jsonString = JsonConverter.bean2Json(msg);
    if (jsonString != null) {
      try {
        rabbitTemplate.convertAndSend(routingKey, jsonString);
      } catch (Exception e) {
        // 连接异常,发送日志
        log.error("Failed to send message RabbitMQ Exception: " + e.getMessage());
      }
    }
  }
}

6,消费者消息确认机制

spring:
   rabbitmq:
	 username: guest
	 password: guest
	 virtual-host: /
	 host: 123.123.123.123
	 port: 5672
	 publisher-confirm-type: simple
	 publisher-returns: true

	 # 消费者确认机制
	 listener:
	   simple:
	   	 # 将消费者确认机制设置成auto,会利用aop原理,当mq消息发送失败时重试
	     acknowledge-mode: auto
	     prefetch: 1 #每次从队列中取一个,轮询分发,默认是公平分发
	     retry:
	       enabled: true # 开启重试
	       initial-interval: 1000 # 初识的失败等待时长为1秒
	       multiplier: 2 # 失败的等待时长倍数
	       max-attempts: 5 # 重试次数
6.1,消费失败重试机制
# 重试达到最大次数后,Spring会返回ack,消息会被丢弃
spring:
  rabbitmq:
    listener:
      simple:
      	prefetch: 1
        acknowledge-mode: auto
        retry:
          enabled: true # 开启消费者失败重试
          initial-interval: 1000 # 初识的失败等待时长为1秒
          multiplier: 2 # 失败的等待时长倍数,下次等待时长 = multiplier * last-interval,相当于第1秒重试,第3秒重试,第7秒重试
          max-attempts: 3 # 最大重试次数
          stateless: true # true无状态;false有状态。如果业务中包含事务,这里改为false
6.2,达到最大重试次数后,失败策略

多次重试失败后将消息投递到异常交换机(死信交换机),交由人工处理

失败策略详解
RejectAndDontRequeueRecoverer重试耗尽后,直接reject,丢弃消息。默认就是这种方式
ImmediateRequeueMessageRecoverer重试耗尽后,返回nack,消息重新入队
RepublishMessageRecoverer重试耗尽后,将失败消息投递到指定的交换机

RabbitMQ交换机类型?

交换机类型解释举例
Fanout广播模式将消息交给所有绑定这个交换机的队列不同queue绑定一个Exchange
Direct定向模式把消息交给符合指定routing key的队列比如一个消费端key = {“red”, “blue”},另一个消费端key = {“red”, “yellow”},当发送端rabbitTemplate.convertAndSend(exchangeName, “red”, message)时,两个消费端都可以收到消息
Topic通配符模式判断routing key的规则是模糊匹配模式消费端1:key = “china.#” 消费端2:key = “#.news”,发送端:rabbitTemplate.convertAndSend(exchangeName, “china.news”, message); #:代表0个或多个词*:代表1个词

RabbitMQ是否可以直接将消息推送到队列?

可以,但不推荐,丧失灵活性

RabbitMQ如何避免消息堆积?

消息堆积问题产生的原因往往是因为消息发送的速度超过了消费者消息处理的速度。因此解决方案无外乎以下三点:
1,提高消费者处理速度 2,增加更多消费者 3,增加队列消息存储上限

1,提高消费者处理速度
消费者处理速度是由业务代码决定的,所以我们能做的事情包括:
尽可能优化业务代码,提高业务性能
接收到消息后,开启线程池,并发处理多个消息
优点:成本低,改改代码即可
缺点:开启线程池会带来额外的性能开销,对于高频、低时延的任务不合适。适合任务执行周期较长的业务。

2,增加更多消费者
一个队列绑定多个消费者,共同争抢任务,自然可以提供消息处理的速度。
优点:能用钱解决的问题都不是问题。实现简单粗暴
缺点:问题是没有钱。成本太高

3,增加队列消息存储上限
在RabbitMQ的1.8版本后,加入了新的队列模式:Lazy Queue惰性队列
这种队列不会将消息保存在内存中,而是在收到消息后直接写入磁盘中,理论上没有存储上限。可以解决消息堆积问题。
优点:磁盘存储更安全;存储无上限;避免内存存储带来的Page Out问题,性能更稳定;
缺点:磁盘存储受到IO性能的限制,消息时效性不如内存模式,但影响不大。

RabbitMQ如何保证消息的有序性?

其实RabbitMQ是队列存储,天然具备先进先出的特点,只要消息的发送是有序的,那么理论上接收也是有序的。不过当一个队列绑定了多个消费者时,可能出现消息轮询投递给消费者的情况,而消费者的处理顺序就无法保证了。
因此,要保证消息的有序性,需要做的下面几点:
保证消息发送的有序性
保证一组有序的消息都发送到同一个队列
保证一个队列只包含一个消费者

如何防止MQ消息被重复消费?

消息重复消费的原因多种多样,不可避免。所以只能从消费者端入手,只要能保证消息处理的幂等性就可以确保消息不被重复消费。
而幂等性的保证又有很多方案:
给每一条消息都添加一个唯一id,在本地记录消息表及消息状态,处理消息时基于数据库表的id唯一性做判断
同样是记录消息表,利用消息状态字段实现基于乐观锁的判断,保证幂等
基于业务本身的幂等性。比如根据id的删除、查询业务天生幂等;新增、修改等业务可以考虑基于数据库id唯一性、或者乐观锁机制确保幂等。本质与消息表方案类似。

如何保证RabbitMQ的高可用?

要实现RabbitMQ的高可用无外乎下面两点:
做好交换机、队列、消息的持久化
搭建RabbitMQ的镜像集群,做好主从备份。当然也可以使用仲裁队列代替镜像集群。

使用MQ可以解决那些问题?

RabbitMQ能解决的问题很多,例如:
解耦合:将几个业务关联的微服务调用修改为基于MQ的异步通知,可以解除微服务之间的业务耦合。同时还提高了业务性能。
流量削峰:将突发的业务请求放入MQ中,作为缓冲区。后端的业务根据自己的处理能力从MQ中获取消息,逐个处理任务。流量曲线变的平滑很多
延迟队列:基于RabbitMQ的死信队列或者DelayExchange插件,可以实现消息发送后,延迟接收的效果。

RabbitMQ模型?

以下两种模型一条消息,只能被一个consumer消费

队列类型解释举例
BasicQueue 简单队列模型只有1个消费者
WorkQueue任务模型多个消费者 但是只有1个消费者消费消息多个消费端绑定一个queue,@RabbitListener(queues = “simple.queue”) listener1和@RabbitListener(queues = “simple.queue”) listener2

发布/订阅(以下三种模式可以多个消费者同时消费

交换机类型解释举例
Fanout广播模式将消息交给所有绑定这个交换机的队列不同queue绑定一个Exchange
Direct定向模式把消息交给符合指定routing key的队列比如一个消费端key = {“red”, “blue”},另一个消费端key = {“red”, “yellow”},当发送端rabbitTemplate.convertAndSend(exchangeName, “red”, message)时,两个消费端都可以收到消息
Topic通配符模式判断routing key的规则是模糊匹配模式消费端1:key = “china.#” 消费端2:key = “#.news”,发送端:rabbitTemplate.convertAndSend(exchangeName, “china.news”, message); #:代表0个或多个词*:代表1个词

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/576003.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

关于Android中的限定符

很多对于Android不了解或是刚接触Android的初学者来说,对于Android开发中出现的例如layout-large或者drawable-xxhdpi这样的文件夹赶到困惑,这这文件夹到底有什么用?什么时候用?这里简单的说一下。 其实,在上面例子中&…

day05 51单片机-外部中断、定时器

1 外部中断——按键控制LED亮灭 1.1 需求描述 本案例通过检测SW3触发的外部中断实现P00对应LED的亮灭。 1.2 硬件设计 1.2.1 中断简介 单片机中断是一种重要的计算机编程概念,用于处理在程序执行过程中突然发生的事件或条件。这些事件可以是外部硬件触发的,如按下按钮、…

SpringBoot+vue开发记录(二)

说明:本篇文章的主要内容为SpringBoot开发中后端的创建 项目创建: 1. 新建项目: 如下,这样简单创建就行了,JDK什么的就先17,当然1.8也是可以的,后面可以改。 这样就创建好了: 2. pom.xml…

【面试经典 150 | 回溯】电话号码的字母组合

文章目录 写在前面Tag题目来源解题思路方法一:回溯 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更…… 专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾…

IOTE2024第二十一届(上海)国际物联网展览会4月24日-26日开幕

交流产业信息,把脉发展方向,IOTE 国际物联网展是每年物联网行业、企业、用户交流合作的大型平台。2024年4月24-26日IOTE2024第二十一届国际物联网展•上海站,在上海世博展览馆开展。 本次物联网展汇聚全球超300家参展企业、3万来自工业、物流…

区块链技术与应用学习笔记(1-4节)——北大肖臻课程

目录 1. 区块链初识(课程简介) 被过度炒作,落地应用有限? 下一代的价值互联网?世界上最慢的数据库? 2. BTC-密码学原理(比特币) 1)哈希 哈希函数特点 个人学习所得 2)签名 个人对于…

工业测径仪的应用场景和可靠性判断

关键字:线缆测径仪,圆棒测径仪,圆管测径仪,金属棒管测径仪,工业测径仪,智能测径仪 智能测径仪主要应用于以下领域: 金属加工:测量金属线材、棒材、管材等的直径。线缆制造:检测电线、电缆的直径。塑料管材生产:监控塑料管材的外…

Python 数组控件的使用

当一个UI窗口界面内有多个相同类型的控件,且这多个控件的功能都类似时,使用数组控件是一个非常不错的选择,可以大大减少代码的编写 且 代码易读性强,可惜的是Python好象是没有数组控件这个东东。 我们来看看以下一个界面&#xff…

前端CSS基础11(相对定位,绝对定位,固定定位,粘性定位)

前端CSS基础11(相对定位,绝对定位,固定定位,粘性定位) CSS相对定位(position: relative;)相对定位的参考点在哪? CSS绝对定位(position: absolute)如何设置绝…

微信小程序:6.事件

什么事事件 事件就是渲染层到逻辑层的通讯方式,比如提交表单,按钮点击都可以看作一个事件。 小程序中常用的事件 事件对象属性列表 当事件回调时,会收到一个事件对象event,他详细属性如夏表所示: target和curren…

yudao-cloud微服务系统系统模块+后台管理系统成功运行

🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 系列文章目录 第一章 芋…

【软件测试】终于有人讲明白:bug的分类和定级了!

01、bug的定义 一般是指不满足用户需求的则可以认为是bug,狭义指软件程序的漏洞或缺陷,广义指测试工程师或用户提出的软件可改进的细节、或与需求文档存在差异的功能实现等 对应三个测试目的: 为了发现程序的代码或业务逻辑错误 为了检查产…

《第二行代码》第二版学习笔记(6)——内容提供器

文章目录 一 运行时权限2.权限分类3 运行时申请权限 二、内容提供器1、 ContentResolver的基本用法2、现有的内容提供器3、创建自己的内容提供器2.1 创建内容提供器的步骤2.2 跨程序数据共享 内容提供器(Content Provider)主要用于在不同的应用程序之间实…

2024年大数据应用、智能控制与软件工程国际会议(BDAICSE2024)

2024年大数据应用、智能控制与软件工程国际会议(BDAICSE2024) 会议简介 我们诚挚邀请您参加2024年大数据应用、智能控制和软件工程国际会议(BDAICSE2024)。这次会议将在美丽的长沙市举行。 本次大会旨在汇聚全球大数据应用、智能控制、软件工程等领…

WebGIS

文章目录 GIS的全名是Geographic Information System,中文全名是地理信息系统。 它是在计算机硬、软件系统支持下,对整个或部分地球表层(包括大气层)空间中的有关地理分布数据进行采集、储存、管理、运算、分析、显示和描述的技术…

Windows搭建php文件管理服务Tiny File Manager并发布至公网可访问

文章目录 1. 前言2.Tiny File Manager网站搭建2.1.Tiny file manager下载和安装2.2 Tiny file manager网页测试2.3 内网穿透工具下载安装 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试总结 1. 前言 今天,笔者就为大家介绍一款只有两个文件…

大数据第七天

文章目录 吐槽一下这个是怎么需要真的这么大吗? 内核错误内核软死锁(soft lockup)我这个cpu很高吗?大模型都说了不超过80就行了 FinBi安装FinBI下载链接安装时间比较长 吐槽一下 dbeaver 查询hive 数据信息是真的慢,没有一点快的方式&…

鲁棒控制理论学习:静态状态反馈H∞控制器

鲁棒性,即系统的健壮性,是指在异常和危险情况下系统能够维持其功能和性能的能力。在控制系统中,鲁棒性表现为系统在参数摄动下维持某些性能的特性。例如,当控制系统面临输入错误、磁盘故障、网络过载或有意攻击等挑战时&#xff0…

dist包在windows的nginx下部署运行

nginx 附带下载包 我用夸克网盘分享了「nginx-1.18.0.zip」 链接:https://pan.quark.cn/s/e87bbf87a742 将dist放到html文件目录下 3.找到nginx的配置文件,conf 下,用编辑器打开 nginx.conf 编辑。 location ^~/api {rewrite ^/api/(.*)…

python--使用pika库操作rabbitmq实现需求

Author: wencoo Blog:https://wencoo.blog.csdn.net/ Date: 22/04/2024 Email: jianwen056aliyun.com Wechat:wencoo824 QQ:1419440391 Details:文章目录 目录正文 或 背景pika链接mqpika指定消费数量pika自动消费实现pika获取队列任务数量pi…
最新文章