高频经典RocketMQ面试题及答案,24道RockerMQ八股文,面渣逆袭必看

基础

1. 为什么要使用消息队列呢?

回答:
消息队列其实就是在不同系统之间传递消息的一个中间件。我们使用消息队列的原因主要有以下几个:

  • 解耦:比如说,用户下单后要同时通知库存系统、物流系统、支付系统。如果这些系统直接相互调用,一旦有一个系统挂掉,整个流程都会出问题。消息队列就像是个“传话筒”,只要把消息放进去,各个系统各自取用,互不干扰。

  • 异步处理:很多操作其实不需要马上完成,比如发送订单确认邮件。我们可以先把消息放到队列里,然后慢慢处理,提高系统响应速度。

  • 削峰填谷:在大促销的时候,订单量会激增,系统可能撑不住。消息队列能把大量请求暂存,慢慢处理,避免系统崩溃。

如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 一万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题,还有市面上最全的技术五百套,精品系列教程,免费提供。

2. 为什么要选择 RocketMQ?
方面RabbitMQActiveMQRocketMQKafka
公司/社区Pivotal (VMware) / 强大开源社区Apache Software Foundation / 强大开源社区Alibaba / 强大开源社区Apache Software Foundation / 强大开源社区
语言ErlangJavaJavaJava
协议支持AMQP, MQTT, STOMP, HTTPOpenWire, STOMP, MQTT, AMQP, HTTPRocketMQ 自定义协议, 支持部分 MQTT自定义协议 (Kafka协议), 支持部分 HTTP/REST
客户端支持语言Java, .NET, Python, Ruby, JavaScript, Go 等Java, .NET, C, C++, Python, Ruby, Perl, PHP 等Java, .NET, C++, Python 等Java, .NET, C/C++, Python, Go, Scala, JavaScript 等
单机吞吐量中等中等非常高
消息延迟低至中等中等低至中等
可用性高,通过集群和镜像队列实现高,通过集群和主从复制实现高,通过多主多从集群实现高,通过分布式集群和复制实现
消息可靠性高,通过持久化和镜像队列实现高,通过持久化和事务支持实现高,通过同步/异步刷盘和多副本机制实现高,通过分布式存储和复制实现
功能支持支持高级路由、消息确认、插件扩展支持消息路由、事务、持久化、JMS 规范支持顺序消息、延时消息、事务消息、广播、负载均衡支持高吞吐、低延迟、分布式日志存储、流处理
优势强大的路由功能,丰富的插件,支持多协议功能丰富,支持多协议,兼容 JMS 规范高性能,支持大规模消息处理,强大的分布式特性超高吞吐量,低延迟,适合大规模实时日志处理和流处理
劣势吞吐量相对较低,集群管理较复杂性能较低,吞吐量一般,配置和调优复杂生态系统较小,社区支持相对较少需要复杂的配置和调优,对小规模消息处理支持不友好
应用适用于需要复杂路由和协议支持的场景,如电商系统的订单处理适用于传统企业集成和兼容 JMS 的系统适用于大规模分布式系统,如金融支付系统适用于大数据和实时日志处理,如行为分析和监控

回答:
选择RocketMQ有几个原因:

  • 高可靠性:RocketMQ的数据可靠性很高,能保证消息不会丢失。比如用户支付成功的消息,必须要确保能送到订单系统,RocketMQ就能很好地保证这一点。
  • 功能丰富:它支持很多高级功能,比如顺序消息、事务消息、延时消息等。比如电商平台要确保支付成功后才发货,这就可以用到它的事务消息。
  • 性能不错:在高并发的情况下,RocketMQ能提供较低的延迟,保证消息快速传递。
  • 与阿里云集成好:如果我们的系统在阿里云上部署,RocketMQ能无缝对接阿里云的各种服务,非常方便。
3. RocketMQ 有什么优缺点?

