今日分享开始啦,请大家多多指教~
本文次要分享美团面试经验和学习办法,心愿能帮忙到你们。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)。而后只用一个消费者去生产该队列。
有的人会问: 那如果为了吞吐量,有多个消费者去生产怎么办?
这个问题,没有固定答复的套路。比方咱们有一个微博的操作,发微博、写评论、删除微博,这三个异步操作。如果是这样一个业务场景,那只有重试就行。
比方你一个消费者先执行了写评论的操作,然而这时候,微博都还没发,写评论肯定是失败的,等一段时间。等另一个消费者,先执行写评论的操作后,再执行,就能够胜利。
总之,针对这个问题,我的观点是保障入队有序就行,出队当前的程序交给消费者本人去保障,没有固定套路。
小结
以上文章中阐明了一下音讯队列相干的问题以及答复,想要扭转“命运”,没有背景没有资本的人,只能通过怠惰取得,侥幸女神往往会眷顾致力的人,一起加油!
今日份分享已完结,请大家多多包涵和指导!