今日分享开始啦,请大家多多指教~
本文次要分享美团面试经验和学习办法,心愿能帮忙到你们。Java学习是一步一积攒的,面试的过程中会波及到很多的知识点,本人学会总结很重要!
1、为什么要应用音讯队列?
剖析:一个用音讯队列的人,不晓得为什么用,有点难堪。没有温习这点,很容易被问蒙,而后就开始胡扯了。
答复:这个问题,只答三个最次要的利用场景(不可否认还有其余的,然而只答三个次要的),即以下六个字:解耦、异步、削峰
(1)解耦
传统模式:
传统模式的毛病:
- 零碎间耦合性太强,如上图所示,零碎A在代码中间接调用零碎B和零碎C的代码,如果未来D零碎接入,零碎A还须要批改代码,过于麻烦!
中间件模式:
中间件模式的的长处:
- 将音讯写入音讯队列,须要音讯的零碎本人从音讯队列中订阅,从而零碎A不须要做任何批改。
(2)异步
传统模式:
传统模式的毛病:
- 一些非必要的业务逻辑以同步的形式运行,太消耗工夫。
中间件模式:
中间件模式的的长处:
- 将音讯写入音讯队列,非必要的业务逻辑以异步的形式运行,放慢响应速度
(3)削峰
传统模式
传统模式的毛病:
- 并发量大的时候,所有的申请间接怼到数据库,造成数据库连贯异样
中间件模式:
中间件模式的的长处:
- 零碎A缓缓地依照数据库能解决的并发量,从音讯队列中缓缓拉取音讯。在生产中,这个短暂的高峰期积压是容许的。
2、应用了音讯队列会有什么毛病?
剖析:一个应用了MQ的我的项目,如果连这个问题都没有思考过,就把MQ引进去了,那就给本人的我的项目带来了危险。
咱们引入一个技术,要对这个技术的弊病有充沛的意识,能力做好预防。要记住,不要给本人挖坑!
答复:答复也很容易,从以下两个个角度来答
- 零碎可用性升高:
你想啊,原本其余零碎只有运行好好的,那你的零碎就是失常的。当初你非要加个音讯队列进去,那音讯队列挂了。因而,零碎可用性升高。
- 零碎复杂性减少:
要多思考很多方面的问题,比方一致性问题、如何保障音讯不被反复生产,如何保障保障音讯牢靠传输。
因而,须要思考的货色更多,零碎复杂性增大。然而,咱们该用还是要用的。
3、音讯队列如何选型?
先说一下,我只会ActiveMQ,RabbitMQ,RocketMQ,Kafka,对什么ZeroMQ等其余MQ没啥了解,因而只能基于这四种MQ给出答复。
剖析:既然在我的项目中用了MQ,必定当时要对业界风行的MQ进行调研,如果连每种MQ的优缺点都没理解分明,就拍脑袋根据爱好,用了某种MQ,还是给我的项目挖坑。
如果面试官问:”你为什么用这种MQ?。”你间接答复”领导决定的。”这种答复就很LOW了。
咱们能够看出,RabbitMQ版本公布比ActiveMq频繁很多。至于RocketMQ和kafka就不带大家看了,总之也比ActiveMQ沉闷得多。
再来一个性能比照表:
综合下面的资料得出以下两点:
(1)中小型软件公司,倡议选RabbitMQ.
一方面,erlang语言天生具备高并发的个性,而且他的治理界面用起来非常不便。
正所谓,成也萧何,败也萧何!他的弊病也在这里,尽管RabbitMQ是开源的,然而国内有几个能定制化开发erlang的程序员呢?
所幸,RabbitMQ的社区非常沉闷,能够解决开发过程中遇到的bug,这点对于中小型公司来说非常重要。
不思考rocketmq和kafka的起因是,一方面中小型软件公司不如互联网公司,数据量没那么大,选消息中间件,应首选性能比拟齐备的,所以kafka排除。
不思考rocketmq的起因是,rocketmq是阿里出品,如果阿里放弃保护rocketmq,中小型公司个别抽不出人来进行rocketmq的定制化开发,因而不举荐。
(2)大型软件公司,依据具体应用在rocketMq和kafka之间二选一
一方面,大型软件公司,具备足够的资金搭建分布式环境,也具备足够大的数据量。
针对rocketMQ,大型软件公司也能够抽出人手对rocketMQ进行定制化开发,毕竟国内有能力改JAVA源码的人,还是相当多的。
至于kafka,依据业务场景抉择,如果有日志采集性能,必定是首选kafka了。具体该选哪个,看应用场景。
4、如何保障音讯队列是高可用的?
剖析:在第二点说过了,引入音讯队列后,零碎的可用性降落。在生产中,没人应用单机模式的音讯队列。
因而,作为一个合格的程序员,应该对音讯队列的高可用有很粗浅的理解。
如果面试的时候,面试官问,你们的消息中间件如何保障高可用的?
如果你的答复只是表明本人只会订阅和公布音讯,面试官就会狐疑你是不是只是本人搭着玩,压根没在生产用过。
因而,请做一个爱思考,会思考,懂思考的程序员。
答复:这问题,其实要对音讯队列的集群模式要有粗浅理解,才好答复。
以rcoketMQ为例,他的集群就有多master 模式、多master多slave异步复制模式、多 master多slave同步双写模式。
多master多slave模式部署架构图:
其实第一眼看到这个图,就感觉和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的拓补架构图:
如上图所示,一个典型的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的概念。
简略说一下,就是每一个音讯都有一个offset,kafka生产过音讯后,须要提交offset,让音讯队列晓得本人曾经生产过了。
那造成反复生产的起因?
就是因为网络传输等等故障,确认信息没有传送到音讯队列,导致音讯队列不晓得本人曾经生产过该音讯了,再次将该音讯分发给其余的消费者。
如何解决?这个问题针对业务场景来答分以下几点
(1)比方,你拿到这个音讯做数据库的insert操作。
那就容易了,给这个音讯做一个惟一主键,那么就算呈现反复生产的状况,就会导致主键抵触,防止数据库呈现脏数据。
(2)再比方,你拿到这个音讯做redis的set的操作。
那就容易了,不必解决。因为你无论set几次后果都是一样的,set操作原本就算幂等操作。
(3)如果下面两种状况还不行,上大招。
筹备一个第三方介质,来做生产记录。以redis为例,给音讯调配一个全局id,只有生产过该音讯,将以K-V模式写入redis。那消费者开始生产前,先去redis中查问有没生产记录即可。
6、如何保障生产的可靠性传输?
剖析:咱们在应用音讯队列的过程中,应该做到音讯不能多生产,也不能少生产。如果无奈做到可靠性传输,可能给公司带来千万级别的财产损失。还是那句话,认真对待每一个我的项目。
答复:其实这个可靠性传输,每种MQ都要从三个角度来剖析:生产者弄丢数据、音讯队列弄丢数据、消费者弄丢数据。
RabbitMQ
(1)生产者丢数据
从生产者弄丢数据这个角度来看,RabbitMQ提供transaction和confirm模式来确保生产者不丢音讯。
transaction机制就是说,发送音讯前,开启事物(channel.txSelect()),而后发送音讯,如果发送过程中呈现什么异样,事物就会回滚(channel.txRollback()),如果发送胜利则提交事物(channel.txCommit())。
然而毛病就是吞吐量降落了。因而,依照之前的教训,生产上用confirm模式的居多。
一旦channel进入confirm模式,所有在该信道下面公布的音讯都将会被指派一个惟一的ID(从1开始)
一旦音讯被投递到所有匹配的队列之后,rabbitMQ就会发送一个Ack给生产者(蕴含音讯的惟一ID)
这就使得生产者晓得音讯曾经正确达到目标队列了.如果rabiitMQ没能解决该音讯,则会发送一个Nack音讯给你,你能够进行重试操作。
解决Ack和Nack的代码如下所示:
(2)音讯队列丢数据
解决音讯队列丢数据的状况,个别是开启长久化磁盘的配置。
这个长久化配置能够和confirm机制配合应用,你能够在音讯长久化磁盘后,再给生产者发送一个Ack信号。
这样,如果音讯长久化磁盘之前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会主动重发。
那么如何长久化呢,这里顺便说一下吧,其实也很容易,就上面两步
1、将queue的长久化标识durable设置为true,则代表是一个长久的队列
2、发送音讯的时候将deliveryMode=2
这样设置当前,rabbitMQ就算挂了,重启后也能复原数据
(3)消费者丢数据
消费者丢数据个别是因为采纳了主动确认音讯模式。
这种模式下,消费者会主动确认收到信息。这时rahbitMQ会立刻将音讯删除,这种状况下如果消费者出现异常而没能解决该音讯,就会失落该音讯。
至于解决方案,采纳手动确认音讯即可。
kafka
Producer在公布音讯到某个Partition时,先通过ZooKeeper找到该Partition的Leader
而后无论该Topic的Replication Factor为多少(也即该Partition有多少个Replica),Producer只将该音讯发送到该Partition的Leader。
Leader会将该音讯写入其本地Log。每个Follower都从Leader中pull数据。
针对上述情况,得出如下剖析
(1)生产者丢数据
在kafka生产中,根本都有一个leader和多个follwer。follwer会去同步leader的信息。
因而,为了防止生产者丢数据,做如下两点配置
第一个配置要在producer端设置acks=all。这个配置保障了,follwer同步实现后,才认为音讯发送胜利。
在producer端设置retries=MAX,一旦写入失败,这有限重试
(2)音讯队列丢数据
针对音讯队列丢数据的状况,无外乎就是,数据还没同步,leader就挂了,这时zookpeer会将其余的follwer切换为leader,那数据就失落了。
针对这种状况,应该做两个配置。
replication.factor参数,这个值必须大于1,即要求每个partition必须有至多2个正本;
min.insync.replicas参数,这个值必须大于1,这个是要求一个leader至多感知到有至多一个follower还跟本人保持联系。
这两个配置加上下面生产者的配置联结起来用,根本可确保kafka不丢数据。
(3)消费者丢数据
这种状况个别是主动提交了offset,而后你处理程序过程中挂了。kafka认为你解决好了。
再强调一次offset是干嘛的。
offset:指的是kafka的topic中的每个生产组生产的下标。
简略的来说就是一条音讯对应一个offset下标,每次生产数据的时候如果提交offset,那么下次生产就会从提交的offset加一那里开始生产。
比方一个topic中有100条数据,我生产了50条并且提交了,那么此时的kafka服务端记录提交的offset就是49(offset从0开始),那么下次生产的时候offset就从50开始生产。
解决方案也很简略,改成手动提交即可。
7、如何保障音讯的程序性?
剖析:其实并非所有的公司都有这种业务需要,然而还是对这个问题要有所温习。
答复:针对这个问题,通过某种算法,将须要放弃先后顺序的音讯放到同一个音讯队列中(kafka中就是partition,rabbitMq中就是queue)。而后只用一个消费者去生产该队列。
有的人会问:那如果为了吞吐量,有多个消费者去生产怎么办?
这个问题,没有固定答复的套路。比方咱们有一个微博的操作,发微博、写评论、删除微博,这三个异步操作。如果是这样一个业务场景,那只有重试就行。
比方你一个消费者先执行了写评论的操作,然而这时候,微博都还没发,写评论肯定是失败的,等一段时间。等另一个消费者,先执行写评论的操作后,再执行,就能够胜利。
总之,针对这个问题,我的观点是保障入队有序就行,出队当前的程序交给消费者本人去保障,没有固定套路。
小结
以上文章中阐明了一下音讯队列相干的问题以及答复,想要扭转“命运”,没有背景没有资本的人,只能通过怠惰取得,侥幸女神往往会眷顾致力的人,一起加油!
今日份分享已完结,请大家多多包涵和指导!
发表回复