回答:
优点

  • 高可靠性:RocketMQ能保证消息不丢失,这对关键业务很重要。
  • 功能丰富:支持顺序消息、事务消息、延时消息等,能满足复杂业务需求。
  • 低延迟:在高并发情况下,消息处理速度快,延迟低。
  • 与阿里云深度集成:使用阿里云的各种服务时非常方便。

缺点

  • 运维复杂:需要一定的运维经验和技巧,配置和调优比较复杂。
  • 社区和生态相对较小:相比Kafka,RocketMQ的社区支持和第三方工具较少,需要自己解决一些问题。
4. 消息队列有哪些消息模型?

回答:
消息队列的消息模型主要有两种:

  • 点对点模型:这个就像发短信,一条消息只会被一个消费者接收到。比如银行系统里的转账操作,只需要处理一次。

  • 发布/订阅模型:这个就像发广播,一条消息可以被多个消费者接收到。比如发布一个优惠券活动,所有用户都可以收到这个消息。

image.png

5. 那 RocketMQ 的消息模型呢?

回答:
RocketMQ支持发布/订阅模型。
这意味着,生产者(发布者)可以发布消息到一个主题(Topic),然后多个消费者(订阅者)可以订阅这个主题,接收并处理消息。
image.png

  • Message

Message(消息)就是要传输的信息。
一条消息必须有一个主题(Topic),主题可以看做是你的信件要邮寄的地址。
一条消息也可以拥有一个可选的标签(Tag)和额处的键值对,它们可以用于设置一个业务 Key 并在 Broker 上查找此消息以便在开发期间查找问题。

  • Topic

Topic(主题)可以看做消息的归类,它是消息的第一级类型。

比如一个电商系统可以分为:交易消息、物流消息等,一条消息必须有一个 Topic 。

Topic 与生产者和消费者的关系非常松散,一个 Topic 可以有 0 个、1 个、多个生产者向其发送消息,一个生产者也可以同时向不同的 Topic 发送消息。
一个 Topic 也可以被 0 个、1 个、多个消费者订阅。

  • Tag

Tag(标签)可以看作子主题,它是消息的第二级类型,用于为用户提供额外的灵活性。使用标签,同一业务模块不同目的的消息就可以用相同 Topic 而不同的 Tag 来标识。

比如交易消息又可以分为:交易创建消息、交易完成消息等,一条消息可以没有 Tag

标签有助于保持你的代码干净和连贯,并且还可以为 RocketMQ 提供的查询系统提供帮助。

  • Group

RocketMQ 中,订阅者的概念是通过消费组(Consumer Group)来体现的。每个消费组都消费主题中一份完整的消息,不同消费组之间消费进度彼此不受影响,也就是说,一条消息被 Consumer Group1 消费过,也会再给 Consumer Group2 消费。
消费组中包含多个消费者,同一个组内的消费者是竞争消费的关系,每个消费者负责消费组内的一部分消息。

默认情况,如果一条消息被消费者 Consumer1 消费了,那同组的其他消费者就不会再收到这条消息。

  • Message Queue

Message Queue(消息队列),一个 Topic 下可以设置多个消息队列,Topic 包括多个 Message Queue ,如果一个 Consumer 需要获取 Topic 下所有的消息,就要遍历所有的 Message Queue。

RocketMQ 还有一些其它的 Queue——例如 ConsumerQueue。

  • Offset

在 Topic 的消费过程中,由于消息需要被不同的组进行多次消费,所以消费完的消息并不会立即被删除,这就需要 RocketMQ 为每个消费组在每个队列上维护一个消费位置(Consumer Offset),这个位置之前的消息都被消费过,之后的消息都没有被消费过,每成功消费一条消息,消费位置就加一。

也可以这么说,Queue 是一个长度无限的数组,Offset 就是下标。

RocketMQ 的消息模型中,这些就是比较关键的概念了

6. 消息的消费模式了解吗?

回答:
消息消费模式有两种:Clustering(集群消费)和Broadcasting(广播消费)

