java八股——消息队列MQ

news2024/11/30 12:43:29

上一篇传送门:点我

目前只学习了RabbitMQ,后续学习了其他MQ后会继续补充。

MQ有了解过吗?说说什么是MQ?

MQ是Message Queue的缩写,也就是消息队列的意思。它是一种应用程序对应用程序的通信方法,使得应用程序能够通过读写出入队列的消息来进行通信,而无需使用专用的连接来链接它们。消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削峰等问题,实现高性能,高可用,可伸缩和最终一致性架构。在消息队列中,有生产者消费者两个角色。生产者负责发送数据到消息队列,而消费者则从消息队列中取出数据进行处理。这种方式实现了生产者与消费者之间的解耦,使得它们可以独立地运行和扩展。

消息队列的优缺点有哪些?

优点:
1.应用解耦:消息队列允许生产者和消费者之间松耦合。生产者只需要将消息发送到队列,而不需要关心消费者何时或如何处理这些消息。
2.异步处理:消息队列允许异步处理消息,这意味着接收者可以在自己方便的时候处理消息,而不是立即响应。这可以提高系统的吞吐量和响应时间。
3.流量削峰:在高并发场景下,消息队列可以起到缓冲作用,平滑突发流量,保护后端系统免受冲击。

缺点:
1.可用性降低:如果消息队列服务成为单点故障,整个系统可能会受到影响。因此,需要实施高可用性和容错策略,一般解决方法是给MQ架集群。
2.复杂性提高:引入消息队列会增加系统的复杂性。因为需要配置和管理消息队列服务,同时还需要处理可能的消息丢失、重复或顺序错乱等问题。
3.一致性问题:在分布式系统中使用消息队列时,如果消息队列发生了消息的丢失与重复,则可能会遇到数据一致性的问题。

说说消息队列的应用场景

消息队列的应用场景主要分为以下三种:
1.异步处理:应用在实时性要求不高的一些场景,例如用户注册发送验证码、下单通知发送优惠券等。这些场景下,服务方只需要把协商好的消息发送到消息队列,剩下的由消费者的消息服务去处理,不需要等待消费者的返回结果就可以直接返回给客户端,返回给业务层面;
2.应用解耦:可以把一些相关的但是耦合度不高的一些系统关联起来,比如订单系统与优惠券积分系统有关联度,但是没有那么紧密,每个系统之间只需要把一些约定好的消息发送到MQ,另外的系统直接去消费就可以了,它可以允许各类系统间采用不同的一些框架和语言来实现,从而大大增加了整个系统的灵活度;
3.流量削峰:应用在大流量入口的一些短时间的业务,短时间内业务需求处理不完的一些服务,例如双十一秒杀、演唱会抢票等。为了权衡高可用把大量的一些并行任务发送给MQ。根据MQ的存储和分发功能平稳的去处理后续的一些业务,从而起到大流量缓冲的作用。

开发过程中有哪些MQ可以选择?如何技术选型?

目前市面上常见的消息队列中间件主要有RabbitMQ、ActiveMQ、RocketMQ、Kafka。这几种消息队列各有优缺点,具体如下:

在这里插入图片描述
由上可以看出,ActiveMQ相较于其它三种消息队列,可用性差,并且吞吐量、消息延迟、可靠性都一般,除了一些小型项目或是追求经济高效的特定需求,ActiveMQ不是消息队列的第一选择,所以现在ActiveMQ不是主流的消息队列了
而由于RabbitMQ是基于Erlang语言开发的,所以如果需要对现有消息队列去做进一步的开发,不推荐使用RabbitMQ(如果只是拿来做简单应用开发就没区别)。
从吞吐量来看,比较好的是RocketMQ和Kafka,其中最好的是Kafka(单机的并发吞吐能力能够达到百万量级),所以如果要追求极致的吞吐能力去处理一些海量数据传输的大数据业务的时候,Kafka会是更好的选择。
而吞吐量高也会带来一定的牺牲,RocketMQ和Kafka的消息延迟(毫秒级)相比RabbitMQ(微秒级)要久很多,如果要追求消息的低延迟就可以选择RabbitMQ。
从可靠性的角度来看,Kafka由于追求极致的并发吞吐量,所以消息可靠性一般,如果要考虑消息的高可靠性,可以选择RabbitMQ或RocketMQ。

说说RabbitMQ的基本架构设计

