🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:
🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection与数据结构 (93平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀线程与网络(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
🎃Redis(97平均质量分)https://blog.csdn.net/2301_80050796/category_12777129.html?spm=1001.2014.3001.5482
🐰RabbitMQ(97平均质量分) https://blog.csdn.net/2301_80050796/category_12792900.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
目录
- 1. MQ的作用以及应用场景
- 2. 了解过哪些MQ?他们有什么区别?
- 3. 介绍一些RabbitMQ的核心概念以及工作流程
- 4. RabbitMQ如何保证消息的可靠性(最高频)
- 5. RabbitMQ如何保证消息的顺序性?
- 6. 如何保证消息消费时候的幂等性
- 7. 介绍一下RabbitMQ的死信队列
- 8. 介绍一下RabbitMQ的延迟队列
- 9. 介绍一下RabbitMQ的工作模式
- 10. 消息积压的问题,如何处理?
- 11. RabbitMQ是推模式还是拉模式(前面没有涉及到)
1. MQ的作用以及应用场景
消息队列是一种应用程序之间通信的一种方法,他允许系统组件以异步的方式进行交互,在不同的应用场景之下可以展现出不同的作用,常见的应用场景如下:
- 异步解耦: 在业务流程中,⼀些操作可能非常耗时,但并不需要即时返回结果.可以借助MQ把这些操作异步化.
- 流量削峰: 在访问量剧增的时候,应用任然需要发挥作用,扛得住压力,如果一味地在硬件方面投入,无疑是巨大的浪费,所以我们就需要使用MQ来控制流量,将请求排队处理,使得一些关键组件不会因为突然增长的访问压力而崩溃.
- 消息分发
当多个系统需要对同一个数据的更新做出响应的时候,可以使用MQ进行消息分发.订阅队列消息的系统都会收到通知(监听消息队列的消费者).比如支付成功之后,支付系统可以直接向MQ发送信息,其他系统订阅该消息,它们会直接收到消息,无需轮询数据库. - 延迟通知
需要在特定的时间之后发送通知的场景中,可以使用MQ的延迟消息功能,比如在电子商务平台中,如果用户在下单之后一定时间之内未支付,可以使用延迟队列在超时后自动取消订单.
2. 了解过哪些MQ?他们有什么区别?
目前业界有很多MQ的产品,例如RabbitMQ,RocketMQ,Kafka,ZeroMQ等.
简单介绍三种的区别:
- Kafka
Kafka一开始的目的是用于日志收集和传输,追求高吞吐量,性能卓越.单机吞吐量达到10万级别,在日志领域比较成熟,功能较为简单,主要支持简单的MQ功能. - RabbitMQ
采用Erlang语言开发,MQ功能比较完备,且几乎支持所有的主流语言,开源提供的界面也非常友好,吞吐量达到万级,舍去活跃度较高,文档更新频繁. - RocketMQ
采用Java语言开发.在可用性以及稳定性等方面都非常出色,吞吐量达到十万级,但是支持的语言不多,产品较新,文档较少,社区活跃度一般.
3. 介绍一些RabbitMQ的核心概念以及工作流程
RabbitMQ是一个消息中间件,也是一个生产者消费者模型,负责接收,存储并转发消息:
- producer: 生产者,向RabbitMQ发送消息.
- Consumer: 消费者,从RabbitMQ接收消息.
- Broker: RabbitMQ服务器.
- Connection: 生产者客户端或者是消费者客户端与RabbitMQ服务器之间的网络连接.允许客户端与RabbitMQ之间通行.
- Channel: 连接里的一个虚拟通道,发送或者是接收消息都是通过通道进行的.Channel和Connection组合起来有点像线程池的模式.
- Exchange: 交换机.负责接搜生产者发送的消息,之后根据路由算法对消息进行路由.
- Queue: 消息队列,存储消息直到他们被消费者消费.
工作流程如下:
- producer生产了一条信息.
- producer连接到RabbitMQBroker,建立一个Connection,并开通一个信道.
- producer声明一个交换机,用于把消息路由到指定的交换机中.声明队列,用于把消息存储到指定的队列中.这些信息会在消息的标签中声明.
- producer经过Channel,发送消息到RabbitMQBroker中.
- RabbitMQBroker接收消息,并按照消息的标签路由到对应的交换机中,交换机再次按照标签存储到对应的队列中.
- 出队列之后,消息会经过Channel到达消费者客户端中.
4. RabbitMQ如何保证消息的可靠性(最高频)
可以从以下几个方面来回答,一共三大机制:
- 发送放投递可靠性(发送方确认)
如果消息在到达服务器之前就已经发生了丢失,这时候消息根本没有到达RabbitMQ,我们就要通过发送放确认来解决.
RabbitMQ提供了两种方式来保证消息投递的可靠性:confirm模式和return模式.confirm模式通过设置RabbitTemplate的ConfirmCallback属性来实现,return模式通过设置ReturnCallback属性来实现. - RabbitMQ可靠性(消息持久化)
如果RabbitMQ由于某种异常情况以外退出或者崩溃,交换机,队列或者消息可能会发生丢失.这时候我们就需要对交换机,队列和消息都设置持久化.Spring中,对队列和交换机设置持久化的时候,我们一般是使用Builder的durable方法来完成,设置消息的持久化我们一般对消息中的DeliveryMode属性设置为持久化来实现. - 消费者可靠性(消费者确认)
如果消息到达了消费者,如果消息处理异常的情况下,这条消息就会被删除,此时就会造成消息的丢失.我们就可以使用RabbitMQ提供的消息确认机制.消息确认分为两种模式,一种是自动确认模式,一种是手动确认模式.要保证消息的可靠性,我们一般使用手动确认来解决.Spring中通过配置文件来修改确认机制.分为None,Auto,Manual三种,其中Auto可以设置最大重试次数.
5. RabbitMQ如何保证消息的顺序性?
消息顺序性保障分为: 局部顺序性保障和全局顺序性保障方案
局部顺序性通常指的是在单个队列内部保证消息的顺序.全局顺序性是指在多个队列或多个消费者之间保证消息的顺序.
保证顺序性的策略有以下的策略:
- 单队列单消费者
最简单的方法是使用单个队列,并有单个消费者进行处理,同⼀个队列中的消息是先进先出的,这是RabbitMQ来帮助我们保证的. - 分区消费
单个消费者的吞吐太低了,当需要多个消费者以提高处理速度时,可以使用分区消费.把⼀个队列分割成多个分区,每个分区由一个消费者处理,以此来保持每个分区内消息的顺序性.(针对一个队列有多个消费者的场景)
但是RabbitMQ本身并不支持单个队列的分区消费,需要业务逻辑实现,或者借助Spring-cloud-Stream来实现. - 消息确认机制
使用手动消息确认机制,消费者在处理完一条消息之后,显示地发送确认,这样RabbitMQ才会移除并继续发送下一条消息. - 业务逻辑控制
在某些情况下,即使消息乱序到达,也可以在业务逻辑层面实现顺序控制.比如通过在消息中嵌入序列号,并在消费时根据这些信息来处理.
6. 如何保证消息消费时候的幂等性
对于MQ而言,幂等性是指同一条消息多次消费,对系统的影响是相同的.
MQ消费者的幂等性的解决方法,一般有以下几种:
-
全局唯一ID
为每条消息分配一个唯一标识符,比如UUID或者MQ消息中唯一的ID,但是一定要保证唯一性.
消费者接收到消息之后,先用该ID判断该消息是否已经消费过,如果已经消费过,则放弃处理.
如果没有消费过,消费者开始处理消息,业务处理成功之后,把唯一的ID保存起来(数据库或Redis等).
可以使用Redis的原子性操作,比如使用Set操作,在后面加上nx命令(存在的时候不设置)来保证幂等性,将唯一的id设置在Redis中,如果返回1,则说明之前没有设置过,正常消费,如果返回的是0,说明之前这个id被保存过,即证明这条消息已经被消费过了,不再进行消费,自动抛弃. -
业务逻辑判断
在业务逻辑层面进行判断以处理幂等性.
例如: 通过检查数据库中是否已经存在相关的数据记录,或者使用乐观锁机制来避免更新已经被其他的事务修改的数据,再或者在处理消息之前,先检查业务相关的状态,确保消息对应的操作尚未执行,然后才进行处理,具体根据业务场景来处理.
7. 介绍一下RabbitMQ的死信队列
死信简单理解就是因为种种原因,无法被消费的信息,就是死信.
有死信,就会有死信队列,当一个消息在一个队列中变为死信之后,它能被重新被发送到另一个交换机中,这个交换机就是DLX(Dead Letter Exchange),绑定DLX的队列,就被称为死信队列(DLQ,Dead Letter Queue).
消息变为死信一般是由于一下的几种情况:
- 消息被拒绝.(Basic.reject/Basic.nack),比如超过最大的重试次数.
- 消息过期,超过TTL设置的过期时间
- 队列达到最大长度
8. 介绍一下RabbitMQ的延迟队列
延迟队列就是在消息发送以后,并不想让消费者立刻拿到消息,而是等待特定的时间之后,消费者才可以拿到消息进行消费.
RabbitMQ本身并没有直接支持延迟队列的功能,但是可以通过TTL+死信队列的方式结合模拟出延迟队列的功能.也可以通过RabbitMQ官方提供的一个延迟的插件来实现延迟队列的功能.
常见的应用场景有:
订单在10min之内未支付自动取消.
用户在注册成功之后,3天之后发起调查问卷
用户发起退款,24小时之内商家未处理,则默认同意退款.
9. 介绍一下RabbitMQ的工作模式
- 简单模式:一个队列直接对应一个消费者和一个生产者.
- 工作队列:一个队列对应一个生产者和多个消费者.
- 广播模式:包含一个生产者,一个交换机,交换机绑定了多个队列,一个队列对应一个消费者.
- 路由模式:和广播模式类似,但是交换机会根据路由键把消息发送到指定的队列中.
- 通配符模式:是路由模式的一种扩展,交换机根据路由键的匹配规则将消息路由到不同的消息队列中.
- RPC模式:通过两个队列实现了一个消息回调的过程.有点类似与我们在网络中学习的"请求和响应",这个功能是MQ的额外功能.
- 发布确认模式: 是RabbitMQ提供的一种确保消息可靠发送到RabbitMQ服务器的机制.在这种模式之下,生产者可以等待RabbitMQ服务器确认,可以确保消息已经被服务器接收并处理,就是我们在前面提到的保证消息可靠性的发送方确认机制.
10. 消息积压的问题,如何处理?
消息积压指的是在消息队列中,等待处理的消息数量超过了消费者的处理能力,导致消息在队列中不断堆积的现象.
通常有以下的几种原因:
- 消息生产过快: 在高流量或者高负载的情况下,生产者以极高的速率发送消息,超过了消费者的处理能力.
- 消费者处理能力不足: 消费者处理消息的速度跟不上消息生产的速度,也会导致消息在队列中积压.
- 网络问题: 因为网络延迟或者不稳定,消费者无法及时接收或确认消息,最终导致消息积压.
- RabbitMQ服务器配置偏低
解决方案如下: - 提高消费者效率
- 增加消费者实例数量,比如新增机器.
- 优化业务逻辑,比如使用多线程并发处理业务.
- 设置prefetchCount,当一个消费者处于繁忙阶段的时候,把消息转发到其他未阻塞的消费者.
- 消息发生异常时,设置合适的重试策略,或者是转入到死信队列.
- 限制生产者速率
- 流量控制: 在消息生产者中实现流量控制,根据消费者处理能力动态调整发送速率.
- 限流: 使用限流工具,为消息发送速率设置一个上限.
- 设置过期时间:,如果消息过期未消费,可以配置死信队列,以免消息丢失,并减少对主队列的压力.
- 资源与配置优化.比如升级RabbitMQ服务器硬件,调整RabbitMQ的配置参数.
11. RabbitMQ是推模式还是拉模式(前面没有涉及到)
RabbitMQ支持两种消息传递模式,推模式和拉模式.
推模式: 消息中间件主动将消息推送给消费者.
拉模式: 消费者主动从消息中间件拉取消息.
RabbitMQ主要是基于推模式工作的,他的设计核心是让消息队列中的消费者接收到由生产者发送的消息.使用Channel.basicConsume方法订阅队列,RabbitMQ就会把消息推送到订阅该队列的消费者,如果只想从队列中获取单条消息而不是持续订阅,则可以使用Channel,basicGet方法来进行消费消息.