默认情况下就是集群消费,这种模式下一个消费者组共同消费一个主题的多个队列,一个队列只会被一个消费者消费,如果某个消费者挂掉,分组内其它消费者会接替挂掉的消费者继续消费。
而广播消费消息会发给消费者组中的每一个消费者进行消费。

如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 一万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题,还有市面上最全的技术五百套,精品系列教程,免费提供。

7. RocketMQ 基本架构了解吗?

回答:
RocketMQ的基本架构

RocketMQ 一共有四个部分组成:NameServer,Broker,Producer 生产者,Consumer 消费者,它们对应了:发现、发、存、收,为了保证高可用,一般每一部分都是集群部署的

8. 那能介绍一下这四部分吗?

回答:
当然:
类比一下我们生活的邮政系统——
邮政系统要正常运行,离不开下面这四个角色, 一是发信者,二 是收信者, 三是负责暂存传输的邮局, 四是负责协调各个地方邮局的管理机构。对应到 RocketMQ 中,这四个角色就是 Producer、 Consumer、 Broker 、NameServer。
weixin-mianznxrocketmqessw-00175355-5532-4ee6-a48c-e3e3a9b87d64.jpg

NameServer

NameServer 是一个无状态的服务器,角色类似于 Kafka 使用的 Zookeeper,但比 Zookeeper 更轻量。
特点:

  • 每个 NameServer 结点之间是相互独立,彼此没有任何信息交互。
  • Nameserver 被设计成几乎是无状态的,通过部署多个结点来标识自己是一个伪集群,Producer 在发送消息前从 NameServer 中获取 Topic 的路由信息也就是发往哪个 Broker,Consumer 也会定时从 NameServer 获取 Topic 的路由信息,Broker 在启动时会向 NameServer 注册,并定时进行心跳连接,且定时同步维护的 Topic 到 NameServer。

功能主要有两个:

  • 1、和 Broker 结点保持长连接。
  • 2、维护 Topic 的路由信息。
Broker

消息存储和中转角色,负责存储和转发消息。

  • Broker 内部维护着一个个 Consumer Queue,用来存储消息的索引,真正存储消息的地方是 CommitLog(日志文件)。

RocketMQ存储-图片来源官网

  • 单个 Broker 与所有的 Nameserver 保持着长连接和心跳,并会定时将 Topic 信息同步到 NameServer,和 NameServer 的通信底层是通过 Netty 实现的。
Producer

消息生产者,业务端负责发送消息,由用户自行实现和分布式部署。

  • Producer由用户进行分布式部署,消息由Producer通过多种负载均衡模式发送到Broker集群,发送低延时,支持快速失败。
  • RocketMQ 提供了三种方式发送消息:同步、异步和单向
  • 同步发送:同步发送指消息发送方发出数据后会在收到接收方发回响应之后才发下一个数据包。一般用于重要通知消息,例如重要通知邮件、营销短信。
  • 异步发送:异步发送指发送方发出数据后,不等接收方发回响应,接着发送下个数据包,一般用于可能链路耗时较长而对响应时间敏感的业务场景,例如用户视频上传后通知启动转码服务。
  • 单向发送:单向发送是指只负责发送消息而不等待服务器回应且没有回调函数触发,适用于某些耗时非常短但对可靠性要求并不高的场景,例如日志收集。
Consumer

消息消费者,负责消费消息,一般是后台系统负责异步消费。

  • Consumer也由用户部署,支持 PUSH 和 PULL 两种消费模式,支持集群消费广播消费,提供实时的消息订阅机制
  • Pull:拉取型消费者(Pull Consumer)主动从消息服务器拉取信息,只要批量拉取到消息,用户应用就会启动消费过程,所以 Pull 称为主动消费型。
  • Push:推送型消费者(Push Consumer)封装了消息的拉取、消费进度和其他的内部维护工作,将消息到达时执行的回调接口留给用户应用程序来实现。所以 Push 称为被动消费类型,但其实从实现上看还是从消息服务器中拉取消息,不同于 Pull 的是 Push 首先要注册消费监听器,当监听器处触发后才开始消费消息。

