消息队列面试题

主要围绕如下几点进行阐述:
为什么使用消息队列?
使用消息队列有什么缺点?
消息队列如何选型?
如何保证消息队列是高可用的?
如何保证消息不被重复消费?
如何保证消费的可靠性传输?
如何保证消息的顺序性?

1.为什么要使用消息队列?

解耦、异步、削峰

2.使用了消息队列会有什么缺点?

我们引入一个技术,要对这个技术的弊端有充分的认识,才能做好预防。

  • 系统可用性降低:如果消息中间件挂了,系统也就挂了。因此,系统可用性会降低。
  • 系统复杂性增加:加入了消息队列,要多考虑很多方面的问题,比如:一致性问题、如何保证消息不被重复消费、如何保证消息可靠性传输等。因此,需要考虑的东西更多,复杂性增大。

3.消息队列如何选型?

特性ActiveMQRabbitMQRocketMQkafka
开发语言javaerlangjavascala
单机吞吐量万级万级10万级10万级
时效性毫秒级微秒级毫秒级毫秒级以内
可用性高(主从架构)高(主从架构)非常高(分布式架构)非常高(分布式架构)
功能特性成熟的产品,在很多公司得到应用;有较多的文档;各种协议支持较好基于erlang开发,所以并发能力很强,性能极其好,延时很低;管理界面较丰富MQ功能比较完备,扩展性佳只支持主要的MQ功能,像一些消息查询,消息回溯等功能没有提供,毕竟是为大数据准备的,在大数据领域应用广。

还需考虑社区活跃程度,使用场景等。

4.如何保证消息队列是高可用的?

4.1 RocketMQ

架构部署方式:
(1)多master模式;
(2)多master多slave异步复制模式;
(3)多master多slave同步双写模式。

4.1.1 多master多slave模式部署架构图

在这里插入图片描述

4.1.2 通信过程如下

(1)生产者:
Producer 与 NameServer集群中的其中一个节点(随机选择)建立长连接,定期从 NameServer 获取 Topic 路由信息,并向提供 Topic 服务的 Broker Master 建立长连接,且定时向 Broker 发送心跳。Producer 只能将消息发送到 Broker master。

(2)消费者:
它同时和提供 Topic 服务的 Master 和 Slave建立长连接,既可以从 Broker Master 订阅消息,也可以从 Broker Slave 订阅消息。

4.2 kafka

kafka的拓扑架构图
在这里插入图片描述

如上图所示,一个典型的Kafka集群中包含以下四大要素
(1)Producer(可以是web前端产生的Page View,或者是服务器日志,系统CPU、Memory等);
(2)若干broker(Kafka支持水平扩展,一般broker数量越多,集群吞吐率越高);
(3)若干Consumer Group;
(4)一个Zookeeper集群。

Kafka通过Zookeeper管理集群配置,选举leader,以及在Consumer Group发生变化时进行rebalance。Producer使用push模式将消息发布到broker,Consumer使用pull模式从broker订阅并消费消息。

5.如何保证消息不被重复消费?

5.1 消息中间件如何知道消息被正确消费?

正常情况下,消费者在消费消息的时候,消费完毕后,会发送一个确认消息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除。
只是不同的消息队列发出的确认消息形式不同。
(1)例如RabbitMQ是发送一个ACK确认消息;
(2)RocketMQ是返回一个CONSUME_SUCCESS成功标志;
(3)kafka实际上有个offet的概念,简单说一下,就是每一个消息都有一个offset,kafka消费过消息后,需要提交offset,让消息队列知道自己已经消费过了。

5.2 那造成重复消费的原因?

就是因为网络传输故障或业务系统故障等等,确认信息没有传送到消息队列,导致消息队列不知道自己已经消费过该消息了,再次将消息分发给其他的消费者。

5.3 如何解决?

这个问题针对业务场景来答,分以下三种情况:
(1)通过数据库设置主键或唯一索引,如果出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。
(2)如果拿到消息后仅做redis的set的操作,并且数据多次set并不会对数据产生影响,那此时就不需要解决了。
(3)使用第三方介质来存储消费记录。以redis为例,给消息分配一个全局id,只要消费过该消息,将id写入redis,那消费者开始消费前,先去redis中查询有没有该记录即可。

6.如何保证消费的可靠性传输?

有三个角度可能会产生丢数据

  • 生产者弄丢数据
  • 消息队列弄丢数据
  • 消费者弄丢数据
6.1 生产者丢数据

从生产者弄丢数据这个角度来看,RabbitMQ提供transaction和confirm模式来确保生产者不丢消息。
(1)transaction机制就是说,发送消息前,开启事务(channel.txSelect()),然后发送消息,如果发送过程中出现什么异常,事务就会回滚(channel.txRollback()),如果发送成功则提交事务(channel.txCommit())。
这种方式有个缺点:吞吐量下降。
(2)confirm模式,所有在该信道上发布的消息都将会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后,rabbitMQ就会发送一个ACK给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了。如果rabbitMQ没能处理该消息,则会发送一个Nack消息给你,你可以进行重试操作。

6.2 消息队列丢数据

一般是开启持久化磁盘的配置。

6.3 消费者丢数据

消费者丢数据一般是因为采用了自动确认消息模式。
解决方案:采用手动确认消息即可。

7.如何保证消息的顺序性

7.1 相对顺序

将需要保持先后顺序的消息hash到同一个消息队列中(RocketMQ中是queue,kafka中就是partition,rabbitMq中就是queue)。在消费端选择一个或者多个消费者。

7.2 绝对顺序

单个producer,单个queue,单个consumer.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值