面试题之RocketMq

1. RocketMq的组成及各自的作用?

  • 在RocketMq中有四个部分组成,分别是Producer,Consumer,Broker ,以及NameServer,类比于生活中的邮局,分别是发信者,收信者,负责暂存,传输的邮局,以及协调各个地方邮局的管理机构。

  • NameServer

    主要是 Topic 和 Broker 注册中心,支持 Broker 动态注册和发现,主要保存 Topic的路由信息和Broker的状态信息。通常也是集群部署,但是各 NameServer 之间不会互相通信, 各 NameServer 都有完整的路由信息,即无状态(跟zk的区别是,zk为有状态的)。

  • Broker

    就是MQ本身,负责收发消息、持久化消息,每个broker负责管理一部分topic的消息;主要分为 Master Broker 和 Slave Broker,一个 Master Broker 可以对应多个 Slave Broker,但是一个 Slave Broker 只能对应一个 Master Broker。Master与Slave的对应关系通过指定相同的BrokerName,不同的BrokerId来定义,BrokerId为0表示Master,非0表示Slave。Master也可以部署多个。每个Broker与Name Server集群中的所有节点建立长连接,定时注册Topic信息到所有Name Server。Broker 启动后需要完成一次将自己注册至 Name Server 的操作。

  • Producer :消息生产者

    可以集群部署。它会先和 NameServer 集群中的随机一台建立长连接,得知当前要发送的 Topic 存在哪台 Broker Master上,然后再与其建立长连接,支持多种负载平衡模式发送消息。

  • Consumer :消息消费者

    可以集群部署。它也会先和 NameServer 集群中的随机一台建立长连接,得知当前要消息的 Topic 存在哪台 Broker Master、Slave上,然后它们建立长连接,支持集群消费和广播消费消息。

  • Topic :

    标识一类消息的逻辑名字,消息的逻辑管理单位。无论消息是生产还是消费都需要指定Topic;比如电商系统可以分为:交易消息、物流消息,每条消息都必须有一个topic,一个类型的消息可以定义一个topic,也可以定义多个,根据业务需求来定;

  • Tag :

    可以看作子主题,它是消息的第二级类型,同一业务模块不同目的的消息就可以用相同 Topic 而不同的 Tag 来标识。比如交易消息又可以分为:交易创建消息、交易完成消息等,一条消息可以没有 Tag ;虽然同一个topic的管理逻辑一样,但是消费topic1的时候,如果你订阅指定的是tagA,那么tagB的消息不会投递。

  • Group

    分组,一个组可以订阅多个Topic,代表某一类的生产者和消费者,一般来说同一个服务可以做为Group,同一个Group一般来说发送和消费的消息都是一样的。

  • Queue

    队列其实就是对Topic的分片,在Kafka里面就是Partition。将Topic分片再切分为若干等分,其中的一份就是一个Queue。每个Topic分片等分的Queue的数量可以不同,由用户在创建Topic时指定。这些队列会被RocketMQ均衡的分布在不同Broker上,Producer在发送消息时会根据一定策略选择一个消息队列进行发送,这样就可以实现负载均衡和提高吞吐的效果。

  • Offset

    偏移,本质上有两种Offset,一种是写入时末尾的Offset,另一种是同一消费组读的Offset。RocketMq消息内容是分片存储,CommitLog 的大小默认是1G,当超过大小限制的时候需要准备新的文件,CommitLog 采用混合型存储,也就是所有 Topic 都存在一起,顺序追加写入,文件名用起始偏移量命名。其次RocketMq还存储了消息体与偏移的关系,用于快速随机读取和检索。

2. 为什么使用消息队列?

最开始的时候业务量小,直接单机能解决,后来业务量大,采用微服务的设计思想,分布式部署的方式,拆出了很多服务,场景也就越来越复杂,所以引用了消息队列。

3. 为什么要用RocketMq?

削峰 :在高并发场景下,系统的请求量可能会瞬间增加,给服务器带来巨大的压力。通过使用消息队列,可以将突发的大量请求进行缓冲和削峰,使其平滑地处理,从而避免服务器过载和崩溃;
异步 :如果下单流程涉及多个系统,影响支付时间,所以支付同时完成其他工作去校验;
解耦:可以将系统的各个模块解耦,减少模块之间的直接依赖。这样可以使各个模块独立地进行开发和部署,提高系统的可扩展性和灵活性。同时,解耦也可以降低系统间的耦合度,提高系统的可维护性和稳定性;

限流:通过控制消息的生产者和消费者的速度,可以限制系统的流量,防止过多的请求对服务器造成过大的压力。