进阶

9. 如何保证消息的可用性/可靠性/不丢失呢?

回答:
保证消息的可靠性主要有以下几种方法:

  • 持久化:消息写入磁盘,防止因为系统崩溃导致消息丢失。RocketMQ默认情况下会将消息持久化到磁盘。
  • 多副本机制:一条消息在多个Broker节点上保存副本,即使某个节点故障,消息也不会丢失。
  • 确认机制:消费者处理完消息后,需要向Broker发送确认(ack),只有收到确认后,Broker才会删除消息,确保消息被成功处理。
  • 事务消息:在业务操作和消息发送之间实现事务控制,确保两者要么都成功,要么都失败,避免消息和业务数据不一致。

那么消息可能在哪些阶段丢失呢?可能会在这三个阶段发生丢失:生产阶段、存储阶段、消费阶段。
所以要从这三个阶段考虑:

生产

在生产阶段,主要通过请求确认机制,来保证消息的可靠传递

  • 1、同步发送的时候,要注意处理响应结果和异常。如果返回响应 OK,表示消息成功发送到了 Broker,如果响应失败,或者发生其它异常,都应该重试。
  • 2、异步发送的时候,应该在回调方法里检查,如果发送失败或者异常,都应该进行重试。
  • 3、如果发生超时的情况,也可以通过查询日志的 API,来检查是否在 Broker 存储成功。
存储

存储阶段,可以通过配置可靠性优先的 Broker 参数来避免因为宕机丢消息,简单说就是可靠性优先的场景都应该使用同步。

  • 1、消息只要持久化到 CommitLog(日志文件)中,即使 Broker 宕机,未消费的消息也能重新恢复再消费。
  • 2、Broker 的刷盘机制:同步刷盘和异步刷盘,不管哪种刷盘都可以保证消息一定存储在 pagecache 中(内存中),但是同步刷盘更可靠,它是 Producer 发送消息后等数据持久化到磁盘之后再返回响应给 Producer。

同步刷盘和异步刷盘-图片来源官网

  • 3、Broker 通过主从模式来保证高可用,Broker 支持 Master 和 Slave 同步复制、Master 和 Slave 异步复制模式,生产者的消息都是发送给 Master,但是消费既可以从 Master 消费,也可以从 Slave 消费。同步复制模式可以保证即使 Master 宕机,消息肯定在 Slave 中有备份,保证了消息不会丢失。
消费

从 Consumer 角度分析,如何保证消息被成功消费?

  • Consumer 保证消息成功消费的关键在于确认的时机,不要在收到消息后就立即发送消费确认,而是应该在执行完所有消费业务逻辑之后,再发送消费确认。
  • 因为消息队列维护了消费的位置,逻辑执行失败了,没有确认,再去队列拉取消息,就还是之前的一条。
10. 如何处理消息重复的问题呢?

回答:
处理消息重复的问题,可以采用以下几种策略:

  • 幂等性:设计业务逻辑时,确保同一条消息多次处理的结果是一致的。比如,更新库存时,先查询当前库存,如果已经更新过,则忽略重复的更新操作。
  • 唯一标识:每条消息分配一个唯一ID,消费者在处理消息时,先检查这个ID是否已经处理过。如果已经处理过,就跳过,避免重复处理。
  • 消息去重表:在数据库中维护一个去重表,记录已经处理过的消息ID。处理消息前,先查询这个表,看消息是否已经处理过。

image.png

如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 一万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题,还有市面上最全的技术五百套,精品系列教程,免费提供。

11. 怎么处理消息积压?