RabbitMQ的基本架构由以下几个部分组成:
1.生产者(Producer):生产者是消息的发送方,负责产生并发生消息到RabbitMQ。生产者通常将消息发生给交换机(Exchange),从而使其消费者没有强关联。
2.交换机(Exchange):交换机是消息的分发中心,负责将接收到的消息路由到一个或多个消息队列。它定义了消息的传递规则,可以根据规则将消息发送到一个或多个队列中。

  • 直连交换机(Direct Exchange):将消息路由到与消息中的路由键(Routing Key)完全匹配的队列;
  • 主题交换机(Topic Exchange):根据通配符匹配路由键(Routing Key),将消息路由到一个或多个队列;
  • 扇出交换机(Fanout Exchange):将消息广播到所有与交换机绑定的队列,忽略路由键;
  • 头部交换机(Headers Exchange):根据消息头中的属性进行匹配,将消息路由到与消息头匹配的队列。

3.队列(Queue):队列是消息的存储区,用于存储生产者发送的消息。消息最终会被消费者从队列中取出并处理。每个队列都有一个名称,并且可以绑定到一个或多个交换机。
4.消费者(Consumer):消费者是消息的接收方,负责从队列中获取消息并进行处理。消费者通过订阅队列来接收消息。
5.绑定(binding):绑定是交换机和队列之间的关联关系。生产者将消息发送到交换机,而队列通过绑定与交换机相连,从而接收消息。
6.虚拟主机(Virtual Host):虚拟主机是RabbitMQ的基本工作单元,每个虚拟主机都拥有自己独立的用户、权限、交换机、队列等资源,完全隔离于其他虚拟主机。
7.连接(Connection):连接是指生产者、消费者与RabbitMQ之间的网络连接。每个连接都可以包含多个信道(Channel),每个信道是一个独立的会话通道,可以进行独立的消息传递。
8.消息(Message):消息是生产者和消费者之间传递的数据单元。消息通常会包含消息体和可选的属性,如路由键等。

在这里插入图片描述

说说RabbitMQ的交换机类型

1.Direct Exchange(直连交换机)
此类型交换机通过RoutingKey路由键将交换机和队列进行绑定,消息被发送到exchange时,需要根据消息的RoutingKey来进行匹配,只将消息发送到完全匹配此RoutingKey的队列。
2.Fanout Exchange(扇出交换机)
此类型交换机会将消息分发给所有绑定了此交换机的队列,此时RoutingKey无效。在Fanout类型交换机下发送一条消息,无论RoutingKey是什么,所有队列均可收到消息。
3.Topic Exchange(主题交换机)
此类型交换机与Direct类似,也是需要通过RoutingKey路由键进行匹配分发,区别在于Topic可以进行模糊匹配,而Direct是完全匹配。
1.在Topic中,将RoutingKey通过“.”来划分为多个部分;
2.“*”:代表一个部分;
3.“#”:代表0个或多个部分(如果绑定的路由键为“#”时,则接受所有消息,因为路由键所有都匹配)
4.Header Exchange(头部交换机)
Headers Exchange匹配AMQP消息的header而不是路由键,此外headers交换机和direct交换机完全一致,但由于它的性能差,目前几乎用不到了。
在此类交换机中,消费方指定的headers中必须包含一个“x-match”的键。该键的值有两个:
1.x-match = all:表示所有的键值对都匹配才能接收到消息
2.x-match = any:表示只要有键值对匹配就能接受到消息

说说RabbitMQ的持久化机制

RabbitMQ的持久化是一个重要的功能,它确保了即使在RabbitMQ服务器意外关闭或重启的情况下,消息仍然能够得到保存和恢复。RabbitMQ的持久化包括三个方面:交换器的持久化、队列的持久化和消息的持久化
交换器的持久化是通过在声明交换器时指定Durability参数为durable实现的。如果交换器不设置持久化,那么在RabbitMQ服务重启之后,相关的交换器元数据会丢失,但消息不会丢失,只是不能将消息发送到这个交换器中。
队列的持久化也是通过在声明队列时指定Durability参数为durable实现的。如果队列不设置持久化,在RabbitMQ服务重启之后,相关队列的元数据和消息数据都会丢失。设置队列持久化可以确保队列本身的元数据不会因异常情况而丢失,但并不能保证内部所存储的消息不会丢失。为了确保消息不会丢失,需要将消息设置为持久化。
消息的持久化可以通过消息的投递模式来实现。将消息设置为持久化可以确保消息在RabbitMQ服务器意外关闭或重启后能够得到恢复。然而,将所有消息都设置为持久化会严重影响RabbitMQ服务器的性能,因为写入磁盘的速度比写入内存的速度慢得多。因此,在选择是否要将消息持久化时,需要在可靠性和吞吐量之间做一个权衡

