RabbitMQ常⻅⾯试题

1. MQ的作⽤及应⽤场景

类似问题:

项⽬什么场景下使⽤到了MQ,

为什么需要MQ RabbitMQ 的作⽤?

使⽤场景有哪些

RabbitMQ的主要应⽤场景

消息队列解耦应⽤程序的例⼦

消息队列的应⽤场景

为什么说消息队列可以削峰

  • 异步解耦: 在业务流程中, ⼀些操作可能⾮常耗时, 但并不需要即时返回结果. 可以借助MQ把这些操作异步化.(⽐如⽤⼾注册后发送注册短信或邮件通知, 可以作为异步任务处理, ⽽不必等待这些操作 完成后才告知⽤⼾注册成功)
  • 流量削峰: 在访问量剧增的情况下, 应⽤仍然需要继续发挥作⽤, 但是是这样的突发流量并不常⻅. 如果以能处理这类峰值为标准⽽投⼊资源,⽆疑是巨⼤的浪费. 使⽤MQ能够使关键组件⽀撑突发访问压⼒, 不会因为突发流量⽽崩溃. (⽐如秒杀或者促销活动, 可以使⽤MQ来控制流量, 将请求排队, 然后系统根据⾃⼰的处理能⼒逐步处理这些请求)
  • 异步通信: 在很多时候应⽤不需要⽴即处理消息, MQ提供了异步处理机制, 允许应⽤把⼀些消息放⼊ MQ中, 但并不⽴即处理它,在需要的时候再慢慢处理.
  • 消息分发: 当多个系统需要对同⼀数据做出响应时, 可以使⽤MQ进⾏消息分发. ⽐如⽀付成功后, ⽀付系统可以向MQ发送消息, 其他系统订阅该消息, ⽽⽆需轮询数据库.
  • 延迟通知: 在需要在特定时间后发送通知的场景中, 可以使⽤MQ的延迟消息功能, ⽐如在电⼦商务平台中,如果⽤⼾下单后⼀定时间内未⽀付,可以使⽤延迟队列在超时后⾃动取消订单

2. 了解过哪些MQ,以及区别

类似问题:

了解过哪些MQ, 与其他同类产品的对⽐

kafka 和 RabbitMQ的对⽐

对⽐其他消息队列,不同mq分别⽤在什么场景

kafka和rocketmq⽐较

消息队列除了使⽤RabbitMQ,可以⽤RocketMQ吗?

⽬前业界有很多的MQ产品, 例如RabbitMQ, RocketMQ, ActiveMQ, Kafka, ZeroMQ等, 简单介绍其中3种:

1. Kafaka

Kafka⼀开始的⽬的就是⽤于**⽇志收集和传输** ,追求⾼吞吐量, 性能卓越, 单机吞吐达到⼗万级, 在⽇志领域⽐较成熟, 功能较为简单, 主要⽀持简单的 MQ 功能 . 适合**⼤数据处理**, ⽇志聚合, 实时分析等场景

2. RabbitMQ

采⽤Erlang语⾔开发, MQ 功能⽐较完备, 且**⼏乎⽀持所有主流语⾔**, 开源提供的界⾯也⾮常友好, 性能较好, 吞吐量能达到万级, 社区活跃度较⾼,⽂档更新频繁, ⽐较适合中⼩型公司, 数据量没那么⼤, 且并发没那么⾼的场景.

3. RocketMQ

采⽤Java语⾔开发, 由阿⾥巴巴开源, 后捐赠给了Apache. 在可⽤性, 可靠性以及稳定性等⽅⾯都⾮常出⾊, 吞吐量能达到⼗万级, 在Alibaba集团内部⼴泛使⽤, 但⽀持的客⼾端语⾔不多, 产品较新⽂档较少, 且社区活跃度⼀般. 适合于⼤规模分布式系统, 可靠性要求⾼, 且并发⼤的场景, ⽐如互联⽹⾦融.

3. 介绍下RabbitMQ的核⼼概念及⼯作流程

相关⾯试题:

RabbitMQ的核⼼流程简单介绍⼀下

讲下RabbitMQ的结构

RabbitMQ是⼀个消息中间件, 也是⼀个⽣产者消费者模型. 它负责接收, 存储并转发消息. 根据⼯作流程 图, 来介绍它的核⼼概念:

  • Producer: ⽣产者, 向RabbitMQ发送消息
  • Consumer: 消费者, 从RabbitMQ接收消息
  • Broker: 消息队列服务器或服务实例, 也就是rabbitMQ Server,接收并转发消息
  • Connection: ⽹络连接, 它允许客⼾端与 RabbitMQ通信
  • Channel: 连接⾥的⼀个虚拟通道, 发送或者接收消息都是通过通道进⾏的.
  • Exchange: 交换机. 负责接收⽣产者发送的消息, 并根据路由算法和规则将消息路由到⼀个或多个队 列
  • Queue: 消息队列, 存储消息直到它们被消费者消费