消息积压是指消息队列中的消息在一定时间内无法被及时消费,造成队列中的消息越来越多的情况。处理消息积压的方式可以从以下几个方面考虑:

  1. 增加消费者数量:最直接的方法就是增加消费者实例,提升消息的消费速度。在电商系统中,比如订单生成时,如果订单处理的消费者过少,可以临时增加消费者实例来处理积压的订单。
  2. 提升消费者性能:优化消费者的处理逻辑,减少每条消息的处理时间。比如优化数据库操作、减少不必要的网络调用等。
  3. 扩展消费者的并发处理能力:可以使用多线程或异步处理来提升单个消费者的处理能力。例如,订单处理服务可以对不同类型的订单进行并行处理。
  4. 流控与限流:通过限制生产者的发送速率,防止消息过快积压,缓解消费者的压力。
  5. 分析积压原因:从系统整体架构上分析,是否因为某些服务的性能瓶颈导致消息处理速度跟不上。例如,数据库写入速度慢、网络带宽不足等问题。

12. 顺序消息如何实现?

顺序消息是指严格按照消息发送的顺序进行消费,这在某些场景下非常重要,比如订单状态更新。要实现顺序消息,可以采用以下方法:

  1. 使用单个队列:一个队列中的消息天然是有序的。确保所有需要按顺序处理的消息发送到同一个队列中。

weixin-mianznxrocketmqessw-8e98ac61-ad47-4ed4-aac6-223201f9aae2.jpg

  1. 分区策略:可以使用分区(Partition)来保证局部有序。在电商系统中,可以根据订单ID进行分区,不同分区的消息可以并行处理,但同一订单的所有消息会进入同一个分区,从而保证顺序。

weixin-mianznxrocketmqessw-14ab3700-8538-473e-bb66-8acfdd6a77a2.jpg

  1. 消费端顺序保证:消费者在处理消息时,也需要按照顺序进行处理。例如,可以在消费者内部使用一个有序队列来处理接收到的消息。

13. 如何实现消息过滤?

消息过滤指的是在消息被消费之前,根据一定的规则筛选出需要处理的消息。常见的实现方法有:

  1. 消息标签(Tag):在消息头部添加标签,消费者只订阅特定标签的消息。例如,在电商系统中,不同类型的订单(普通订单、促销订单)可以打上不同的标签,消费者只订阅自己关心的标签。
  2. 消息属性过滤:利用消息属性进行过滤。生产者在发送消息时设置一些属性,消费者根据属性过滤消息。
  3. 消费端过滤:将所有消息都推送给消费者,消费者自行过滤不需要处理的消息。虽然这种方法较为简单,但会增加网络和处理的负担。

14. 延时消息了解吗?

延时消息指的是消息在发送后不会立即被消费,而是经过一段时间延迟后再进行处理。在电商系统中,可以用来实现以下场景:

  1. 订单支付超时取消:用户下单后,如果在规定时间内未完成支付,可以使用延时消息来自动取消订单。
  2. 库存回滚:促销活动中,如果用户在一定时间内未支付,自动释放锁定的库存。

实现延时消息的方法有:

  1. 消息队列的延时功能:一些消息队列中(如RabbitMQ、RocketMQ)自带延时消息的功能。
  2. 定时任务调度:在消息被生产后,记录消息时间,定期扫描并触发处理。

值得注意的是:目前 RocketMQ 支持的延时级别是有限的,仅支持以下时间的延迟

private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
RocketMQ 怎么实现延时消息的?

简单,八个字:临时存储+定时任务。
Broker 收到延时消息了,会先发送到主题(SCHEDULE_TOPIC_XXXX)的相应时间段的 Message Queue 中,然后通过一个定时任务轮询这些队列,到期后,把消息投递到目标 Topic 的队列中,然后消费者就可以正常消费这些消息。
weixin-mianznxrocketmqessw-e3b68480-8006-4cd6-892a-1c72f8b0fbcb.jpg

如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 一万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题,还有市面上最全的技术五百套,精品系列教程,免费提供。

15. 怎么实现分布式消息事务的?半消息?