4. RocketMq的优点?

  • 单机吞吐量:十万级别;
  • 可用性:分布式架构,可用性强;
  • 消息可靠性:MQ的功能较为完善,还是分布式的扩展性好;
  • 支持10亿级别的消息堆积,不会因为堆积的性能下降;
  • Java源码,可二次开发;
  • 适用于可靠性要求要求高的场景;
  • 稳定性搞,经过阿里系统的考验;

5. RocketMq的缺点?

  • 支持语言不多:Java和C++(不成熟);
  • 移植复杂:没有引入JMS等接口,系统迁移需要改大量代码;
  • 系统可用性降低 :系统引入的外部依赖越多,越容易挂掉。万一 MQ 挂了,MQ 一挂,整套系统崩 溃,你不就完了?
  • 系统复杂度提高 :硬生生加个 MQ 进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况? 怎么保证消息传递的顺序性?问题一大堆。
  • 一致性问题 :A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致 了。

6. RocketMq的顺序消费?

不能保证全局顺序消费,只能保证单个queue里的顺序,queue是典型的FIFO;

7. RocketMq的重复消费以及怎么解决?

影响重复消费的主要原因是网络原如下:

  • 生产者没有接受到消费者的结果;
  • 消费成功没有返回ack;
  • 消费成功但是宕机了;

解决办法:

RocketMQ重复消费的问题可以通过以下几种方式解决:

  • 分布式锁:在生产环境中,通常都是多元jvm集群环境,当RocketMQ系统投递重复消息时,可能会造成数据库重复消费。此时可以采用分布式锁,通过zookeeper和redis搭建,解决消息重复的甄别问题。
  • 数据库约束+java异常处理机制:首先需要针对数据库简历约束,不允许产生重复数据,然后再使用java的异常处理机制来规避重复消息。
  • 幂等性处理:消费者端要自己保证消费的幂等性,例如消费者收到消息后,从消息中获取消息标识写入到Redis或数据库,当再次收到该消息时就不作处理。
  • 负载均衡阶段重复听或漏听的问题:微众银行在负载均衡结果变化过程增加了一个过渡态,在过渡态的时候,Consumer会继续保留上一次负载均衡的结果,直到原消费者拉取的消息全部ack,才释放老的结果。改造的实现是在RocketMQ的Broker端增加了一个ConsumeQueueAccessLockManager类,对Queue加了锁。

8. RocketMq的消息丢失

Producer端

利用自带的事务处理机制,发送half信息,如果正常就处理,不正常就回滚;
Broker端

  • 没来得及持久化,由异步刷盘改为同步刷盘;
  • 集群部署,主从模式,高可用;
    Consumer端
  • 消费完成后,手动确认ack;

9. RocketMq的消费失败

  • 默认重试16次(会导致重复消费的问题),否则会进入死信队列;
  • 死信解决办法:让mq重新发消息,然后消费消息,看问题所在;
  • 死信队列三天后会自动删除,查看死信队列可视化工具-rocket mq console

10. RocketMq的消息堆积

  • consumer端增加消费者,扩容;
  • 熔断隔离:一个Broker积压将其熔断隔离,发送其他队列
  • broker:扩容
  • producer:限流

11. RocketMq的延时消息

-发送消息不会被及时消费,比如关闭超时未支付订单,下单30分钟后支付启动定时,隔几秒去扫描待支付的订单

12. RocketMq Broker 中的消息被消费后会立即删除么?那么消息会堆积么?

  • 不会,每条消息都会持久化到commitLog中,每个Consumer连接到Broker后会维持消费进度信息,当有消息消费后只是当前Consumer的消费进度(commitLog的offset)更新了;
  • 默认72小时后会删除不再使用的Commitlog文件;

13. RocketMq什么时候清理过期消息?

  • 消息文件过期(默认72小时)且到达清理时间点(默认是凌晨4点)后,会自动清理过期文件。
  • 消息文件过期(默认72小时)且磁盘空间占用率已达过期清理警戒线(默认75%)后,无论是否达到清理时间点,都会自动清理过期文件。
  • 磁盘占用率达到清理警戒线(默认85%)后,开始按照设定好的规则清理文件,无论是否过期。

14. RocketMq消费模式有几种?

消费模型由Consummer决定,消费维度为topic

集群消费:默认的模式

  • 一条消息只会被同Group中的一个Consumer消费;
  • 多个Group同时消费一个Topic时,每个Group都会有一个Consumer消费到数据;
  • 根据队列分配策略算法,每个Consumer实例只会消费自己队列上的数据,消费完的消息不会被其他实例消费。这种模式适用于大部分消息业务,能够提高系统的稳定性和可用性