如何保证RabbitMQ的消息可靠性传输(保证消息不丢失)?

在RabbitMQ的整个消息投递过程中,有以下三种情况会存在消息丢失的问题:

1.生产者把消息发送到RabbitMQ Server的过程中丢失;
2.RabbitMQ Server收到消息后,在持久化之前宕机导致数据丢失;
3.消费端收到消息后还未来得及处理便宕机,导致RabbitMQ Server认为这个消息已经签收,这个消息就无法重复投递,导致消息无法消费的问题。

所以只需要解决这三个角度的问题,就能保证消息的可靠传输。
从生产者发送消息到Server端的角度来说,RabbitMQ提供了一个Confirm的消息确认机制,也就是说生产者发送的消息到Server端后,如果消息处理成功,Server端会返回客户端一个ack的消息,那么客户端可以根据消息的处理结果来决定是否要对消息进行重新发送,从而确保消息一定要到达到RabbitMQ Server端上;
从Server端的角度来说,可以开启消息的持久化机制,也就是收到消息后,将消息持久化到磁盘里面,设置消息的持久化一般有两个步骤:首先在创建Queue的时候设置为持久化,然后在发送消息的时候,把消息投递模式设置为持久化投递。虽然设置了持久化消息,但是也有可能会出现问题,比如消息刷新到磁盘上之前,RabbitMQ的Server端就发生宕机,这还是会导致消息丢失。为了确保万无一失,需要结合Confirm消息确认机制来一起使用;
从消费者的角度来看,可以把消息的ack机制中的自动确认修改为手动确认(将auto_ack参数设置为false),也就是说消费端只有手动调用消息确认方法,才表示这个消息已经被签收,这种方式可能会造成消息的重复消费,所以还需要考虑到幂等性的设计。

RabbitMQ中如何保证消息不被重复消费?

保证消息不被重复消费,实际上就是解决消息消费端幂等问题 (幂等性,指的是一条指令,任意多次执行所产生的影响均与一次执行的影响相同)。所以只要消费端具备了幂等性,消息重复消费的问题就解决了。
实现消息幂等性可以采用以下两种方案:
1.使用数据库的唯一约束实现幂等,比如对于MQ中的消息,设置一个唯一的消息id,如果消费端多次消费,就会触发数据库的唯一约束异常,从而实现消息的幂等性。
2.使用redis中的setNX指令,在MQ中,为了避免MQ重复消费导致数据被多次修改,消费端可以在接收到消息时,把消息通过setNX写入到redis里面,这样一来一旦消息被消费过,就不会再次被消费。

RabbitMQ中如何解决消息堆积问题?

在RabbitMQ中,出现消息堆积问题的场景一般有以下几种:
1.消息被消费方拒绝,一般来说这种情况是出现在程序或是逻辑有问题的时候。
解决方法:通过添加死信队列或是日志记录的方式避免消息重新入队
2.消费者消费消息的速度慢,从而导致消息的堵塞堆积。
解决方法:通过优化程序代码或建立消费者集群的方式增加消费者的消费能力。
3.队列容量不够,也可能导致消息堆积。
解决方法:增加队列的容量,以容纳更多的待处理消息。

RabbitMQ如何保证消息的顺序消费?

我们说的保证顺序消费,说的是消费者消费信息的顺序。虽然Server端队列中的消息是顺序的,但是由于多个消费者并发消费消息,所以获取消息的速度不一样,从而可能会导致消息的消费顺序出现问题。
想要解决顺序消费的问题,通常的解决办法就是一个队列只有一个消费者,这样就可以一个个消息按顺序处理,但缺点就是并发能力下降,无法并发消费消息,这是个取舍的问题。
也可以在发送消息时使用一些标识符或分区键将消息分区,并确保具有相同标识符的消息被发送到同一个队列。然后,可以使用多个消费者,每个消费者处理一个特定的分区,从而保证了消息在特定分区内的顺序性。

RabbitMQ如何给消息设置过期时间?

在RabbitMQ中存在2种方法设置消息的过期时间。第一种方法是通过对队列进行设置,这种设置后,该队列中所有的消息都存在相同的过期时间;第二种方法是通过对消息本身进行设置,那么每条消息的过期时间都不一样。如果同时使用这两种方法,那么以过期时间较小的哪个数值为准。当消息达到过期时间还没有被消费,那么该消息就成为了一个死信消息
队列设置:在队列中声明的时候使用x-message-ttl参数,单位为 毫秒。
单个消息设置:设置消息属性的expiration参数的值,单位为 毫秒。