半消息:是指暂时还不能被 Consumer 消费的消息,Producer 成功发送到 Broker 端的消息,但是此消息被标记为 “暂不可投递” 状态,只有等 Producer 端执行完本地事务后经过二次确认了之后,Consumer 才能消费此条消息。
依赖半消息,可以实现分布式消息事务,其中的关键在于二次确认以及消息回查:
weixin-mianznxrocketmqessw-76df2fb9-0f3f-496d-88a8-aac79ad1102c.jpg

  • 1、Producer 向 broker 发送半消息
  • 2、Producer 端收到响应,消息发送成功,此时消息是半消息,标记为 “不可投递” 状态,Consumer 消费不了。
  • 3、Producer 端执行本地事务。
  • 4、正常情况本地事务执行完成,Producer 向 Broker 发送 Commit/Rollback,如果是 Commit,Broker 端将半消息标记为正常消息,Consumer 可以消费,如果是 Rollback,Broker 丢弃此消息。
  • 5、异常情况,Broker 端迟迟等不到二次确认。在一定时间后,会查询所有的半消息,然后到 Producer 端查询半消息的执行情况。
  • 6、Producer 端查询本地事务的状态
  • 7、根据事务的状态提交 commit/rollback 到 broker 端。(5,6,7 是消息回查)
  • 8、消费者段消费到消息之后,执行本地事务,执行本地事务。

16. 死信队列知道吗?

死信队列(DLQ)是指无法被正常消费的消息会被转移到一个专门的队列中。常见的原因有:

  1. 消息被拒绝(Rejection):消费者处理消息失败,拒绝接收消息。
  2. 消息过期(Expiration):消息在队列中等待时间过长,超出了设置的TTL(Time-To-Live)。
  3. 重试次数超限:消息多次投递失败,达到最大重试次数。

在电商系统中,可以用死信队列来监控和处理异常订单消息。

例如,订单处理失败的消息进入死信队列后,可以定期人工处理或发送告警。

死信消息的特点

  • 不会再被消费者正常消费。
  • 有效期与正常消息相同,均为 3 天,3 天后会被自动删除。因此,需要在死信消息产生后的 3 天内及时处理。

死信队列的特点

  • 一个死信队列对应一个 Group ID, 而不是对应单个消费者实例。
  • 如果一个 Group ID 未产生死信消息,消息队列 RocketMQ 不会为其创建相应的死信队列。
  • 一个死信队列包含了对应 Group ID 产生的所有死信消息,不论该消息属于哪个 Topic。

RocketMQ 控制台提供对死信消息的查询、导出和重发的功能。

17. 如何保证 RocketMQ 的高可用?

RocketMQ 的高可用性可以通过以下几个方面来保证:

  1. 集群部署:通过多主多从的集群架构,保证即使部分节点故障,系统仍能正常工作。
  2. 主从同步:使用同步刷盘和异步复制,保证消息在主节点和从节点都有备份,主节点故障时可以快速切换到从节点。
  3. 自动故障转移:RocketMQ 可以自动检测节点故障并进行主从切换,保证系统的持续可用。
  4. 多机房部署:在不同机房部署多个节点,防止单点故障导致整体系统不可用。
  5. 消息持久化:使用可靠的持久化机制,保证消息不会因为节点故障而丢失。
NameServer高可用

NameServer 因为是无状态,且不相互通信的,所以只要集群部署就可以保证高可用。

Broker高可用

Broker的高可用主要通过集群部署+主从架构来实现
weixin-mianznxrocketmqessw-76c5eb61-9605-4620-84fb-dc960f01de85.jpg
Broker 可以配置两种角色:Master 和 Slave,Master 角色的 Broker 支持读和写,Slave 角色的 Broker 只支持读,Master 会向 Slave 同步消息。
也就是说 Producer 只能向 Master 角色的 Broker 写入消息,Cosumer 可以从 Master 和 Slave 角色的 Broker 读取消息。

Producer(发送端)的高可用

如何达到发送端写的高可用性呢?

在创建 Topic 的时候,把 Topic 的多个 Message Queue 创建在多个 Broker 组上(相同 Broker 名称,不同 brokerId 机器组成 Broker 组),这样当 Broker 组的 Master 不可用后,其他组 Master 仍然可用, Producer 仍然可以发送消息