广播消费:同Topic下的消息会被多个实例共同消费。也就是说,如果一个Topic下有多个Consumer实例,那么每个消息会被所有的Consumer实例消费一次。这种模式适用于一些分发消息的场景,例如将消息同时发送给多个消费者进行处理。

15. RocketMq消息消费是push还是pull?

没有真正意义的push,都是pull,虽然有push类,但是实际底层是长轮训机制,即拉取方式;

16. RocketMq为什么是主动拉取而不是监听的方式?

  • 事件驱动方式是建立好长连接,由事件(发送数据)的方式来实时推送。
  • 如果 broker 主动推送消息的话有可能 push 速度快,消费速度慢的情况,那么就会造成消息在 consumer 端堆积过多,同时又不能被其他 consumer 消费的情况。
  • 而 pul 的方式可以根据当前自身情况来 pull,不会造成过多的压力而造成瓶颈。所以采取了 pull 的方式。

17. RocketMq Broker是如何拉取请求的?

RocketMQ的Broker在处理拉取请求时,会根据负载均衡策略选择一个负责处理该请求的Consumer实例。Broker将消息队列中存储的消息按照提交偏移量的顺序发送给Consumer实例。Consumer实例接收到消息后,会根据消费策略对消息进行处理,并将处理结果返回给Broker。Broker收到Consumer的处理结果后,会更新消息的消费状态,以便下次拉取时能够正确地发送。

18. RocketMq是如何做到负载均衡的?

Producer端 :发送端指定message queue发送消息到相应的broker,来达到写入时的负载均衡。同时,Producer还支持开启隔离机制,通过判断Broker是否被隔离以及是否是上一次选择的那个Broker,来避免将消息发送到不可用的Broker上。
Consumer端:默认情况下,Consumer会根据队列的平均值进行负载均衡,即将所有队列的平均值作为Broker的负载均衡值。如果某个Broker的负载均衡值高于其他Broker,那么Consumer会优先选择该Broker进行拉取请求。如果多个Broker的负载均衡值相同,则会根据优先级选择。

其他负载均衡算法:

  • 环形分配策略
  • 手动配置分配策略
  • 机房分配策略
  • 一致性哈希分配策略
  • 靠近机房策略

19. 当RocketMq的负载均衡consumer和queue不对等的时候会发生什么?

  • 如果consumer<queue的个数,会存在部分consumer消费多个queue的情况;
  • 如果consumer=queue的个数,一个consumer消费一个queue;
  • 如果consumer>queue的个数,部分consummer空余,会浪费。

20. RocketMq如何保证数据的高容错性?

  • 首先,RocketMQ采用消息持久化机制,将消息持久化到磁盘上,并通过刷盘机制保证数据不丢失。
  • 同时,RocketMQ还提供同步刷盘和异步刷盘两种方式,以满足不同场景的需求。
  • 其次,RocketMQ采用主从复制的方式来提高系统的可用性。对于每个队列,RocketMQ会为其创建一个主节点和多个从节点。主节点负责消息的写入,从节点负责消息的复制和读取。当主节点出现故障时,从节点会接替主节点的工作,确保消息的正常处理。
  • 此外,RocketMQ还具备故障恢复的能力。当RocketMQ服务端发生故障或宕机时,可以通过重启服务端来恢复。重启服务端后,RocketMQ会自动从上次的快照中恢复未被消费的消息,并继续处理后续消息。
  • 同时,RocketMQ还支持消息的重试机制。当消息发送失败时,RocketMQ会根据预设的重试次数和时间间隔进行消息的重试,直到消息发送成功或达到最大重试次数。这样可以保证消息的可靠传输,提高系统的容错性。
  • 最后,RocketMQ还通常使用自动的降级熔断策略,当性能达到阈值时就会自动开启。
  • 此外还会设置一个手动的降级开关,来人工开启降级流程。这样可以保证在面对故障或性能问题时,RocketMQ能够自动或手动地进行降级处理,保障服务的可用性和稳定性。

21. RocketMq任何一台Broker突然宕机了怎么办?

  • RocketMQ的Broker采用主从架构和多副本策略来解决Broker突然宕机的问题。具体来说,Master收到消息后会同步给Slave,这样一条消息就不止一份了,Master宕机了还有Slave中的消息可用,保证了MQ的可靠性和高可用性。

  • 如果Broker宕机,NameServer会感知到。Broker会定时向NameServer发送心跳,然后NameServer会定时运行一个任务,去检查一下各个Broker的最近一次心跳时间。如果某个Broker超过120s都没发送心跳了,那么就认为这个Broker已经挂掉了。

