当面试官要你介绍一下MQ时,该怎么回答?

当面试官要你介绍一下MQ时,该怎么回答?

 

1、为何要使用MQ消息中间件?

一个用消息队列的人,不知道为啥用,有点尴尬。没有复习这点,很容易被问蒙,而后就开始胡扯了。前端

回答:这个问题,咱只答三个最主要的应用场景,不能否认还有其余的,可是只答三个主要的,即如下六个字:程序员

解耦、异步、削峰web

一、解耦面试

传统模式:redis

 

当面试官要你介绍一下MQ时,该怎么回答?

 

 

传统模式的缺点:算法

系统间耦合性太强,如上图所示,系统A在代码中直接调用系统B和系统C的代码,若是未来D系统接入,系统A还须要修改代码,过于麻烦!数据库

中间件模式:服务器

 

当面试官要你介绍一下MQ时,该怎么回答?

 

 

中间件模式的的优势:网络

将消息写入消息队列,须要消息的系统本身从消息队列中订阅,从而系统A不须要作任何修改。架构

二、异步

传统模式:

 

当面试官要你介绍一下MQ时,该怎么回答?

 

 

传统模式的缺点:

一些非必要的业务逻辑以同步的方式运行,太耗费时间。

中间件模式:

 

当面试官要你介绍一下MQ时,该怎么回答?

 

 

中间件模式的的优势:

将消息写入消息队列,非必要的业务逻辑以异步的方式运行,加快响应速度

三、削峰

传统模式

 

当面试官要你介绍一下MQ时,该怎么回答?

 

 

传统模式的缺点:

并发量大的时候,全部的请求直接怼到数据库,形成数据库链接异常

中间件模式:

 

当面试官要你介绍一下MQ时,该怎么回答?

 

 

中间件模式的的优势:

系统A慢慢的按照数据库能处理的并发量,从消息队列中慢慢拉取消息。在生产中,这个短暂的高峰期积压是容许的。

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

分析:一个使用了MQ的项目,若是连这个问题都没有考虑过,就把MQ引进去了,那就给本身的项目带来了风险。

咱们引入一个技术,要对这个技术的弊端有充分的认识,才能作好预防。要记住,不要给公司挖坑!

回答:回答也很容易,从如下两个个角度来答

系统可用性下降:

你想啊,原本其余系统只要运行好好的,那你的系统就是正常的。

如今你非要加个消息队列进去,那消息队列挂了,你的系统不是呵呵了。所以,系统可用性下降

系统复杂性增长:

要多考虑不少方面的问题,好比一致性问题、如何保证消息不被重复消费,如何保证保证消息可靠传输。

所以,须要考虑的东西更多,系统复杂性增大。

可是,咱们该用仍是要用的。

3、消息队列如何选型?

先说一下,我只会ActiveMQ,RabbitMQ,RocketMQ,Kafka,对什么ZeroMQ等其余MQ没啥理解,所以只能基于这四种MQ给出回答。

分析:既然在项目中用了MQ,确定事先要对业界流行的MQ进行调研,若是连每种MQ的优缺点都没了解清楚,就拍脑壳依据喜爱,用了某种MQ,仍是给项目挖坑。

若是面试官问:"你为何用这种MQ?。"

你直接回答"领导决定的。"

这种回答就很LOW了。

仍是那句话,不要给公司挖坑。

咱们能够看出,RabbitMQ版本发布比ActiveMq频繁不少。至于RocketMQ和kafka就不带你们看了,总之也比ActiveMQ活跃的多。详情,可自行查阅。

再来一个性能对比表

当面试官要你介绍一下MQ时,该怎么回答?

 

综合上面的材料得出如下两点:

一、中小型软件公司,建议选RabbitMQ.

一方面,erlang语言天生具有高并发的特性,并且他的管理界面用起来十分方便。

正所谓,成也萧何,败也萧何!他的弊端也在这里,虽然RabbitMQ是开源的,然而国内有几个能定制化开发erlang的程序员呢?

所幸,RabbitMQ的社区十分活跃,能够解决开发过程当中遇到的bug,这点对于中小型公司来讲十分重要。

不考虑rocketmq和kafka的缘由是,一方面中小型软件公司不如互联网公司,数据量没那么大,选消息中间件,应首选功能比较完备的,因此kafka排除。

不考虑rocketmq的缘由是,rocketmq是阿里出品,若是阿里放弃维护rocketmq,中小型公司通常抽不出人来进行rocketmq的定制化开发,所以不推荐。

二、大型软件公司,根据具体使用在rocketMq和kafka之间二选一

一方面,大型软件公司,具有足够的资金搭建分布式环境,也具有足够大的数据量。

针对rocketMQ,大型软件公司也能够抽出人手对rocketMQ进行定制化开发,毕竟国内有能力改JAVA源码的人,仍是至关多的。

至于kafka,根据业务场景选择,若是有日志采集功能,确定是首选kafka了。具体该选哪一个,看使用场景。

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

在第二点说过了,引入消息队列后,系统的可用性降低。

在生产中,没人使用单机模式的消息队列。