值得注意的是:RocketMQ 目前还不支持把 Slave 自动转成 Master ,如果机器资源不足,需要把 Slave 转成 Master ,则要手动停止 Slave 色的 Broker ,更改配置文件,用新的配置文件启动 Broker。

Consumer(消费端)的高可用

Consumer 的配置文件中,并不需要设置是从 Master 读还是从 Slave 读,当 Master 不可用或者繁忙的时候, Consumer 的读请求会被自动切换到从 Slave。有了自动切换 Consumer 这种机制,当一个 Master 角色的机器出现故障后,Consumer 仍然可以从 Slave 读取消息,不影响 Consumer 读取消息,这就实现了读的高可用。

如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 一万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题,还有市面上最全的技术五百套,精品系列教程,免费提供。

原理

18. 说一下 RocketMQ 的整体工作流程?

简单来说,RocketMQ 是一个分布式消息队列,也就是消息队列+分布式系统。
作为消息队列,它是发-存-收的一个模型,对应的就是 Producer、Broker、Cosumer;
作为分布式系统,它要有服务端、客户端、注册中心,对应的就是 Broker、Producer/Consumer、NameServer
所以我们看一下它主要的工作流程
RocketMQ 由 NameServer 注册中心集群、Producer 生产者集群、Consumer 消费者集群和若干 Broker(RocketMQ 进程)组成:

  1. Broker 在启动的时候去向所有的 NameServer 注册,并保持长连接,每 30s 发送一次心跳
  2. Producer 在发送消息的时候从 NameServer 获取 Broker 服务器地址,根据负载均衡算法选择一台服务器来发送消息
  3. Conusmer 消费消息的时候同样从 NameServer 获取 Broker 地址,然后主动拉取消息来消费

weixin-mianznxrocketmqessw-ec571bd4-fa24-4ada-87ab-f761a7dfdf3f.jpg

19. 为什么 RocketMQ 不使用 Zookeeper 作为注册中心呢?

RocketMQ 在设计上避免使用 Zookeeper 作为注册中心,主要原因有以下几点:

  1. 简化架构:不依赖外部系统,减少系统复杂度和依赖性,降低维护成本。
  2. 性能考虑:使用 Zookeeper 作为注册中心会带来额外的网络通信和延迟,而 RocketMQ 内部实现的 NameServer 可以更高效地处理注册和路由信息。
  3. 灵活性:RocketMQ 的 NameServer 实现更符合其自身的需求,能够提供更加灵活的负载均衡和故障转移机制。

20. Broker 是怎么保存数据的呢?

RocketMQ 的 Broker 主要通过以下几个文件来保存数据:

  1. CommitLog:这是消息存储的核心文件,所有的消息都先写入 CommitLog。它是一个顺序写的日志文件,写入性能高。
  2. ConsumeQueue:这是消息的逻辑队列,存储了消息在 CommitLog 中的物理偏移量、消息大小和消息的 Tag 哈希值。每个 Topic 下的每个队列都有一个对应的 ConsumeQueue。
  3. IndexFile:这是消息的索引文件,存储了消息的索引信息,可以通过消息的 Key 快速查找消息。

这些文件都存储在磁盘上,Broker 会定期进行刷盘操作,将内存中的数据写入磁盘,保证消息的持久性。

21. 说说 RocketMQ 怎么对文件进行读写的?

RocketMQ 对文件的读写主要通过内存映射(Memory Mapping)和顺序读写来实现:

  1. 零拷贝:RocketMQ 使用 Java 的 MappedByteBuffer 将文件映射到内存,方便快速读写操作。这种方式可以直接操作内存,而不是通过系统调用读写文件,提升了性能。
  2. 顺序写:所有的消息都按顺序写入 CommitLog,这种方式避免了随机写带来的磁盘寻址开销,提高了写入性能。
  3. 异步刷盘:RocketMQ 支持异步刷盘,即消息写入内存后立即返回,后台线程负责将内存数据批量写入磁盘。这种方式可以提高写入吞吐量,但会有一定的数据丢失风险。
  4. 随机读:读取消息时,通过 ConsumeQueue 或 IndexFile 定位消息在 CommitLog 中的位置,然后从 CommitLog 中读取消息。读取操作相对复杂,需要进行一定的随机读,但由于有索引和顺序读的特性,性能仍然较高。
