常见面试题
# 常见面试题
https://blog.csdn.net/see__you__again/article/details/115909509
# RabbitMQ怎么实现优先级队列?
先设置最大优先级属性:x-max-priority
发送消息时设置消息的优先级
# 如何限流?
# 为什么要限流?
○ 数据量特别大时,对消费者限流。避免激增的数据量把资源耗尽,保证系统的稳定性
# ● 实现方式——限流API
○ RabbitMQ提供了qos功能,在非自动确认消息的前提下。如果达到一定数量的消息未被确认时,将不会消费新的消息。
○ void basicQos(int prefetchSize, int prefetchCount, boolean global) throws IOException。设置消息的大小,一次消费的数量,设置成channel级别还是consumer级别。
# ● 如何进行限流?
○ 消费端关闭自动ack
○ 设置限流的大小
○ 消费者手动ack,并设置批量处理ack回应位true(channel.basicAck(envelope.getDeliveryTag(), true);)
https://www.cnblogs.com/peteremperor/p/10273077.html
# 1. 为什么使用消息队列?
● 解耦 ● 异步 ○ 一些非必要的业务逻辑以同步的方式运行,太耗费时间 ○ 将消息写入队列,非必要的业务以异步的方式运行,加快响应速度 ● 削峰 ○ 并发量大的时候,所有的请求直接怼到数据库,造成数据库连接异常 ○ 系统从消息队列中按照数据库能处理的并发量,慢慢拉取数据。在生产中,这个短暂的高峰期积压是允许的。
# 2. 使用消息队列有什么缺点?
● 系统可用性降低:多了一个可能挂掉的系统 ● 系统复杂性增加:要考虑很多方面的问题。如:一致性问题、如何保证消息不被重复消费、消息不丢失
# 3. 消息队列如何选型?
● 中小型软件公司,建议选RabbitMQ.一方面,erlang语言天生具备高并发的特性,而且他的管理界面用起来十分方便。 ● 大型软件公司,根据具体使用在rocketMq和kafka之间二选一。一方面,大型软件公司,具备足够的资金搭建分布式环境,也具备足够大的数据量。针对rocketMQ,大型软件公司也可以抽出人手对rocketMQ进行定制化开发,毕竟国内有能力改JAVA源码的人,还是相当多的。至于kafka,根据业务场景选择,如果有日志采集功能,肯定是首选kafka了。具体该选哪个,看使用场景。
# 4. 如何保证消息队列高可用?
各个消息队列的集群模式
# 5. 如何保证消息不被重复消费
造成重复消费的原因:一般的消费者在消费完消息后都会给消息队列发送确认消息,消息队列收到后就会将其删除(或者移动消费位点)。由于网络故障或消费者挂掉消息队列没有收到消息,消息队列将再次把该消息发送给其他消费者。
解决办法:
● 消费者拿到消息时,就做数据库插入操作,每个消息有唯一的id,将它作为唯一主键。重复消费的话会报错。
● 消息做redis的set操作
● 第三方介质做消费记录,如redis,每个消息分配一个全局id,以id-message的形式,每次消费都先去redis查是否消费过
# 6. 哪些情况消息可能会丢失,如何保证消息的可靠性传输?
https://juejin.cn/post/7401463939592470538?searchId=20260119190232ECD8BBA49AE359D83425
# 生产者丢失数据
○ 需要等待MQ返回ACK消息,才代表消息发送成功
# 消息队列丢失数据
Broker 会把消息持久化到 commitlog
其实持久化的过程并不会直接就存储到磁盘,RocketMQ 实际上用的是异步刷盘,也就是消息先写入内存,然后再由专门的线程异步刷到磁盘。
默认情况下消息还在存在 Broker 的内存中,就给 Producer 返回 ACK 消息了,这个时候,如果 Broker 重启,存在内存中的消息自然就丢失了
所以对于有些对消息严格不能丢失的业务来说,就要更改默认的异步刷盘为同步刷盘,也就是在消息写入到磁盘之前,会阻塞发送请求,直到消息成功刷盘。
# 消费者丢失数据
一般是由于消费者采用了自动确认消息模式,消费者拿到消息后,自动确认收到消息,rabbitMQ会立即删除消息。如果消费者异常未处理消息就会丢失该消息。
保证消费过程中消息不丢失,在提交消费位点之前,一定要保证已经处理完业务流程,再进行消费位点的提交。
# RocketMQ自身的机制
- 同步刷盘:默认是异步,改为同步会阻塞,牺牲性能,需要修改broker.conf: flushDiskType=SYNC_FLUSH
- 主从同步复制 a. 主节点负责所有的读写请求,从节点从主节点同步数据,作为备份 b. 主节点故障可以切换到从节点 c. 默认是异步复制,保证数据完全不丢失需要同步复制,修改broker.conf:brokerRole=SYNC_MASTER
- 消息重试
- 如何保证消息的顺序性 保证入队的顺序性,出队的顺序性由消费者来保证。
# 消息堆积如何处理
https://juejin.cn/post/7474264487513194547?searchId=20260201102503B3F6477C6FEAAF177DDF
首先应该搭建监控和告警
# 产生原因
● 生产端堆积:生产速度>broker的处理速度
○ 生产者发送速率飙升
○ 出现网络问题导致发送延迟或失败,频繁重试拉长发送时间
● Broker堆积:Broker处理能力不足。无法及时接受、存储和投递消息
○ Broker的写入性能下降(磁盘满了、CPU过载)
○ Broker节点故障或主从同步延迟
○ Topic队列不足,导致消息的写入和消费并行度低
● 消费段堆积:消费端处理速度<Broker的投递速度。消息没有被及时消费
○ 消费者的处理逻辑变慢
○ 消费者线程池配置不合理、消费节点太少
○ 消息处理失败导致重复投递
# 如何解决
● 横向扩展:增加消费者的实例
○ RocketMQ的消费组支持动态扩缩容,同一消费者组内的消费者实例会自动分摊队列的负载
○ 关键条件:队列数量>=消费者数量 (4.x需要满足,5.x不需要)
● 纵向优化:提高消费者的处理能力
○ 调整消费者的线程数
○ 批量消费,聚合请求,批量写入
○ 降低外部服务延迟
# 如何预防
● 监控和告警
● 保证消费者拥有满足常规流量的消费能力
○ 确定单点消费者能力和消费者数量,使消费者拥有合理的资源。通过压测单个节点,不断调高线程数,观测系统指标,得到单个节点最优的消费线程数量和消息吞吐量。并根据上游的流量峰值计算需要的节点数
○ 提高单点消费性能。调整线程数、批量消费、优化耗时逻辑等
● 要具备应对突发流量的能力。发现消息堆积时及时扩容
○ 手动扩容
○ 云厂商的自动扩容
● 资源隔离,风险隔离
○ 物理隔离。核心业务和非核心业务使用各自MQ
○ 逻辑隔离。在同一个MQ中,通过NameSpace、Topic/Queue、Consumer Group角度进行逻辑隔离
# 参考书籍
《万亿级数据洪峰下的分布式消息引擎》