复盘女朋友面试4个月的RocketMQ面试题

又来了,这是复盘第六波女朋友面试4个月的面试题,本次是关于RocketMQ的专题

在分布式系统中,消息队列是一个使用场景非常丰富的技术。我们通常会用来作为异步通信,系统解耦,海量请求或者数据的削峰填谷,也可能使用延迟消息或者顺序消息完成特殊场景的业务功能。

消息队列产品有Kafka,RocketMQ, rabbitmq, 是市面上使用比较多的一个中间件, 也是Java后端面试中命中率较高的专题。

还是老套路,高频的面试题已经标星,有面试需要的同学可以先点星星收藏起来

架构相关题目

  • 说说RocketMQ架构组成有哪些?

哈哈,这个题目是不是就是传说中的送分题?我们如果使用过RocketMQ一般都可以回答出这个答案。

RocketMQ由生产者,消费者,broker,nameserver四个组件组成。前面三者都会和nameserver通信,nameserver可以理解成注册中心,他会存储所有生产者,消费者,broker的信息。broker是支持高可用的,他支持集群和主从模式。我们脑海里如果记住有下面这幅图就能解答这个问题了。

rocketMQ官网也有这部分的这部分更加详细的介绍。认识RocketMQ

使用姿势

  • 在集群消费模式下,16个消费者,8个写队列,有什么问题?

回答这个问题,需要知道Rocketmq负载均衡机制,默认使用平均分配策略,并且一个消费者最小消费的单元是队列。所以如果消费者数量比队列数大的时候,大于队列的消费者是无法消费到消息的,下面是RocketMQ官网给出的图:

因此,我们一定要合理规划topic下的队列数量。

功能原理相关题目

  • 顺序消息原理

这个问题需要从生产者和消费者,broker三端来解答,因为顺序消息需要三端配合。

  1. 生产者

生产者发送消息时候需要根据自己的业务规则,实现MessageQueueSelector接口的select方法,计算当前消息路由到哪个队列去。

java 复制代码
//队列负载均衡
public interface MessageQueueSelector {
    MessageQueue select(final List<MessageQueue> mqs, final Message msg, final Object arg);
}
//发送消息
SendResult sendResult = producer.send(msg, new MessageQueueSelector() {
                    @Override
                    public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
                        //arg 业务id
                        Integer id = (Integer) arg;
                        //生成订单 , 支付订单 保持顺序
                        System.out.println("订单id:"+id);
                        int index = id % mqs.size();
                        return mqs.get(index);
                    }
                }, orderId);
  1. 消费者

消费端消费的时候,consumer首先会向broker申请加锁,发送topic,queueId,clientId给broker,broker只会让这个消费者拉取对应队列的消息。

java 复制代码
for (MessageQueue mq : mqs) {

if (this.isLocked(group, mq, clientId)) {
    lockedMqs.add(mq);
} else {
    notLockedMqs.add(mq);
}
}

真正消费的地方,consumer还会加锁。

先对MessageQueue加锁

java 复制代码
public Object fetchLockObject(final MessageQueue mq) {
        Object objLock = this.mqLockTable.get(mq);
        if (null == objLock) {
            objLock = new Object();
            Object prevLock = this.mqLockTable.putIfAbsent(mq, objLock);
            if (prevLock != null) {
                objLock = prevLock;
            }
        }

        return objLock;
    }

真正处理消息前对processQueue加锁,保证当前消息队列Queue只被1个线程处理

java 复制代码
try {
      //对处理队列加锁
      this.processQueue.getLockConsume().lock();
      //调用业务逻辑处理消息
      status = messageListener.consumeMessage(Collections.unmodifiableList(msgs), context);
  } catch (Throwable e) {
      hasException = true;
  } finally {
      //处理队列解锁
      this.processQueue.getLockConsume().unlock();
  }

顺序消息的实现是比较复杂的,因为涉及到锁和线程并发控制,源码需要多读几次才能理解。面试时我们要注重讲解核心要点。

  • 事务消息原理

生产者发送事务消息(这是半消息,无法被消费者消费的)之后,开始执行本地事务,根据本地事务执行情况,告诉broker本地事务结果,要么成功,要么失败,如果是成功,那么broker会将事务消息还原到真实的topic和队列,如果是失败,broker会将事务消息(半消息)删除。

这里如果生产者没有告诉broker本地事务的执行结果,broker有一个兜底的定时任务,broker启用一个线程,扫描事务消息topic里的队列里面的消息,判断是否需要检查事务状态(最大检查15次)。

面试的时候回答还是要简洁一些,首先要把主流程讲解出来,其实这个细节原理在RocketMQ的实现内部也是比较复杂的。

高级特性

  • RocketMQ为什么这么快?

这个问题好像似曾相识,因为很多时候面试官喜欢问一些归类总结性的问题,这个问题就是这样,可以判断候选者对技术有没有自己分析总结的能力,这种题目其实没有标准答案,需要了解技术实现的情况下,进行分析总结。

我们还是需要从生产者,消费者,broker来分析

首先是生产者,生产者发送消息支持同步,支持异步,还支持oneway,oneway效率最高,因为他不用等broker返回。

在broker端,消息由索引和消息内容数据两部分组成,消息内容先需要写到commitlog,先写到pagecache,再刷新到磁盘,由于commitlog是顺序写的,而刷盘支持异步刷,这样性能是极高的。

如果是消费者从broker拉取消息, 先查询索引数据consumerQueue,这些索引数据占用空间小,通过页缓存读取,并且本地有缓存机制,读取性能也非常高,读取文件使用到零拷贝mmap技术提高性能,而且消费者和broker保持长轮训机制,使新消息到达可以快速投递到消费端。

最后在消费者这边支持并发多线程消费,将topic和队列信息会进行本地缓存,同时和broker保持长链接,能够保证及时接收到最新的消息。

总结

RocketMQ专题的知识其实很多,底层涉及的一些技术,比如rpc通信,编码解码,零拷贝,刷盘机制,主从复制,负载均衡算法等是大部分中间件通用的一些技术点,如果问这个专题的面试题,有很多题可能被问到。因此我们需要掌握实现机制,才能从容面对面试官的灵魂发问。

如果大家对其他专题的面试题感兴趣,可以关注我的高频面试题专栏,里面已经有5个高频面试专题,后续会陆续更新成体系,成专题的面试题。

相关推荐
llz_1123 小时前
web-第二次课后作业
前端·后端·web
AI人工智能+电脑小能手8 小时前
【大白话说Java面试题 第87题】【Mysql篇】第17题:分布式事务的实现原理?
java·数据库·分布式·mysql·面试
红尘散仙9 小时前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
卷毛的技术笔记10 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
会编程的土豆10 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
Cosolar10 小时前
从零写一个 Attention Is All You Need
人工智能·面试·架构
喵个咪10 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
basketball61611 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
qq_25183645711 小时前
SpringBoot+Vue 共享电池柜管理系统 完整实现 前后端分离项目实战 完整代码
vue.js·spring boot·后端
zhangxingchao11 小时前
AI 大模型核心六:量化、Workflow 与 Agent、多轮 RAG
前端·人工智能·后端