大家好我是小明,今天学习消息中间件RabbitMQ
`
文章目录
- [1. RabbbitMQ如何保证消息不丢失问题(最高频)](#1. RabbbitMQ如何保证消息不丢失问题(最高频))
- [2. RabbitMQ消息的重复消费如何解决??](#2. RabbitMQ消息的重复消费如何解决??)
- [3. RabbitMQ中的死信交换机(RabbitMQ延迟队列有了解过吗?)](#3. RabbitMQ中的死信交换机(RabbitMQ延迟队列有了解过吗?))
- [4. RabbitMQ如果有100万条消息堆积在MQ,如何解决(信息堆积怎么解决)](#4. RabbitMQ如果有100万条消息堆积在MQ,如何解决(信息堆积怎么解决))
- [5. RabbitMQ的高可用机制有哪些有了解过吗。](#5. RabbitMQ的高可用机制有哪些有了解过吗。)
复习大纲

1. RabbbitMQ如何保证消息不丢失问题(最高频)
这个这么回答:

生产者确认机制: 消息发到MQ后会返回一个ack给生产者,表示消息成功发送到mq.
消费者确认机制: 消费者处理完消息后发送ack给MQ,MQ收到ack回执后,MQ才会删除该消息。
SpringAMQP则允许配置三种消费者消息确认确认模式:
- 自动确认: RabbitMQ 会⾃动把发送出去的消息置为确认, 然后从内存(或者磁盘)中删除, ⽽不管消费者是否真正地消费到了这些消息.
- 手动确认: 费者处理完业务后,手动调用 channel.basicAck() 确认;处理失败则调用 basicNack()/basicReject() 拒绝(可重入队列或丢弃)。
- 批量确认(批量手动) : 就是消费者处理完一批消息之后就确认这一批消息,下面看批量确认代码
java
// 批量确认示例(假设累计处理100条后确认)
private int batchCount = 0;
private long lastDeliveryTag = 0;
@RabbitListener(queues = "batch.queue")
public void onBatchMessage(Message message, Channel channel) throws IOException {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
// 处理业务逻辑
processMessage(message);
batchCount++;
lastDeliveryTag = deliveryTag;
// 累计100条批量确认
if (batchCount >= 100) {
channel.basicAck(lastDeliveryTag, true); // 确认所有<=lastDeliveryTag的消息
batchCount = 0; // 重置计数器
}
} catch (Exception e) {
// 批量处理失败,拒绝当前消息并停止批量
channel.basicNack(deliveryTag, false, true);
batchCount = 0;
}
}
假如说:消费者消息确认失败怎么办

可以利用Spring的retry机制,在消费者出现异常时利用本地重试机制,设置重试次数,当到达一定次数还是失败,就把消息丢到死信队列,由人工处理。
消息持久化: MQ默认是内存存储消息,开启持久化可以保证消息在MQ中消息不丢失。

面试回答:

2. RabbitMQ消息的重复消费如何解决??
问题:
消费者处理完消息之后,发送的ack用于网络波动没有接收到,mq再次发送该消息给消费者处理,导致消费者重复消费。

解决: 消息带身份标识(id,支付id,订单id),消费者校验该id是否存在进行处理,如果存在直接跳过处理流程。
3. RabbitMQ中的死信交换机(RabbitMQ延迟队列有了解过吗?)
死信出现的三种情况?
- 消息被拒绝(Rejected):消费者调用了 basicReject 或 basicNack 方法并且方法的第二个参数 requeue(重入队列)被设置为 false,
- 消息过期(TTL Expired):队列设置了过期时间: 整个队列里的所有消息都有统一的过期时间(x-message-ttl)。消息本身设置了过期时间: 发送消息时给这条消息单独设置了过期时间(expiration 属性)。
- 队列达到最大长度:队列像一个桶,桶满了,再往里面倒水,水就会溢出来。溢出的消息就会变成死信。
延迟队列: 进入队列的消息会被延迟消费的队列
使用场景:
- 30 分钟内支付订单
- 定时发布作品
- 限时优惠
延迟队列的实现原理(TTL + 死信队列)
- 创建一个 "延迟队列"(实际是普通队列),不给它配置消费者(消息不会被立即消费);
- 给这个延迟队列设置 TTL(消息过期时间),并绑定死信交换机;
- 消息发送到这个延迟队列后,会在队列里 "等待" 直到过期;
- 消息过期后,会自动变成死信,被转发到绑定的死信交换机;
- 死信交换机再把消息路由到实际消费队列,消费者监听这个队列,就能拿到 "延迟后的消息"。
简单来说:延迟队列的本质是 "让消息先在一个'临时队列'里等过期,过期后自动转到消费队列被处理",TTL + 死信是实现这个逻辑的 "巧劲"。

4. RabbitMQ如果有100万条消息堆积在MQ,如何解决(信息堆积怎么解决)
当生产者发送消息的速度超过了消费者处理消息的速度,就会导致队列中的消息堆积,直到队列存储消息达到上限。之后发送的消息就会成为死信,可能会被丢弃,这就是消息堆积问题。
解决消息堆积三种思路:
- 增加更多消费者,提高消费速度
- 在消费者内开启线程池加快消息的消息的处理速度
- 扩大队列容积,提高堆积上线
这么扩大队列消息容积呢??
惰性队列
设置队列属性为lazy该队列就会变成惰性队列。
- 消息存储在硬盘中而非内存。
- 消费者需要消费消息时才会从磁盘中读取并加载。
- 支持数百万消息存储。
这样就扩大消息的存储了。
5. RabbitMQ的高可用机制有哪些有了解过吗。
镜像集群
本质: 主从模式
具备以下特征:
-
交换机,队列,队列中的消息在各个MQ节点的镜像节点进行同步。
-
创建队列的节点被称为队列主节点,备份到的节点叫做队列的进镜像点。
-
一个队列的主节点可能是另一个队列的镜像节点。
-
所有操作都是由主节点完成,然后同步镜像节点。
-
主节点宕机后,镜像节点会代替成新主节点,主节点在数据同步时宕机的会造成数据丢失 。

仲裁队列 -
和镜像队列一样,都是主从模式,支持主从数据同步
-
使用非常简单,没有复杂的配置
-
**主从同步使用Raft协议,强一致性

好了今天就到这里