工作流程:

  1. 创建连接: Producer连接到RabbitMQBroker, 建⽴⼀个连接(Connection), 开启⼀个信道(Channel)
  2. 声明交换机和队列,以及绑定规则: Producer 声明⼀个交换机(Exchange)和队列, 并绑定Queue到 Exchange
  3. 发布消息: Producer 发送消息⾄RabbitMQ Broker
  4. 消息存储: RabbitMQ Broker 接收消息, 并存⼊相应的队列(Queue)中, 如果未找到相应的队列, 则根 据⽣产者的配置, 选择丢弃或者退回给⽣产者.
  5. 消费消息: 消费者监听Queue, 当消息到达时, 从Queue中获取消息, 处理后, 向RabbitMQ发送消息确 认
  6. 消息删除: 消息被确认后, RabbitMQ 会把消息从Queue中删除.

4. RabbitMQ如何保证消息的可靠性

相关⾯试题:

RabbitMQ消息丢失原因及其解决⽅案

如何保证消息不丢失

消息写⼊失败怎么办

消息消费失败如何处理

MQ的主动ack和被动ack有什么区别

RabbitMQ如何解决数据丢失问题, 如何保证⼀致性

消息队列怎么保证消费者的消息不丢失的?

从以下⼏个⽅⾯来回答

  1. 发送⽅投递可靠性

  2. RabbitMQ可靠性

  3. 消费者可靠性

详见高级特性3.3

5. RabbitMQ如何保证消息的顺序性

相关⾯试题:

RabbitMQ怎么保证消息的顺序性?

如何保证消息能够有序消费?

  • 单队列单消费者
  • 分区消费
  • 事务和消息确认机制
  • 业务逻辑控制, ⽐如消费端内部实现消息排序逻辑

详看应用问题2.顺序性保障

6. 如何保证消息消费时的幂等性

相关问题:

RabbitMQ怎么保证消息不重复消费

消息或请求存在重复消费问题吗? 是怎么解决的?

怎么解决MQ重复消费的问题

详看应用问题1. 幂等性保障

7. RabbitMQ有哪些特性

  • 发送⽅消息确认
  • 持久化
  • 消费端消息确认
  • 重试机制
  • TTL
  • 死信队列

详看高级特性

8. 介绍下RabbitMQ的死信队列

类似问题:

RabbitMQ的死信队列以及应⽤场景

从以下⽅⾯来回答:

  • 死信队列的概念
  • 死信的来源
  • 死信队列的应⽤场景

详看高级特性-死信队列

9. 介绍下RabbitMQ的延迟队列

类似问题:

rabbitmq延迟队列的实

从以下三个⽅⾯来回答

  • 概念
  • 应⽤场景
  • 实现⽅式

详看高级特性-死信队列

10. 介绍下RabbitMQ的⼯作模式

相关⾯试题:

RabbitMQ的⼏种模式, work模式怎么实现的能者多劳

  1. Simple(简单模式)

  2. Work Queue(⼯作队列)

  3. Publish/Subscribe (发布/订阅)

  4. Routing(路由模式)

  5. Topics(通配符模式)

  6. RPC(RPC通信)

  7. Publisher Confirms(发布确认)

11. 消息积压的原因, 如何处理

类似问题:

MQ消息堆积问题

如果解决MQ的数据囤积?

消息积压的原因:

  • 消息⽣产过快
  • 消费者能⼒不⾜
  • ⽹络问题
  • RabbitMQ服务配置偏低

.....

解决⽅案:

  • 提⾼消费者效率, ⽐如增加机器, 优化业务逻辑
  • 限制消费者⽣产速率
  • 资源配置优化

详看应用问题-消息积压

12. RabbitMQ是推模式还是拉模式

概念

RabbitMQ⽀持两种消息传递模式: 推模式(push)和拉模式(pull)

推模式:消息中间件主动将消息推送给消费者.

拉模式:消费者主动从消息中间件拉取消息.

RabbitMQ主要是基于推模式⼯作的, 它的核⼼设计是让消息队列中的消费者接收到由⽣产者发送的消息. 使⽤channel.basicConsume⽅法订阅队列, RabbitMQ就会把消息推送到订阅该队列的消费者, 如果只想从队列中获取单条消息而不是持续订阅,则可以使⽤channel.basicGet⽅法来进⾏消费消息.

借助SpringBoot:


使用SDK来完成:

