RabbitMQ消息队列面试题集合
17.rabbit的死信队列和延时队列的使用
死信队列(DLX) 是当队列中的消息不能被正常消费或处理时,消息会被转发到一个死信队列进行处理或记录。
- 消息被拒绝(
reject
或nack
)且没有重新排入队列(requeue=false); - 消息在队列的存活时间超过设置的TTL时间。
- 消息队列的消息数量已经超过最大队列长度。
设置方法:
- 在 RabbitMQ 中,死信队列可以通过设置队列的
x-dead-letter-exchange
(死信交换机)和x-dead-letter-routing-key
(死信路由键)来实现
如果满足上面三条之一那么该消息将成为“死信"。“死信"消息会被RabbitMQ进行特殊处理,如果配置了死信队列信息,那么该消息将会被丢进死信队列中,如果没有配置,则该消息将会被丢弃为每个需要使用死信的业务队列配置一个死信交换机,这里同一个项目的死信交换机可以共用一个,然后为每个业务队列分配一个单独的路由key,死信队列只不过是绑定在死信交换机上的队列,死信交换机也不是什么特殊的交换机,只不过是用来接受死信的交换机,所以可以为任何类型【Direct、Fanout、Topic】
延时队列 允许将消息推迟一定时间再进行消费。实现方式:
- 利用 TTL 和死信队列:可以为消息设置 TTL(Time-To-Live,生存时间),消息在过期后会被发送到死信队列。然后,可以将死信队列的消息重新投递到原队列,从而实现延时消费。
18.队列的应用场景,实现方案
1.异步任务处理
- 场景:异步任务可以通过队列来处理,例如,用户注册时发送激活邮件,或者用户上传文件后进行后台处理。
- 实现方案:通过消息队列将需要异步处理的任务放入队列,引入消息队列后,将不是必须的业务逻辑,将发注册邮件和注册短信进行异步处理,提高接口响应时间。
2.流量削峰与负载均衡
- 场景:比如秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。
- 实现方案:为解决这个问题,一般需要在应用前端加入消息队列。用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面。
3.延迟处理与定时任务
- 场景:有些任务需要在指定时间后执行。可以将任务放入消息队列,设置延迟时间,让队列在特定时间后将任务交给消费者处理。
- 实现方案:使用支持延迟队列的消息队列(如RabbitMQ的延迟队列、Kafka的定时消息),将任务放入队列并设置延迟时间。
4.日志处理
日志处理是指将消息队列用在日志处理中,比如 Kafka 的应用,解决大量日志传输的问题。
19.如何保证消息的可靠性
1.事务,性能较差,一般不用
2.消息持久化:确保队列和消息在 RabbitMQ 重启后不丢失,使用 durable=true
和 persistent=true
。
3.使用消息确认机制:
发送方确认:
1.channel设置为confirm模式,则每条消息会被分配一个唯一id
2.消息投递成功,信道会发送ack给生产者,包含了id,回调ConfirmCallback接口
3.如果发生错误导致消息丢失,返回nack给生产者。回调ReturnCallback接口
ack和nack只有一个触发,且只有一次,异步触发。可以继续发送消息
接收方确认:
1.声明队列时,指定noack=false,broker会等待消费者手动返回ack、才会删除消息,否则立刻删除
2.broker的ack没有超时机制,只会判断链接是否断开,如果断开、消息会被重新发送
20.项目中如何集成消息队列
“在项目中集成消息队列的步骤通常包括以下几个部分:
- 选择合适的消息队列:根据项目需求选择合适的消息队列,例如,如果需要高吞吐量和持久化,可以选择 Kafka;如果需要支持复杂的消息模式,可以选择 RabbitMQ。
- 安装和配置:安装并配置好消息队列服务,并在项目中引入对应的 SDK。比如在使用 RabbitMQ 时,引入 Spring AMQP 依赖,配置连接信息。
- 编写生产者和消费者代码:生产者负责将消息发送到队列,消费者则监听并处理这些消息。在 RabbitMQ 中,生产者通过
channel.basicPublish()
发送消息,消费者通过channel.basicConsume()
接收消息。 - 配置消息可靠性:确保消息的可靠性,比如通过队列的持久化、消息确认机制以及重试机制,避免消息丢失或重复消费。
- 监控和优化:使用消息队列提供的监控工具来监测消息的发送和消费情况,确保系统性能和稳定性。”
21.队列的类型有哪些
常用的四个
普通队列(Simple Queue)
元素按照插入的顺序排队,先进入的元素先出。
操作:常见操作包括 enqueue
(入队)和 dequeue
(出队)。
循环队列(Circular Queue)
普通队列的缺点是当队列的尾部达到最大容量时,不能再继续添加元素。循环队列通过将队列的尾部与队列的头部连接起来,解决了这个问题,使队列变成一个循环结构。
双端队列(Deque,Double-Ended Queue)
可以从队列的两端进行插入和删除操作,因此有时也被称为双端队列。支持从队列的前端或后端进行插入和删除。
操作:常见操作包括 enqueue_front
(从前端入队)、enqueue_back
(从后端入队)、dequeue_front
(从前端出队)和 dequeue_back
(从后端出队)。
优先队列(Priority Queue)
与普通队列不同,优先队列中的元素按优先级高低来决定出队顺序。优先级高的元素先出队
操作:enqueue
(入队),并且元素入队时会被赋予一个优先级,dequeue
(出队)时会按优先级顺序返回元素。
22.如何实现公平分发
公平分发的核心目标是确保所有消费者或任务节点公平地获得任务量,避免某些消费者或节点过载。实现公平分发的方法有很多,常见的包括:
- 轮询法,通过简单的轮流分配任务,确保每个消费者都能公平地获取任务。
- 加权轮询法,在任务量不均衡的情况下,给消费者设置不同的权重,处理能力强的消费者可以多接收一些任务。
- 最少连接法,选择当前任务量最少的消费者来分配新任务,这样可以平衡负载。
- 公平队列,通过管理队列中的消息,确保每个消费者轮流消费消息,防止某个消费者一直占据任务。
- 使用信号量或公平锁,来控制任务的分配顺序,确保任务公平地分配给每个消费者。
具体实现方式要根据业务场景来选择,比如在消息队列中,像 RabbitMQ 就可以通过调整 prefetch count
和启用公平分发模式来实现公平地消息分配。
23.解释rabbitMQ消息堆积的原因,如何临时紧急扩容
消息堆积原因:
RabbitMQ 消息堆积通常是由多种原因导致的。一方面,生产者发送消息速度过快,比如在一些高并发场景下,生产者可能会在短时间内产生大量消息,超过了消费者的处理能力。另一方面,消费者处理能力不足也会引发问题,像是消费者代码中存在复杂的业务逻辑,或者受限于服务器资源,导致处理消息的速度跟不上消息产生的速度。此外,队列配置不合理,如容量过小或预取计数设置不当,以及网络出现延迟、中断等情况,都可能造成消息在队列中堆积。
临时紧急扩容:
我认为可以从以下几个方面入手。一是增加消费者数量,通过水平扩展的方式,让更多的消费者来处理消息,能快速提高消息的消费速度。二是优化消费者的处理逻辑,提高单个消费者的处理能力,同时为消费者分配更多的资源,像增加 CPU 和内存等,以提升其性能。三是调整队列配置,合理增加队列容量和优化预取计数,让队列能更好地适应消息的处理流程。四是考虑使用镜像队列,将队列复制到多个节点上,这样不仅能提高队列的可用性,还可以通过多个节点并行处理来加快消息的消费。
24.rabbitMQ如何保证消息不会被重复消费?(未完成)
主要就是保证消费端的幂等性
幂等性:一个数据或者一个请求,重复来多次,确保对应的数据是不会改变的
1.如果是写 redis,就没问题,反正每次都是set,天然幂等性
2.生产者发送消息的时候带上一个全局唯一的id,消费者拿到消息后,先根据这个id去redis里查一下,之前有没
消费过,没有消费过就处理,并且写入这个id 到redis,如果消费过了,则不处理。MQ