# RabbitMQ 面试题

# 01. 消息队列的应用场景有哪些?

参考答案

答:消息队列的应用场景如下:

  • 应用解耦,比如,用户下单后,订单系统需要通知库存系统,假如库存系统无法访问,则订单减库存将失败,从而导致订单失败。订单系统与库存系统耦合,这个时候如果使用消息队列,可以返回给用户成功,先把消息持久化,等库存系统恢复后,就可以正常消费减去库存了。

  • 削峰填谷,比如,秒杀活动,一般会因为流量过大,从而导致流量暴增,应用挂掉,这个时候加上消息队列,服务器接收到用户的请求后,首先写入消息队列,假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面。

  • 日志系统,比如,客户端负责将日志采集,然后定时写入消息队列,消息队列再统一将日志数据存储和转发。

# 02. RabbitMQ 有哪些优点?

参考答案

RabbitMQ 的优点如下:

  • 可靠性,RabbitMQ 的持久化支持,保证了消息的稳定性;

  • 高并发,RabbitMQ 使用了 Erlang 开发语言,Erlang 是为电话交换机开发的语言,天生自带高并发光环和高可用特性;

  • 集群部署简单,正是因为 Erlang 使得 RabbitMQ 集群部署变的非常简单;

  • 社区活跃度高,因为 RabbitMQ 应用比较广泛,所以社区的活跃度也很高;

  • 解决问题成本低,因为资料比较多,所以解决问题的成本也很低;

  • 支持多种语言,主流的编程语言都支持,如 Java、.NET、PHP、Python、JavaScript、Ruby、Go 等;

  • 插件多方便使用,如网页控制台消息管理插件、消息延迟插件等。

# 03. RabbitMQ 有哪些重要的角色?

参考答案

RabbitMQ 包含以下三个重要的角色:

  • 生产者:消息的创建者,负责创建和推送数据到消息服务器;

  • 消费者:消息的接收方,用于处理数据和确认消息;

  • 代理:就是 RabbitMQ 本身,用于扮演“快递”的角色,本身不生产消息,只是扮演“快递”的角色。

# 04. RabbitMQ 有哪些重要的组件?它们有什么作用?

参考答案

RabbitMQ 包含的重要组件有:ConnectionFactory(连接管理器)、Channel(信道)、Exchange(交换器)、Queue(队列)、RoutingKey(路由键)、BindingKey(绑定键) 等重要的组件,它们的作用如下:

  • ConnectionFactory(连接管理器):应用程序与 RabbitMQ 之间建立连接的管理器,程序代码中使用;

  • Channel(信道):消息推送使用的通道;

  • Exchange(交换器):用于接受、分配消息;

  • Queue(队列):用于存储生产者的消息;

  • RoutingKey(路由键):用于把生成者的数据分配到交换器上;

  • BindingKey(绑定键):用于把交换器的消息绑定到队列上。

# 05. 什么是消息持久化?

参考答案

消息持久化是把消息保存到物理介质上,以防止消息的丢失。

# 06. RabbitMQ 要实现消息持久化,需要满足哪些条件?

参考答案

RabbitMQ 要实现消息持久化,必须满足以下 4 个条件:

  • 投递消息的时候 durable 设置为 true ,消息持久化,代码:channel.queueDeclare(x, true, false, false, null),参数2 设置为 true 持久化;

  • 设置投递模式 deliveryMode 设置为 2(持久),代码:channel.basicPublish(x, x, MessageProperties.PERSISTENT TEXT PLAIN,x),参数3 设置为存储纯文本到磁盘;

  • 消息已经到达持久化交换器上;

  • 消息已经到达持久化的队列。

# 07. 消息持久化有哪些缺点?如何缓解?

参考答案

消息持久化的缺点是很消耗性能,因为要写入硬盘要比写入内存性能较低很多,从而降低了服务器的吞吐量。可使用固态硬盘来提高读写速度,以达到缓解消息持久化的缺点。

# 08. RabbitMQ 交换器类型有哪些?

参考答案

RabbitMQ 消费类型也就是交换器(Exchange)类型有以下四种:

 direct:轮询方式
headers:轮询方式,允许使用 header 而非路由键匹配消息,性能差,几乎不用
 fanout:广播方式,发送给所有订阅者
  topic:匹配模式,允许使用正则表达式匹配消息

RabbitMQ 默认的是 direct 方式。

# 09. RabbitMQ 如何确保每个消息能被消费?

参考答案

RabbitMQ 使用 ack 消息确认的方式保证每个消息都能被消费,开发者可根据自己的实际业务,选择 channel.basicAck() 方法手动确认消息被消费。

# 10. RabbitMQ 接收到消息之后必须消费吗?

参考答案

RabbitMQ 接收到消息之后可以不消费,在消息确认消费之前,可以做以下两件事:

  • 拒绝消息消费,使用 channel.basicReject(消息编号, true) 方法,消息会被分配给其他订阅者;
  • 设置为死信队列,死信队列是用于专门存放被拒绝的消息队列。

# 11. topic 模式下发布了一个路由键为“com.mq.rabbit.error”的消息,请问以下不能接收到消息的是?

A:cn.mq.rabbit.*
B:#.error
C:cn.mq.*
D:cn.mq.#

参考答案

C

* 用于匹配一个分段(用 . 分割)的内容,# 用于匹配 0 和多个字符。

# 12. 以下可以获取历史消息的是?

A. topic 交换器
B. fanout 交换器
C. direct 交换器
D. 以上都不是

参考答案

C

fanout 和 topic 都是广播形式的,因此无法获取历史消息,而 direct 可以。