22. RocketMq的Broker会把信息注册到哪个NameServer上?

Broker启动的时候会向所有的NameServer节点进行注册,注意这里是向集群中所有的NameServer节点注册,而不是只向其中的某些节点注册,因为NameServer每个节点都是对等的,所以Broker需要向每一个节点进行注册,这样每一个节点都会有一份Broker的注册信息。

23. RocketMq的自动伸缩扩容的机制是什么?

  • RocketMQ的自动伸缩扩容机制主要基于Broker的负载情况。当Broker的负载过高时,会自动触发扩容操作,增加新的Broker实例来分担负载。扩容过程不需要人工干预,系统会自动完成。同时,当流量回归正常后,为了防止资源的浪费,可以自动缩容,将一些不必要的Broker实例移除。

  • 此外,RocketMQ还支持消息队列的动态扩容和缩容。在Topic的消息量特别大时,可以通过增加消息队列的数量来提高系统的处理能力。相反,如果消息队列的数量过多,也可以适当减少,以节约系统资源。

  • RocketMQ的自动伸缩扩容机制可以有效地提高系统的可用性和稳定性,同时避免了资源的浪费。在实际应用中,需要根据具体的需求和场景进行配置和调整,以达到最佳的效果。

24. RocketMq与Kafka的区别?

  • R支持定时重试,K消费失败不支持;
  • 都支持顺序消费,但是K宕机,消息乱序;
  • R支持定时消息、分布式消息、消息查询,K都不支持
  • R编写用Java,K用scale
  • R定位于非日志可靠消息传输,K主要定位于日志传输
  • R支持异步/同步刷盘,K支持异步实时刷盘

25. 让你手动来实现一个分布式消息中间件,整体架构你会如何设计?

设计一个分布式消息中间件需要考虑多个方面,包括消息的可靠性、一致性、性能、扩展性、容错性等。以下是一个可能的整体架构设计:

  • 消息队列服务(Message Queue Service):这是整个分布式消息中间件的核心,负责接收、存储和转发消息。它可以由多个节点组成,以实现高可用性和可扩展性。
  • 节点管理服务(Node Management Service):负责管理消息队列服务的节点,包括节点的添加、删除、监控等。它需要保证在节点故障时能够及时地发现并处理,以保证系统的稳定性和可用性。
  • 客户端代理服务(Client Proxy Service):提供给客户端使用的代理服务,负责与消息队列服务进行交互。客户端通过这个服务来发送和接收消息,而不需要直接与消息队列服务的节点进行通信。这样可以减少客户端与服务器之间的网络开销,提高系统的性能和稳定性。
  • 监控与日志服务(Monitoring and Logging Service):负责收集、处理和存储消息队列服务的运行状态和日志信息。通过这个服务,可以实时监控系统的运行状态,及时发现和处理问题,保证系统的稳定性和可靠性。
  • 配置管理服务(Configuration Management Service):负责管理消息队列服务的配置信息,包括节点配置、队列配置、订阅关系配置等。通过这个服务,可以方便地修改和配置消息队列服务的各项参数,以满足不同的业务需求。
  • 安全与认证服务(Security and Authentication Service):负责提供安全和认证功能,包括用户身份验证、访问控制、加密解密等。通过这个服务,可以保证消息的安全性和隐私性,防止敏感信息的泄露和未经授权的访问。
相关推荐
掘金-我是哪吒13 分钟前
分布式微服务系统架构第156集:JavaPlus技术文档平台日更-Java线程池使用指南
java·分布式·微服务·云原生·架构
亲爱的非洲野猪39 分钟前
Kafka消息积压的多维度解决方案:超越简单扩容的完整策略
java·分布式·中间件·kafka
wfsm42 分钟前
spring事件使用
java·后端·spring
微风粼粼1 小时前
程序员在线接单
java·jvm·后端·python·eclipse·tomcat·dubbo
缘来是庄1 小时前
设计模式之中介者模式
java·设计模式·中介者模式
rebel2 小时前
若依框架整合 CXF 实现 WebService 改造流程(后端)
java·后端
代码的余温3 小时前
5种高效解决Maven依赖冲突的方法
java·maven
慕y2743 小时前
Java学习第十六部分——JUnit框架
java·开发语言·学习
paishishaba3 小时前
Maven
java·maven
张人玉3 小时前
C# 常量与变量
java·算法·c#