java 复制代码
public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //1. 建立连接
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost(Constants.HOST);
        connectionFactory.setPort(Constants.PORT); //需要提前开放端口号
        connectionFactory.setUsername(Constants.USER_NAME);//账号
        connectionFactory.setPassword(Constants.PASSWORD);  //密码
        connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST); //虚拟主机
        Connection connection = connectionFactory.newConnection();
        //2. 开启信道
        Channel channel = connection.createChannel();
        //3. 声明队列   使用内置的交换机
        //如果队列不存在, 则创建, 如果队列存在, 则不创建
        channel.queueDeclare(Constants.MESSAGE_QUEUE,true,false,false,null);
        //4. 发送消息
        for (int i = 0; i < 10; i++) {
            String msg = "hello message queue...."+i;
            channel.basicPublish("",Constants.MESSAGE_QUEUE, null, msg.getBytes());
        }

        System.out.println("消息发送成功~");
        //5. 资源释放
        channel.close();
        connection.close();
    }
}
java 复制代码
/**
 * 拉模式
 */
public class PullController {
    public static void main(String[] args) throws IOException, TimeoutException {
        //1. 建立连接
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost(Constants.HOST);
        connectionFactory.setPort(Constants.PORT); //需要提前开放端口号
        connectionFactory.setUsername(Constants.USER_NAME);//账号
        connectionFactory.setPassword(Constants.PASSWORD);  //密码
        connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST); //虚拟主机
        Connection connection = connectionFactory.newConnection();
        //2. 开启信道
        Channel channel = connection.createChannel();
        //3. 声明队列   使用内置的交换机
        //如果队列不存在, 则创建, 如果队列存在, 则不创建
        channel.queueDeclare(Constants.MESSAGE_QUEUE, true, false, false, null);
        //4.拉模式获取
        GetResponse getResponse = channel.basicGet(Constants.MESSAGE_QUEUE, true);
        System.out.println("拉模式获取消息:"+new String(getResponse.getBody(),"UTF-8"));
        //5. 资源释放
//        channel.close();
//        connection.close();

    }
}
java 复制代码
/**
 * 推模式
 */
public class PushController {
    public static void main(String[] args) throws IOException, TimeoutException, IOException, TimeoutException {
        //1. 建立连接
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost(Constants.HOST);
        connectionFactory.setPort(Constants.PORT); //需要提前开放端口号
        connectionFactory.setUsername(Constants.USER_NAME);//账号
        connectionFactory.setPassword(Constants.PASSWORD);  //密码
        connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST); //虚拟主机
        Connection connection = connectionFactory.newConnection();
        //2. 开启信道
        Channel channel = connection.createChannel();
        //3. 声明队列   使用内置的交换机
        //如果队列不存在, 则创建, 如果队列存在, 则不创建
        channel.queueDeclare(Constants.MESSAGE_QUEUE, true, false, false, null);
        //4. 消费消息
        DefaultConsumer consumer = new DefaultConsumer(channel){
            //从队列中收到消息, 就会执行的方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                //TODO
                System.out.println("接收到消息:"+ new String(body));
            }
        };
        channel.basicConsume(Constants.MESSAGE_QUEUE, true, consumer);

//        //5. 资源释放
//        channel.close();
//        connection.close();
    }
}

两种方式区别:

推模式:

对消息的获取更加实时, 适合对数据实时性要求⽐较⾼时, ⽐如实时数据处理, 如监控系统, 报表系统等.

拉模式:

消费端可以按照⾃⼰的处理速度来消费, 避免消息积压, 适合需要流量控制, 或者需要⼤量计算资源的任 务, 拉取模式允许消费者在准备好后再请求消息, 避免资源浪费

相关推荐
活老鬼2 分钟前
Ceph分布式存储
linux·运维·服务器·分布式·ceph
明天不吃。2 小时前
【RabbitMQ】如何在 Ubuntu 安装 RabbitMQ
ubuntu·rabbitmq
XQ_8988788882 小时前
【02】RabbitMQ客户端应用开发实战
rabbitmq
Francek Chen13 小时前
【大数据技术基础 | 实验十】Hive实验:部署Hive
大数据·数据仓库·hive·hadoop·分布式
拔剑纵狂歌13 小时前
ZooKeeper单机、集群模式搭建教程
分布式·后端·学习·zookeeper·中间件·架构·服务发现
すあ14 小时前
Spark:大数据处理的强大引擎
大数据·分布式·spark
PersistJiao16 小时前
Spark RDD中的迭代器
大数据·分布式·spark·迭代器
EdwardYange16 小时前
Springboot RabbitMq 集成分布式事务问题
spring boot·分布式·rabbitmq·java-rabbitmq·分布式事务问题
小笨猪-18 小时前
RabbitMQ运维
java·运维·redis·分布式·rabbitmq·java-rabbitmq