说说RabbitMQ的死信队列

当队列中的消息被拒绝、或者消息过期会变成死信,死信可以被重新发布到另一个交换机,这个交换机是死信交换机(DLX,Dead Letter Exchange),与DLX绑定的队列被称为死信队列
出现死信的原因一般有以下几点:1.消息被消费方拒绝(消费方使用channel.basicNack或channel.basicReject,并且此时requeue属性被设置为false);2.消息超出过期时间超时;3.消息总量超过了队列的最大长度

说说RabbitMQ的延迟队列

延迟队列存储的是延迟消息。延迟消息是指,当消息被发布出去后,并不立即投递给消费者,而是在指定时间之后投递。例如:在订单系统中,订单有30秒的付款时间,在订单超时之后再投递给消费者处理超时订单。
RabbitMQ没有直接支持延迟队列,可以通过死信队列来实现。在死信队列中,可以为普通交换机绑定多个消息队列,假设绑定过期时间为5分钟,10分钟和30分钟三个消息队列,然后为每个消息队列设置DLX,为每个DLX关联一个死信队列。
当消息过期后,消息会被转存到对应的死信队列中,然后投递给指定的消费者消费。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多线程回答的滚瓜烂熟,面试官问我虚线程了解吗?我说不太了解!

Java虚拟线程(Virtual Threads)标志着Java在并发编程领域的一次重大飞跃,特别是从Java 21版本开始。这项新技术的引入旨在克服传统多线程和线程池存在的挑战。 多线程和线程池 在Java中,传统的多线程编程依赖于Thread类或实现Ru…

Python(1):认识Python并且了解一些简单函数

文章目录 一、Python的优势及其使用场景二、Python环境的安装三、Python中的变量及其命名四、Python中的注释五、一些简单常见的函数和认识ASCII表六、Python导入模块的方式 一、Python的优势及其使用场景 优点: 开发效率高:Python具有非常强大的第三方…

Java——数组练习

目录 一.数组转字符串 二.数组拷贝 三.求数组中元素的平均值 四.查找数组中指定元素(顺序查找) 五.查找数组中指定元素(二分查找) 六.数组排序(冒泡排序) 七.数组逆序 一.数组转字符串 代码示例: import java.util.Arrays int[] arr {1,2,3,4,5,6}; String…

220 基于matlab的考虑直齿轮热弹耦合的动力学分析

基于matlab的考虑直齿轮热弹耦合的动力学分析,输入主动轮、从动轮各类参数,考虑润滑油温度、润滑油粘度系数等参数,输出接触压力、接触点速度、摩擦系数、对流传热系数等结果。程序已调通,可直接运行。 220直齿轮热弹耦合 接触压力…

出游旅行,不能错过的华为nova 12 Ultra4个AI小技巧

随着AI功能的快速普及,让我们的日常生活和工作借助这些工具变得越来越高效。今天就分享4个超级实用的华为nova 12 Ultra自带的AI小技巧:小艺智能魔法抠图、AI消除、图库搜索、小艺帮写,看看有哪些还是你不知道的? 1. 小艺智能…

Windows:Redis数据库图形化中文工具软件——RESP(3)

这个是用于连接redis数据库的软件工具,安装在windows上的图形化界面,并且支持中文,是在github上的一个项目 1.获取安装包 发布 lework/RedisDesktopManager-Windows (github.com)https://github.com/lework/RedisDesktopManager-Windows/rel…

紧急 CCF-C ICPR 2024摘要投稿日期延期至4月10日 速投速成就科研梦

会议之眼 快讯 第27届ICPR(The International Conference on Pattern Recognition)即国际模式识别会议将于 2024年 12月1日-5日在印度加尔各答的比斯瓦孟加拉会议中心举行!ICPR是国际模式识别协会的旗舰会议,也是模式识别、计算机…

OpenHarmony南向开发案例:【智能保险柜】

样例简介 智能保险柜实时监测保险柜中振动传感器,当有振动产生时及时向用户发出警报。在连接网络后,配合数字管家应用,用户可以远程接收智能保险柜的报警信息。后续可扩展摄像头等设备,实现对危险及时报警,及时处理&a…

LeetCode-2529题:正整数和负整数的最大计数(原创)

