0


RabbitMQ初级的部分面试题

1.RabbitMQ是什么?有什么作用?

    RabbitMQ是一个消息代理:它接受和转发消息。能够实现异步消息处理,达到业务解耦,错峰流控的功能。它的实现是基于消息队列(Queue)。

2.什么是消息队列,有什么作用?

    消息队列(Message Queue MQ)是实现应用之间数据通信的一种机制,采用先进先出的数据结构和生产者消费者设计模式实现通信。

消息队列的优势:解耦,异步,消峰。

2.1 解耦:

    实现生产者和消费者的解耦,生产者和消费者不直接调用,也不用关心对方如何处理,代码的维护性提高

    例如:使用openfeign实现服务调用,如果被调用服务的接口发生修改,服务调用方也需要进行修改,服务之间的耦合性较高,不利于开发和维护

2.2 异步:

同步调用,服务A调用服务B,必须等待服务B执行完业务,服务A才能执行其它业务

异步调用,服务A发送消息给消息队列,马上返回完成其它业务,不用等待服务B执行完

2.3削峰:

可以通过控制消息队列的长度来限制请求流量,从而达到限流保护服务器的作用

消息队列的缺点:

  1. 提高系统的复杂性
  2. 降低系统的可用性

3.消息队列的基本概念

  • 生产者向消息队列发送消息的服务
  • 消费者从消息队列取消息的服务
  • 队列 queue存放消息的容器,采用FIFO数据结构
  • 交换机 exchange实现消息路由,将消息分发到对应的队列中
  • 消息服务器 Broker进行消息通信的软件平台服务器
  • 虚拟主机 virtual host类似于namespace,将不同用户的交换机和队列区分开来
  • 连接 connection网络连接
  • 通道 channel数据通信的通道

4.RabbitMQ常见的五种消息模型

  1. 简单的一对一模型
  2. 工作队列模型 ,一个生产者将消息轮询分发给多个消费者
  3. 发布/订阅模型 ,生产者发布消息,多个消费者同时收取
  4. 路由模型 ,生产者通过关键字发送消息给特定消费者
  5. 主题模型 ,路由模式基础上,在关键字里加入了通配符

4.1 一对一模型:

最基本的队列模型: 一个生产者发送消息到一个队列,一个消费者从队列中取消息。

4.2 工作队列模型

工作队列,生产者将消息分发给多个消费者,如果生产者生产了100条消息,消费者1消费50条,消费者2消费50条。

4.3 发布/订阅模型

发布/订阅模式和Work模式的区别是:Work模式只存在一个队列,多个消费者共同消费一个队列中的消息;而发布订阅模式存在多个队列,不同的消费者可以从各自的队列中处理完全相同的消息。

4.4 路由模型

路由模式的消息队列可以给队列绑定不同的key,生产者发送消息时,给消息设置不同的key,这样交换机在分发消息时,可以让消息路由到key匹配的队列中。 可以想象上图是一个日志处理系统,C1可以处理error日志消息,C2可以处理info\error\warining类型的日志消息,使用路由模式就很容易实现了。

4.5 主题模型

主题模式和路由模式差不多,在key中可以加入通配符:

    • 匹配任意一个单词 com.* ----> com.hopu com.blb com.baidu
  • 匹配.号隔开的0个或多个单词 com.# ---> com.hopu.net com.hopu com.163.xxx.xxx.xxx

5.SpringBoot整合RabbitMQ

1)创建两个SpringBoot项目,一个作为生产者,一个作为消费者

生产者会发送两种消息:保存课程(更新和添加),删除课程

消费者监听两个队列:保存课程队列和删除课程队列

2)给生产者和消费者服务添加依赖

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-amqp</artifactId>
 </dependency>

3) 给生产者和消费者服务添加配置

spring:
    rabbitmq:
      host: localhost
      port: 5672
      username: admin
      password: 123456
      virtual-host: myhost

4)生产者的配置,用于生成消息队列和交换机

/**
 * RabbitMQ的配置
 */