所以,做为一个合格的程序员,应该对消息队列的高可用有很深入的了解。

若是面试官问:"大家的消息中间件如何保证高可用的?"

若是你的回答只是代表本身只会订阅和发布消息,面试官就会怀疑你是否是只是本身搭着玩,压根没在生产用过。

所以,请作一个爱思考,会思考,懂思考的程序员。

回答:这问题,其实要对消息队列的集群模式要有深入了解,才好回答。

以rcoketMQ为例,他的集群就有多master 模式、多master多slave异步复制模式、多 master多slave同步双写模式。

多master多slave模式部署架构图(网上找的,偷个懒,懒得画):

 

当面试官要你介绍一下MQ时,该怎么回答?

 

 

其实博主第一眼看到这个图,就以为和kafka好像,只是NameServer集群,在kafka中是用zookeeper代替,都是用来保存和发现master和slave用的。

通讯过程以下:

Producer 与 NameServer集群中的其中一个节点(随机选择)创建长链接,按期从 NameServer 获取 Topic 路由信息,并向提供 Topic 服务的 Broker Master 创建长链接,且定时向 Broker 发送心跳。

Producer 只能将消息发送到 Broker master,可是 Consumer 则不同,它同时和提供 Topic 服务的 Master 和 Slave创建长链接,既能够从 Broker Master 订阅消息,也能够从 Broker Slave 订阅消息。

那么kafka呢,为了对比说明直接上kafka的拓补架构图(也是找的,懒得画)

当面试官要你介绍一下MQ时,该怎么回答?

 

 

如上图所示,一个典型的Kafka集群中包含若干Producer(能够是web前端产生的Page View,或者是服务器日志,系统CPU、Memory等),若干broker(Kafka支持水平扩展,通常broker数量越多,集群吞吐率越高),若干Consumer Group,以及一个Zookeeper集群。

Kafka经过Zookeeper管理集群配置,选举leader,以及在Consumer Group发生变化时进行rebalance。

Producer使用push模式将消息发布到broker,Consumer使用pull模式从broker订阅并消费消息。

至于rabbitMQ,也有普通集群和镜像集群模式,自行去了解,比较简单,两小时即懂。

要求,在回答高可用的问题时,应该能逻辑清晰的画出本身的MQ集群架构或清晰的叙述出来。

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

这个问题其实换一种问法就是,如何保证消息队列的幂等性?

这个问题能够认为是消息队列领域的基本问题。换句话来讲,是在考察你的设计能力,这个问题的回答能够根据具体的业务场景来答,没有固定的答案。

回答:先来讲一下为何会形成重复消费?

其实不管是那种消息队列,形成重复消费缘由其实都是相似的。

正常状况下,消费者在消费消息时候,消费完毕后,会发送一个确认信息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除。只是不一样的消息队列发送的确认信息形式不一样

例如RabbitMQ是发送一个ACK确认消息,RocketMQ是返回一个CONSUME_SUCCESS成功标志,kafka实际上有个offset的概念

简单说一下(若是还不懂,出门找一个kafka入门到精通教程),就是每个消息都有一个offset,kafka消费过消息后,须要提交offset,让消息队列知道本身已经消费过了。

那形成重复消费的缘由?

就是由于网络传输等等故障,确认信息没有传送到消息队列,致使消息队列不知道本身已经消费过该消息了,再次将该消息分发给其余的消费者。

如何解决?这个问题针对业务场景来答分如下几点

一、好比,你拿到这个消息作数据库的insert操做。

那就容易了,给这个消息作一个惟一主键,那么就算出现重复消费的状况,就会致使主键冲突,避免数据库出现脏数据。

二、再好比,你拿到这个消息作redis的set的操做

那就容易了,不用解决。由于你不管set几回结果都是同样的,set操做原本就算幂等操做。

三、若是上面两种状况还不行,上大招。

准备一个第三方介质,来作消费记录。以redis为例,给消息分配一个全局id,只要消费过该消息,将以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录便可。

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

分析:咱们在使用消息队列的过程当中,应该作到消息不能多消费,也不能少消费。若是没法作到可靠性传输,可能给公司带来千万级别的财产损失。

一样的,若是可靠性传输在使用过程当中,没有考虑到,这不是给公司挖坑么,你能够拍拍屁股走了,公司损失的钱,谁承担。

仍是那句话,认真对待每个项目,不要给公司挖坑

回答:其实这个可靠性传输,每种MQ都要从三个角度来分析:生产者弄丢数据、消息队列弄丢数据、消费者弄丢数据

RabbitMQ

一、生产者丢数据

从生产者弄丢数据这个角度来看,RabbitMQ提供transaction和confirm模式来确保生产者不丢消息。

transaction机制就是说,发送消息前,开启事物(channel.txSelect()),而后发送消息,若是发送过程当中出现什么异常,事物就会回滚(channel.txRollback()),若是发送成功则提交事物(channel.txCommit())。

然而缺点就是吞吐量降低了。所以,按照博主的经验,生产上用confirm模式的居多。

