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();
    }
}

两种方式区别:

推模式:

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

拉模式:

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

相关推荐
RainbowSea16 小时前
6. RabbitMQ 死信队列的详细操作编写
java·消息队列·rabbitmq
RainbowSea16 小时前
5. RabbitMQ 消息队列中 Exchanges(交换机) 的详细说明
java·消息队列·rabbitmq
数据智能老司机17 小时前
CockroachDB权威指南——CockroachDB SQL
数据库·分布式·架构
数据智能老司机17 小时前
CockroachDB权威指南——开始使用
数据库·分布式·架构
数据智能老司机18 小时前
CockroachDB权威指南——CockroachDB 架构
数据库·分布式·架构
IT成长日记18 小时前
【Kafka基础】Kafka工作原理解析
分布式·kafka
州周20 小时前
kafka副本同步时HW和LEO
分布式·kafka
ChinaRainbowSea21 小时前
1. 初始 RabbitMQ 消息队列
java·中间件·rabbitmq·java-rabbitmq
爱的叹息1 天前
主流数据库的存储引擎/存储机制的详细对比分析,涵盖关系型数据库、NoSQL数据库和分布式数据库
数据库·分布式·nosql
千层冷面1 天前
RabbitMQ 发送者确认机制详解
分布式·rabbitmq·ruby