【题目描述】 给你一个按 非递减顺序 排列的数组 nums ,返回正整数数目和负整数数目中的最大值。换句话讲,如果 nums 中正整数的数目是 pos ,而负整数的数目是 neg ,返回 pos 和 neg二者中的最大值。注意:0 既不是正整…

Linux 线程:线程同步、生产者消费者模型

目录 一、死锁 二、条件变量实现线程同步 1、为什么需要线程同步 2、条件变量、同步、竞态条件 3、条件变量函数:初始化 销毁 等待 唤醒 4、实现简单的多线程程序 不唤醒则一直等待 实现线程同步 三、生产者消费者 1、借助超市模型理解 2、优点 四、基于…

Eland上传bge-base-zh-v1.5向量化模型到ElasticSearch中

最近需要做一些向量检索,试试ES 一、准备 系统:MacOS 14.3.1 ElasticSearch:8.13.2 Kibana:8.13.2 本地单机环境,无集群,也不基于Docker BGE是一个常见的文本转向量的模型,在很多大模型RAG应…

python基础语法--输入和输出

一、 输入 input() python使用input输入变量,input输入的变量为字符串形式,可以通过其他方式转换为整型或其他类型。 (1)单行读入已知个数的字符串或数字 读入字符串 # 单行读入字符串a,并给出一句输入提示 a input("请…

【汇编语言实战】求三个已知数最大值

C语言描述该程序流程&#xff1a; #include <stdio.h> int main() {int a10,b20,c15;//scanf("%d %d",&a,&b);if(a>b){if(a>c){printf("%d",c);}else{printf("%d",a);}}else{if(b>c){printf("%d",b);}else{pr…

惊!磁盘未初始化,数据如何拯救?

在数字化时代&#xff0c;磁盘作为存储数据的重要载体&#xff0c;其稳定性直接关系到数据的安全。然而&#xff0c;有时我们会遭遇一个令人头疼的问题——磁盘没有初始化。这意味着磁盘无法被操作系统正常识别和使用&#xff0c;其中的数据仿佛被锁进了一个无形的牢笼。那么&a…

2024全面启动:《水资源基础调查实施方案》解读

【引言】 去年&#xff0c;随着自然资源部《关于开展水资源基础调查工作的通知》&#xff08;自然资发〔2023〕230号&#xff09;的发布&#xff0c;一项旨在全面掌握我国水资源状况、助力生态文明建设与经济社会发展的重大工程——水资源基础调查正式启动。 近日&#xff0c…

uniapp小程序给指定的页面新增下拉刷新功能

需求:有些页面需要实时更新数据,但是又不能做实时刷新,所以给用户一个手动下拉刷新指定接口的功能 第一步:在pages.json给页面加"enablePullDownRefresh": true配置 第二步:在指定页面写onPullDownRefresh方法,和methods同级 onPullDownRefresh() {//加个定时器1秒…

在隐私计算应用中和数链具备哪些技术特点?

在加速“可信数字化”进程的背景下&#xff0c;我国区块链产业将在打造新型平台经济&#xff0c;开启共享经济新时代的同时&#xff0c;带动数字经济“脱虚向实”服务实体经济。 和数软件在加速数字化进程的同时&#xff0c;进一步服务实体经济&#xff0c;提高实体经济的活力…

windows安装Redis,Mongo,ES并快速基本掌握开发流程

前言 这里只是一些安装后的基础操作&#xff0c;后期会学习更加深入的操作 基础操作 前言RedisRedis启动idea集成Redisjedis技术 Mongodbwindows版Mongodb的安装idea整合Mongodb ES(Elasticsearch)ESwindows下载ES文档操作idea整合ES低级别ES整合高级别ES整合 Redis Redis是…

如何在项目中引入vue-router

vue3对应vue-router4 先安装最新版的vue-router pnpm i vue-router 在src目录下新建router文件夹&#xff0c;在其下创建index.js文件 在index.js文件下写 // 创建一个路由器&#xff0c;并暴露出去 // 第一步&#xff1a;引入createRouter import {createRouter,createWeb…

Terraform进阶技巧

Terraform 是管理 IaC 的强大工具&#xff0c;常用常新。在这一部分我们将探索 Terraform 的进阶技能&#xff0c;包括 Terraform 模块、远程状态存储、Terraform 工作区以及自定义 Provider。 1、Terraform 模块 Terraform 模块是可复用的 Terraform 代码包&#xff0c;其…