RabbitMQ面试题
一、RabbitMQ基础
1. 什么是RabbitMQ,它的基本架构是怎样的?
RabbitMQ 是一个开源的消息代理和队列服务器,用于通过异步消息传递方式在分布式系统或服务之间进行通信。RabbitMQ 实现了高级消息队列协议(AMQP),同时也支持其他消息协议,如 MQTT 和 STOMP。它由 Erlang 语言编写,因此继承了 Erlang 所具有的高并发、高可用和容错特性。
RabbitMQ 的基本架构包含了以下几个主要组件:
- 生产者(Producer): 生产者是发送消息的应用程序。它创建消息,并可以将消息发送到交换器。
- 消费者(Consumer): 消费者是接收消息的应用程序。它从队列中提取消息并进行处理。
- 交换器(Exchange): 交换器负责接收生产者发送的消息,并根据路由规则将消息路由到一个或多个队列。RabbitMQ 支持几种不同类型的交换器:- 直接交换(Direct Exchange)- 扇出交换(Fanout Exchange)- 主题交换(Topic Exchange)- 头交换(Headers Exchange)
- 队列(Queue): 队列是消息最终被消费者接收的地方,它是存放消息的缓冲区。生产者和消费者通常都不直接交互,而是通过队列进行通信。
- 绑定(Binding): 绑定是交换器和队列之间的链接。它告诉交换器消息应该传递到哪些队列。
- 虚拟主机(Virtual Host): 虚拟主机提供了一组独立的环境,每个环境都有自己的交换器、队列和绑定。它们用于逻辑上区分和隔离不同应用程序的消息环境。
- 连接(Connection): 连接是一个 TCP 连接,生产者和消费者通过此连接到 RabbitMQ 服务器。在一个连接内部,可以创建多个通道。
- 通道(Channel): 通道是在连接内部建立的多路传输会话。每个通道代表一个会话任务。
RabbitMQ 服务器(RabbitMQ broker)通常指的是运行RabbitMQ软件的物理服务器或集群。在分布式模式下,RabbitMQ 可以配置为集群模式,以实现负载均衡和高可用性。
RabbitMQ 是一个强大的中间件,它使得应用程序和服务能够通过消息队列以松耦合的形式交换数据,支持多种消息模式,如工作队列、发布订阅、路由和主题消息等。这为跨多个服务和应用程序的可靠消息传递提供了基础设施。
2. RabbitMQ支持哪些协议?
RabbitMQ支持AMQP协议,也支持MQTT、STOMP等其他协议。
3. 说一下AMQP协议?
4. 为什么要使用RabbitMQ?
- 在分布式系统下具备异步,削峰,负载均衡等一系列高级功能;
- 拥有持久化的机制,进程消息,队列中的信息也可以保存下来。
- 实现消费者和生产者之间的解耦。
- 对于高并发场景下,利用消息队列可以使得同步访问变为串行访问达到一定量的限流,利于数据库的操作。
- 可以使用消息队列达到异步下单的效果,排队中,后台进行逻辑下单。
5. MQ的应用场景有哪些?
1. 异步处理
场景说明:用户注册后,需要发注册邮件和注册短信。传统的做法有两种1.串行的方式;2.并行方式。
(1)串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端。
(2)并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间。
假设三个业务节点每个使用50毫秒钟,不考虑网络等其他开销,则串行方式的时间是150毫秒,并行的时间可能是100毫秒。
因为CPU在单位时间内处理的请求数是一定的,假设CPU1秒内吞吐量是100次。则串行方式1秒内CPU可处理的请求量是7次(1000/150)。并行方式处理的请求量是10次(1000/100)。
小结:如以上案例描述,传统的方式系统的性能(并发量,吞吐量,响应时间)会有瓶颈。如何解决这个问题呢?
引入消息队列,将不是必须的业务逻辑,异步处理。改造后的架构如下:
按照以上约定,用户的响应时间相当于是注册信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了两倍。
2. 应用解耦
场景说明:用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用库存系统的接口。
传统模式的缺点:
1) 假如库存系统无法访问,则订单减库存将失败,从而导致订单失败;
2) 订单系统与库存系统耦合;
如何解决以上问题呢?引入应用消息队列后的方案,如下图:
订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功。
库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作。
假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦。
3. 请求削峰
流量削锋也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛。
应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。
可以控制活动的人数;
可以缓解短时间内高流量压垮应用;
用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面;
秒杀业务根据消息队列中的请求信息,再做后续处理。
4. 日志处理
日志处理是指将消息队列用在日志处理中,比如Kafka的应用,解决大量日志传输的问题。架构简化如下:
日志采集客户端,负责日志数据采集,定时写受写入Kafka队列;
Kafka消息队列,负责日志数据的接收,存储和转发;
日志处理应用:订阅并消费kafka队列中的日志数据;
(1)Kafka:接收用户日志的消息队列。
(2)Logstash:做日志解析,统一成JSON输出给Elasticsearch。
(3)Elasticsearch:实时日志分析服务的核心技术,一个schemaless,实时的数据存储服务,通过index组织数据,兼具强大的搜索和统计功能。
(4)Kibana:基于Elasticsearch的数据可视化组件,超强的数据可视化能力是众多公司选择ELK stack的重要原因。
5. 消息通讯
消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。
点对点通讯:
客户端A和客户端B使用同一队列,进行消息通讯。
聊天室通讯:
客户端A,客户端B,客户端N订阅同一主题,进行消息发布和接收。实现类似聊天室效果。
6. 解耦、异步、削峰是什么?
解耦:A 系统发送数据到 BCD 三个系统,通过接口调用发送。如果 E 系统也要这个数据呢?那如果 C 系统现在不需要了呢?A 系统负责人几乎崩溃…A 系统跟其它各种乱七八糟的系统严重耦合, A 系统产生一条比较关键的数据,很多系统都需要 A 系统将这个数据发送过来。如果使用 MQ,A系统产生一条数据,发送到 MQ 里面去,哪个系统需要数据自己去 MQ 里面消费。如果新系统需要数据,直接从 MQ 里消费即可;如果某个系统不需要这条数据了,就取消对 MQ 消息的消费即可。这样下来,A 系统压根儿不需要去考虑要给谁发送数据,不需要维护这个代码,也不需要考虑人家是否调用成功、失败超时等情况。
就是一个系统或者一个模块,调用了多个系统或者模块,互相之间的调用很复杂,维护起来很麻烦。但是其实这个调用是不需要直接同步调用接口的,如果用 MQ 给它异步化解耦。
异步:A 系统接收一个请求,需要在自己本地写库,还需要在 BCD 三个系统写库,自己本地写库要 3ms,BCD 三个系统分别写库要 300ms、450ms、200ms。最终请求总延时是 3 + 300 + 450 + 200 = 953ms,接近 1s,用户感觉搞个什么东西,慢死了慢死了。用户通过浏览器发起请求。如果使用 MQ,那么 A 系统连续发送 3 条消息到 MQ 队列中,假如耗时 5ms,A 系统从接受一个请求到返回响应给用户,总时长是 3 + 5 = 8ms。
削峰:减少高峰时期对服务器压力。
7. 消息队列有什么缺点?
- 系统可用性降低 本来系统运行好好的,现在你非要加入个消息队列进去,那消息队列挂了,你的系统不是呵呵了。因此,系统可用性会降低;
- 系统复杂度提高 加入了消息队列,要多考虑很多方面的问题,比如:一致性问题、如何保证消息不被重复消费、如何保证消息可靠性传输等。因此,需要考虑的东西更多,复杂性增大。
- 一致性问题 A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致了。
所以消息队列实际是一种非常复杂的架构,你引入它有很多好处,但是也得针对它带来的坏处做各种额外的技术方案和架构来规避掉,做好之后,你会发现,妈呀,系统复杂度提升了一个数量级,也许是复杂了 10 倍。但是关键时刻,用还是得用的。
8. Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什么优缺点?
综上,各种对比之后,有如下建议:
- 一般的业务系统要引入 MQ,最早大家都用 ActiveMQ,但是现在确实大家用的不多
版权归原作者 Blocking The Sky 所有, 如有侵权,请联系我们删除。