说说什么是零拷贝?

在操作系统中,使用传统的方式,数据需要经历几次拷贝,还要经历用户态/内核态切换。
传统文件传输

  1. 从磁盘复制数据到内核态内存;
  2. 从内核态内存复制到用户态内存;
  3. 然后从用户态内存复制到网络驱动的内核态内存;
  4. 最后是从网络驱动的内核态内存复制到网卡中进行传输。

所以,可以通过零拷贝的方式,减少用户态与内核态的上下文切换内存拷贝的次数,用来提升 I/O 的性能。零拷贝比较常见的实现方式是mmap,这种机制在 Java 中是通过 MappedByteBuffer 实现的。

22. 消息刷盘怎么实现的呢?

RocketMQ 的消息刷盘主要有两种模式:

  1. 同步刷盘
    • 每次消息写入 CommitLog 后,立即将数据写入磁盘并等待刷盘完成。
    • 这种模式下,消息的可靠性高,但写入性能较低。
  2. 异步刷盘
    • 消息写入 CommitLog 后,只是将数据写入内存(PageCache),由后台线程定期将内存数据批量刷盘到磁盘。
    • 这种模式下,写入性能高,但在系统故障时可能会有少量数据丢失。

RocketMQ 允许用户根据实际需求选择刷盘模式,以在性能和数据可靠性之间取得平衡。

23. 能说下 RocketMQ 的负载均衡是如何实现的?

RocketMQ 的负载均衡主要体现在消息的生产和消费两个方面:

  1. 消息生产
    • 生产者在发送消息时,会根据负载均衡策略选择一个 Broker。
    • 常用的策略有轮询(Round-Robin)、随机选择(Random)等。
  2. 消息消费
    • 消费者从 Topic 的多个队列中拉取消息,每个消费者负责一部分队列。
    • RocketMQ 使用了均衡算法(如哈希、轮询)将队列分配给不同的消费者。
    • 当消费者数量变化时(如有新消费者加入或老消费者退出),RocketMQ 会重新分配队列,确保负载均衡。

这种设计保证了系统的高可用性和高性能,同时也能灵活适应不同的负载情况。

24. RocketMQ 消息长轮询了解吗?

长轮询(Long Polling)是一种消息消费的优化策略,用于降低消息拉取的延迟和网络开销。其工作原理如下:

  1. 普通轮询
    • 消费者定期向 Broker 拉取消息,如果没有新消息,则返回空结果并等待一段时间后再次拉取。
    • 这种方式在消息量较少时会频繁发起无效请求,浪费带宽和资源。
  2. 长轮询
    • 消费者向 Broker 发起拉取请求,如果 Broker 中没有新消息,则保持连接一段时间(如 30 秒)。
    • 在这段时间内,如果有新消息到达,Broker 会立即返回消息给消费者;如果超时还没有新消息,则返回空结果。
    • 这种方式减少了无效请求,提高了消息拉取的实时性和效率。

在电商系统中,使用长轮询可以提高订单处理、库存更新等操作的实时性,提升用户体验。

最后说一句(求关注,求赞,别白嫖我)

**最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。这是大佬写的, **7701页的BAT大佬写的刷题笔记,让我offer拿到手软

本文,已收录于,我的技术网站 【cxykk.com:程序员编程资料站】,有大厂完整面经,工作技术,架构师成长之路,等经验分享

求一键三连:点赞、分享、收藏

点赞对我真的非常重要!在线求赞,加个关注我会非常感激!

  • 19
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值