一旦channel进入confirm模式,全部在该信道上面发布的消息都将会被指派一个惟一的ID(从1开始)

一旦消息被投递到全部匹配的队列以后,rabbitMQ就会发送一个Ack给生产者(包含消息的惟一ID)

这就使得生产者知道消息已经正确到达目的队列了.若是rabiitMQ没能处理该消息,则会发送一个Nack消息给你,你能够进行重试操做。

处理Ack和Nack的代码以下所示(说好不上代码的,偷偷上了):

 

当面试官要你介绍一下MQ时,该怎么回答?

 

 

二、消息队列丢数据

处理消息队列丢数据的状况,通常是开启持久化磁盘的配置。

这个持久化配置能够和confirm机制配合使用,你能够在消息持久化磁盘后,再给生产者发送一个Ack信号。

这样,若是消息持久化磁盘以前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会自动重发。

那么如何持久化呢,这里顺便说一下吧,其实也很容易,就下面两步

一、将queue的持久化标识durable设置为true,则表明是一个持久的队列

二、发送消息的时候将deliveryMode=2

这样设置之后,rabbitMQ就算挂了,重启后也能恢复数据

三、消费者丢数据

消费者丢数据通常是由于采用了自动确认消息模式。

这种模式下,消费者会自动确认收到信息。这时rahbitMQ会当即将消息删除,这种状况下若是消费者出现异常而没能处理该消息,就会丢失该消息。

至于解决方案,采用手动确认消息便可。

kafka

 

当面试官要你介绍一下MQ时,该怎么回答?

 

 

Producer在发布消息到某个Partition时,先经过ZooKeeper找到该Partition的Leader

而后不管该Topic的Replication Factor为多少(也即该Partition有多少个Replica),Producer只将该消息发送到该Partition的Leader。

Leader会将该消息写入其本地Log。每一个Follower都从Leader中pull数据。

针对上述状况,得出以下分析

一、生产者丢数据

在kafka生产中,基本都有一个leader和多个follwer。follwer会去同步leader的信息。

所以,为了不生产者丢数据,作以下两点配置

第一个配置要在producer端设置acks=all。这个配置保证了,follwer同步完成后,才认为消息发送成功。

在producer端设置retries=MAX,一旦写入失败,这无限重试

二、消息队列丢数据

针对消息队列丢数据的状况,无外乎就是,数据还没同步,leader就挂了,这时zookpeer会将其余的follwer切换为leader,那数据就丢失了。

针对这种状况,应该作两个配置。

replication.factor参数,这个值必须大于1,即要求每一个partition必须有至少2个副本

min.insync.replicas参数,这个值必须大于1,这个是要求一个leader至少感知到有至少一个follower还跟本身保持联系

这两个配置加上上面生产者的配置联合起来用,基本可确保kafka不丢数据

三、消费者丢数据

这种状况通常是自动提交了offset,而后你处理程序过程当中挂了。kafka觉得你处理好了。

再强调一次offset是干吗的

offset:指的是kafka的topic中的每一个消费组消费的下标。

简单的来讲就是一条消息对应一个offset下标,每次消费数据的时候若是提交offset,那么下次消费就会从提交的offset加一那里开始消费。

好比一个topic中有100条数据,我消费了50条而且提交了,那么此时的kafka服务端记录提交的offset就是49(offset从0开始),那么下次消费的时候offset就从50开始消费。

解决方案也很简单,改为手动提交便可。

7、如何保证消息的顺序性?

分析:其实并不是全部的公司都有这种业务需求,可是仍是对这个问题要有所复习。

回答:针对这个问题,经过某种算法,将须要保持前后顺序的消息放到同一个消息队列中(kafka中就是partition,rabbitMq中就是queue)。而后只用一个消费者去消费该队列。

有的人会问:那若是为了吞吐量,有多个消费者去消费怎么办?

这个问题,没有固定回答的套路。好比咱们有一个微博的操做,发微博、写评论、删除微博,这三个异步操做。若是是这样一个业务场景,那只要重试就行。

好比你一个消费者先执行了写评论的操做,可是这时候,微博都还没发,写评论必定是失败的,等一段时间。等另外一个消费者,先执行写评论的操做后,再执行,就能够成功。

总之,针对这个问题,个人观点是保证入队有序就行,出队之后的顺序交给消费者本身去保证,没有固定套路。

 

当面试官要你介绍一下MQ时,该怎么回答?

 

 

8、总结

写到这里,但愿读者把本文提出的这几个问题,通过深入的准备后,通常来讲,能囊括大部分的消息队列的知识点。

若是面试官不问这几个问题怎么办,简单,本身把几个问题讲清楚,突出如下本身考虑的全面性。

最后,其实我不太提倡这样突击复习,但愿你们打好基本功,作一个爱思考,懂思考,会思考的程序员。

感谢你看完个人长篇大论,若是以为对你有帮助的话,能够动动你敲代码的小手帮我点个赞。

或者也能够关注个人公众号【Java技术zhai】,不按期的技术干货内容分享,带你从新定义架构的魅力!

相关文章
相关标签/搜索