@Configuration
public class RabbitMQConfig {
​
    public static final String QUEUE_COURSE_SAVE = "queue.course.save";
    public static final String QUEUE_COURSE_REMOVE = "queue.course.remove";
    public static final String KEY_COURSE_SAVE = "key.course.save";
    public static final String KEY_COURSE_REMOVE = "key.course.remove";
    public static final String COURSE_EXCHANGE = "edu.course.exchange";
​
    @Bean
    public Queue queueCourseSave() {
        return new Queue(QUEUE_COURSE_SAVE);
    }
​
    @Bean
    public Queue queueCourseRemove() {
        return new Queue(QUEUE_COURSE_REMOVE);
    }
​
    @Bean
    public TopicExchange topicExchange() {
        return new TopicExchange(COURSE_EXCHANGE);
    }
​
    @Bean
    public Binding bindCourseSave() {
        return BindingBuilder.bind(queueCourseSave()).to(topicExchange()).with(KEY_COURSE_SAVE);
    }
​
    @Bean
    public Binding bindCourseRemove() {
        return BindingBuilder.bind(queueCourseRemove()).to(topicExchange()).with(KEY_COURSE_REMOVE);
    }
}

5) 生产者RabbitTemplate发送消息的核心代码

@Autowired
RabbitTemplate rabbitTemplate;
​
//发消息的代码
rabbitTemplate.convertAndSend(交换机的名称,消息的key,消息内容);

6)消费者添加监听器 RabbitListener监听器注解

@Slf4j
@Component
public class CourseMQListener {
​
    public static final String QUEUE_COURSE_SAVE = "queue.course.save";
    public static final String QUEUE_COURSE_REMOVE = "queue.course.remove";
    public static final String KEY_COURSE_SAVE = "key.course.save";
    public static final String KEY_COURSE_REMOVE = "key.course.remove";
    public static final String COURSE_EXCHANGE = "course.exchange";
​
    /**
     * 监听课程添加操作
     */
    @RabbitListener(bindings = {
            @QueueBinding(value = @Queue(value = QUEUE_COURSE_SAVE, durable = "true"),
                    exchange = @Exchange(value = COURSE_EXCHANGE,
                            type = ExchangeTypes.TOPIC,
                            ignoreDeclarationExceptions = "true")
                    , key = KEY_COURSE_SAVE)})
    public void receiveCourseSaveMessage(String message) {
        try {
            log.info("课程添加:{}",message);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
​
    /**
     * 监听课程删除操作
     */
    @RabbitListener(bindings = {
            @QueueBinding(value = @Queue(value = QUEUE_COURSE_REMOVE, durable = "true"),
                    exchange = @Exchange(value = COURSE_EXCHANGE,
                            type = ExchangeTypes.TOPIC,
                            ignoreDeclarationExceptions = "true")
                    , key = KEY_COURSE_REMOVE)})
    public void receiveCourseDeleteMessage(Long id) {
        try {
            log.info("课程删除完成:{}",id);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

6 小结

一、消息队列是分布式系统的重要组件,起到的作用有:

  1. 解耦,生产者和消费者不需要知道对方的具体接口
  2. 异步,生产者发送完消息直接结束,不需要等待消费者执行完,效率高
  3. 削峰,控制高峰期消息的数量,降低服务器压力

二、RabbitMQ的消息模型有:

  1. 一对一,一个生产者一个队列一个消费者,一个发一个收
  2. 一对多,一个生产者一个队列多个消费者,多个消费者共享一个队列中的消息
  3. 发布订阅模式由交换机绑定多个队列,消息分发到多个队列,每个消费者消费自己的队列中的消息
  4. 路由模式在发布订阅模式的基础上,加入路由键,消息通过键路由到不同的队列
  5. 主题模式在路由模式基础上,键中加入通配符,实现更加灵活的匹配
标签: rabbitmq 分布式

本文转载自: https://blog.csdn.net/m0_64592129/article/details/135568894
版权归原作者 In末摘花 所有, 如有侵权,请联系我们删除。

“RabbitMQ初级的部分面试题”的评论:

还没有评论