消息队列面试题、RabbitMQ面试题、Kafka面试题、RocketMQ面试题 (史上最全、持续更新、吐血推荐)


疯狂创客圈 史上最强 面试题 系列
Java基础
JVM面试题(史上最强、持续更新、吐血推荐) http://www.javashuo.com/article/p-vhnpdnhb-vd.html
Java基础面试题(史上最全、持续更新、吐血推荐) https://www.cnblogs.com/crazymakercircle/p/14366081.html
死锁面试题(史上最强、持续更新) http://www.javashuo.com/article/p-uyudvdol-vd.html
多线程、线程池、内置锁 面试题 (史上最强、持续更新) http://www.javashuo.com/article/p-tecubweb-vd.html
JUC并发包与容器类 - 面试题(史上最强、持续更新) http://www.javashuo.com/article/p-xcyjkbgi-vd.html
SpringBoot - 面试题(史上最强、持续更新) http://www.javashuo.com/article/p-xjwdvxjl-vd.html
Linux面试题(史上最全、持续更新、吐血推荐) https://www.cnblogs.com/crazymakercircle/p/14366893.html
分布式、高并发、设计模式、架构
Zookeeper 面试题(史上最强、持续更新) http://www.javashuo.com/article/p-fvxlillp-vd.html
Mysql 面试题(史上最强、持续更新) http://www.javashuo.com/article/p-xhmrgfwk-vd.html
Redis 面试题 - 收藏版(史上最强、持续更新) http://www.javashuo.com/article/p-vkywkhov-vd.html
SpringCloud 面试题 - 收藏版(史上最强、持续更新) http://www.javashuo.com/article/p-pptrkvmu-vd.html
Netty 面试题 (史上最强、持续更新) http://www.javashuo.com/article/p-guuqkocg-vd.html
消息队列、RabbitMQ、Kafka、RocketMQ面试题 (史上最全、持续更新、吐血推荐) https://www.cnblogs.com/crazymakercircle/p/14367425.html
设计模式面试题 (史上最全、持续更新、吐血推荐) http://www.javashuo.com/article/p-qnkzhtsu-vd.html
架构设计面试题 (史上最全、持续更新、吐血推荐) http://www.javashuo.com/article/p-dlpjqbmg-vd.html

MQ基础

问:为何使用MQ?MQ的优势

简答html

  • 异步处理 - 相比于传统的串行、并行方式,提升了系统吞吐量。
  • 应用解耦 - 系统间经过消息通讯,不用关心其余系统的处理。
  • 流量削锋 - 能够经过消息队列长度控制请求量;能够缓解短期内的高并发请求。
  • 日志处理 - 解决大量日志传输。
  • 消息通信 - 消息队列通常都内置了高效的通讯机制,所以也能够用在纯的消息通信。好比实现点对点消息队列,或者聊天室等。

详答java

主要是:解耦、异步、削峰。node

解耦:A 系统发送数据到 BCD 三个系统,经过接口调用发送。若是 E 系统也要这个数据呢?那若是 C 系统如今不须要了呢?A 系统负责人几乎崩溃…A 系统跟其它各类乱七八糟的系统严重耦合,A 系统产生一条比较关键的数据,不少系统都须要 A 系统将这个数据发送过来。若是使用 MQ,A 系统产生一条数据,发送到 MQ 里面去,哪一个系统须要数据本身去 MQ 里面消费。若是新系统须要数据,直接从 MQ 里消费便可;若是某个系统不须要这条数据了,就取消对 MQ 消息的消费便可。这样下来,A 系统压根儿不须要去考虑要给谁发送数据,不须要维护这个代码,也不须要考虑人家是否调用成功、失败超时等状况。git

就是一个系统或者一个模块,调用了多个系统或者模块,互相之间的调用很复杂,维护起来很麻烦。可是其实这个调用是不须要直接同步调用接口的,若是用 MQ 给它异步化解耦。github

异步:A 系统接收一个请求,须要在本身本地写库,还须要在 BCD 三个系统写库,本身本地写库要 3ms,BCD 三个系统分别写库要 300ms、450ms、200ms。最终请求总延时是 3 + 300 + 450 + 200 = 953ms,接近 1s,用户感受搞个什么东西,慢死了慢死了。用户经过浏览器发起请求。若是使用 MQ,那么 A 系统连续发送 3 条消息到 MQ 队列中,假如耗时 5ms,A 系统从接受一个请求到返回响应给用户,总时长是 3 + 5 = 8ms。面试

削峰:减小高峰时期对服务器压力。算法

问:消息队列有什么优缺点?RabbitMQ有什么优缺点?

优势上面已经说了,就是在特殊场景下有其对应的好处解耦异步削峰sql

缺点有如下几个:数据库

系统可用性下降apache

原本系统运行好好的,如今你非要加入个消息队列进去,那消息队列挂了,你的系统不是呵呵了。所以,系统可用性会下降;

系统复杂度提升

加入了消息队列,要多考虑不少方面的问题,好比:一致性问题、如何保证消息不被重复消费、如何保证消息可靠性传输等。所以,须要考虑的东西更多,复杂性增大。

一致性问题

A 系统处理完了直接返回成功了,人都觉得你这个请求就成功了;可是问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致了。

因此消息队列实际是一种很是复杂的架构,你引入它有不少好处,可是也得针对它带来的坏处作各类额外的技术方案和架构来规避掉,作好以后,你会发现,妈呀,系统复杂度提高了一个数量级,也许是复杂了 10 倍。可是关键时刻,用,仍是得用的。

问:大家公司生产环境用的是什么消息中间件?

这个首先你能够说下大家公司选用的是什么消息中间件,好比用的是RabbitMQ,而后能够初步给一些你对不一样MQ中间件技术的选型分析。

举个例子:好比说ActiveMQ是老牌的消息中间件,国内不少公司过去运用的仍是很是普遍的,功能很强大。

可是问题在于无法确认ActiveMQ能够支撑互联网公司的高并发、高负载以及高吞吐的复杂场景,在国内互联网公司落地较少。并且使用较多的是一些传统企业,用ActiveMQ作异步调用和系统解耦。

而后你能够说说RabbitMQ,他的好处在于能够支撑高并发、高吞吐、性能很高,同时有很是完善便捷的后台管理界面能够使用。

另外,他还支持集群化、高可用部署架构、消息高可靠支持,功能较为完善。

并且通过调研,国内各大互联网公司落地大规模RabbitMQ集群支撑自身业务的case较多,国内各类中小型互联网公司使用RabbitMQ的实践也比较多。

除此以外,RabbitMQ的开源社区很活跃,较高频率的迭代版本,来修复发现的bug以及进行各类优化,所以综合考虑事后,公司采起了RabbitMQ。

可是RabbitMQ也有一点缺陷,就是他自身是基于erlang语言开发的,因此致使较为难以分析里面的源码,也较难进行深层次的源码定制和改造,毕竟须要较为扎实的erlang语言功底才能够。

而后能够聊聊RocketMQ,是阿里开源的,通过阿里的生产环境的超高并发、高吞吐的考验,性能卓越,同时还支持分布式事务等特殊场景。

并且RocketMQ是基于Java语言开发的,适合深刻阅读源码,有须要能够站在源码层面解决线上生产问题,包括源码的二次开发和改造。

另外就是Kafka。Kafka提供的消息中间件的功能明显较少一些,相对上述几款MQ中间件要少不少。

可是Kafka的优点在于专为超高吞吐量的实时日志采集、实时数据同步、实时数据计算等场景来设计。

所以Kafka在大数据领域中配合实时计算技术(好比Spark Streaming、Storm、Flink)使用的较多。可是在传统的MQ中间件使用场景中较少采用。

问:Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什么优缺点?

ActiveMQ RabbitMQ RocketMQ Kafka ZeroMQ
单机吞吐量 比RabbitMQ低 2.6w/s(消息作持久化) 11.6w/s 17.3w/s 29w/s
开发语言 Java Erlang Java Scala/Java C
主要维护者 Apache Mozilla/Spring Alibaba Apache iMatix,创始人已去世
成熟度 成熟 成熟 开源版本不够成熟 比较成熟 只有C、PHP等版本成熟
订阅形式 点对点(p2p)、广播(发布-订阅) 提供了4种:direct, topic ,Headers和fanout。fanout就是广播模式 基于topic/messageTag以及按照消息类型、属性进行正则匹配的发布订阅模式 基于topic以及按照topic进行正则匹配的发布订阅模式 点对点(p2p)
持久化 支持少许堆积 支持少许堆积 支持大量堆积 支持大量堆积 不支持
顺序消息 不支持 不支持 支持 支持 不支持
性能稳定性 通常 较差 很好
集群方式 支持简单集群模式,好比’主-备’,对高级集群模式支持很差。 支持简单集群,'复制’模式,对高级集群模式支持很差。 经常使用 多对’Master-Slave’ 模式,开源版本需手动切换Slave变成Master 自然的‘Leader-Slave’无状态集群,每台服务器既是Master也是Slave 不支持
管理界面 通常 较好 通常

综上,各类对比以后,有以下建议:

通常的业务系统要引入 MQ,最先你们都用 ActiveMQ,可是如今确实你们用的很少了,没通过大规模吞吐量场景的验证,社区也不是很活跃,因此你们仍是算了吧,我我的不推荐用这个了;

后来你们开始用 RabbitMQ,可是确实 erlang 语言阻止了大量的 Java 工程师去深刻研究和掌控它,对公司而言,几乎处于不可控的状态,可是确实人家是开源的,比较稳定的支持,活跃度也高;

不过如今确实愈来愈多的公司会去用 RocketMQ,确实很不错,毕竟是阿里出品,但社区可能有忽然黄掉的风险(目前 RocketMQ 已捐给 Apache,但 GitHub 上的活跃度其实不算高)对本身公司技术实力有绝对自信的,推荐用 RocketMQ,不然回去老老实实用 RabbitMQ 吧,人家有活跃的开源社区,绝对不会黄。

因此中小型公司,技术实力较为通常,技术挑战不是特别高,用 RabbitMQ 是不错的选择;大型公司,基础架构研发实力较强,用 RocketMQ 是很好的选择。

若是是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,况且几乎是全世界这个领域的事实性规范。

问:MQ 有哪些常见问题?如何解决这些问题?

MQ 的常见问题有:

  1. 消息的顺序问题
  2. 消息的重复问题

消息的顺序问题

消息有序指的是能够按照消息的发送顺序来消费。

假如生产者产生了 2 条消息:M一、M2,假定 M1 发送到 S1,M2 发送到 S2,若是要保证 M1 先于 M2 被消费,怎么作?

img

解决方案:

(1)保证生产者 - MQServer - 消费者是一对一对一的关系

img

缺陷:

  • 并行度就会成为消息系统的瓶颈(吞吐量不够)
  • 更多的异常处理,好比:只要消费端出现问题,就会致使整个处理流程阻塞,咱们不得不花费更多的精力来解决阻塞的问题。 (2)经过合理的设计或者将问题分解来规避。
  • 不关注乱序的应用实际大量存在
  • 队列无序并不意味着消息无序 因此从业务层面来保证消息的顺序而不只仅是依赖于消息系统,是一种更合理的方式。

消息的重复问题

形成消息重复的根本缘由是:网络不可达。

因此解决这个问题的办法就是绕过这个问题。那么问题就变成了:若是消费端收到两条同样的消息,应该怎样处理?

消费端处理消息的业务逻辑保持幂等性。只要保持幂等性,无论来多少条重复消息,最后处理的结果都同样。保证每条消息都有惟一编号且保证消息处理成功与去重表的日志同时出现。利用一张日志表来记录已经处理成功的消息的 ID,若是新到的消息 ID 已经在日志表中,那么就再也不处理这条消息。

问:说说设计MQ思路?

好比说这个消息队列系统,咱们从如下几个角度来考虑一下:

首先这个 mq 得支持可伸缩性吧,就是须要的时候快速扩容,就能够增长吞吐量和容量,那怎么搞?设计个分布式的系统呗,参照一下 kafka 的设计理念,broker -> topic -> partition,每一个 partition 放一个机器,就存一部分数据。若是如今资源不够了,简单啊,给 topic 增长 partition,而后作数据迁移,增长机器,不就能够存放更多数据,提供更高的吞吐量了?

其次你得考虑一下这个 mq 的数据要不要落地磁盘吧?那确定要了,落磁盘才能保证别进程挂了数据就丢了。那落磁盘的时候怎么落啊?顺序写,这样就没有磁盘随机读写的寻址开销,磁盘顺序读写的性能是很高的,这就是 kafka 的思路。

其次你考虑一下你的 mq 的可用性啊?这个事儿,具体参考以前可用性那个环节讲解的 kafka 的高可用保障机制。多副本 -> leader & follower -> broker 挂了从新选举 leader 便可对外服务。

能不能支持数据 0 丢失啊?能够的,参考咱们以前说的那个 kafka 数据零丢失方案。

RabbitMQ

问:什么是RabbitMQ?

RabbitMQ是一款开源的,Erlang编写的,基于AMQP协议的消息中间件

问:rabbitmq 的使用场景

(1)服务间异步通讯

(2)顺序消费

(3)定时任务

(4)请求削峰

问:RabbitMQ基本概念

  • Broker: 简单来讲就是消息队列服务器实体
  • Exchange: 消息交换机,它指定消息按什么规则,路由到哪一个队列
  • Queue: 消息队列载体,每一个消息都会被投入到一个或多个队列
  • Binding: 绑定,它的做用就是把exchange和queue按照路由规则绑定起来
  • Routing Key: 路由关键字,exchange根据这个关键字进行消息投递
  • VHost: vhost 能够理解为虚拟 broker ,即 mini-RabbitMQ server。其内部均含有独立的 queue、exchange 和 binding 等,但最最重要的是,其拥有独立的权限系统,能够作到 vhost 范围的用户控制。固然,从 RabbitMQ 的全局角度,vhost 能够做为不一样权限隔离的手段(一个典型的例子就是不一样的应用能够跑在不一样的 vhost 中)。
  • Producer: 消息生产者,就是投递消息的程序
  • Consumer: 消息消费者,就是接受消息的程序
  • Channel: 消息通道,在客户端的每一个链接里,可创建多个channel,每一个channel表明一个会话任务

由Exchange、Queue、RoutingKey三个才能决定一个从Exchange到Queue的惟一的线路。

问:RabbitMQ的工做模式

一.simple模式(即最简单的收发模式)

img

1.消息产生消息,将消息放入队列

2.消息的消费者(consumer) 监听 消息队列,若是队列中有消息,就消费掉,消息被拿走后,自动从队列中删除(隐患 消息可能没有被消费者正确处理,已经从队列中消失了,形成消息的丢失,这里能够设置成手动的ack,但若是设置成手动ack,处理完后要及时发送ack消息给队列,不然会形成内存溢出)。

二.work工做模式(资源的竞争)

img

1.消息产生者将消息放入队列消费者能够有多个,消费者1,消费者2同时监听同一个队列,消息被消费。C1 C2共同争抢当前的消息队列内容,谁先拿到谁负责消费消息(隐患:高并发状况下,默认会产生某一个消息被多个消费者共同使用,能够设置一个开关(syncronize) 保证一条消息只能被一个消费者使用)。

三.publish/subscribe发布订阅(共享资源)

img

一、每一个消费者监听本身的队列;

二、生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每一个队列,每一个绑定交换机的队列都将接收到消息。

四.routing路由模式

img

1.消息生产者将消息发送给交换机按照路由判断,路由是字符串(info) 当前产生的消息携带路由字符(对象的方法),交换机根据路由的key,只能匹配上路由key对应的消息队列,对应的消费者才能消费消息;

2.根据业务功能定义路由字符串

3.从系统的代码逻辑中获取对应的功能字符串,将消息任务扔到对应的队列中。

4.业务场景:error 通知;EXCEPTION;错误通知的功能;传统意义的错误通知;客户通知;利用key路由,能够将程序中的错误封装成消息传入到消息队列中,开发者能够自定义消费者,实时接收错误;

五.topic 主题模式(路由模式的一种)

img

1.星号井号表明通配符

2.星号表明多个单词,井号表明一个单词

3.路由功能添加模糊匹配

4.消息产生者产生消息,把消息交给交换机

5.交换机根据key的规则模糊匹配到对应的队列,由队列的监听消费者接收消息消费

(在个人理解看来就是routing查询的一种模糊匹配,就相似sql的模糊查询方式)

问:如何保证RabbitMQ消息的顺序性?

拆分多个 queue,每一个 queue 一个 consumer,就是多一些 queue 而已,确实是麻烦点;或者就一个 queue 可是对应一个 consumer,而后这个 consumer 内部用内存队列作排队,而后分发给底层不一样的 worker 来处理。

问:消息如何分发?

若该队列至少有一个消费者订阅,消息将以循环(round-robin)的方式发送给消费者。每条消息只会分发给一个订阅的消费者(前提是消费者可以正常处理消息并进行确认)。经过路由可实现多消费的功能

问:消息怎么路由?

消息提供方->路由->一至多个队列消息发布到交换器时,消息将拥有一个路由键(routing key),在消息建立时设定。经过队列路由键,能够把队列绑定到交换器上。消息到达交换器后,RabbitMQ 会将消息的路由键与队列的路由键进行匹配(针对不一样的交换器有不一样的路由规则);

经常使用的交换器主要分为一下三种:

fanout:若是交换器收到消息,将会广播到全部绑定的队列上

direct:若是路由键彻底匹配,消息就被投递到相应的队列

topic:能够使来自不一样源头的消息可以到达同一个队列。 使用 topic 交换器时,能够使用通配符

问:消息基于什么传输?

因为 TCP 链接的建立和销毁开销较大,且并发数受系统资源限制,会形成性能瓶颈。RabbitMQ 使用信道的方式来传输数据。信道是创建在真实的 TCP 链接内的虚拟链接,且每条 TCP 链接上的信道数量没有限制。

问:如何保证消息不被重复消费?或者说,如何保证消息消费时的幂等性?

先说为何会重复消费:正常状况下,消费者在消费消息的时候,消费完毕后,会发送一个确认消息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除;

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

针对以上问题,一个解决思路是:保证消息的惟一性,就算是屡次传输,不要让消息的屡次消费带来影响;保证消息等幂性;

好比:在写入消息队列的数据作惟一标示,消费消息时,根据惟一标识判断是否消费过;

假设你有个系统,消费一条消息就往数据库里插入一条数据,要是你一个消息重复两次,你不就插入了两条,这数据不就错了?可是你要是消费到第二次的时候,本身判断一下是否已经消费过了,如果就直接扔了,这样不就保留了一条数据,从而保证了数据的正确性。

问:如何确保消息正确地发送至 RabbitMQ? 如何确保消息接收方消费了消息?

发送方确认模式

将信道设置成 confirm 模式(发送方确认模式),则全部在信道上发布的消息都会被指派一个惟一的 ID。

一旦消息被投递到目的队列后,或者消息被写入磁盘后(可持久化的消息),信道会发送一个确认给生产者(包含消息惟一 ID)。

若是 RabbitMQ 发生内部错误从而致使消息丢失,会发送一条 nack(notacknowledged,未确认)消息。

发送方确认模式是异步的,生产者应用程序在等待确认的同时,能够继续发送消息。当确认消息到达生产者应用程序,生产者应用程序的回调方法就会被触发来处理确认消息。

接收方确认机制

消费者接收每一条消息后都必须进行确认(消息接收和消息确认是两个不一样操做)。只有消费者确认了消息,RabbitMQ 才能安全地把消息从队列中删除。

这里并无用到超时机制,RabbitMQ 仅经过 Consumer 的链接中断来确认是否须要从新发送消息。也就是说,只要链接不中断,RabbitMQ 给了 Consumer 足够长的时间来处理消息。保证数据的最终一致性;

下面罗列几种特殊状况

  • 若是消费者接收到消息,在确认以前断开了链接或取消订阅,RabbitMQ 会认为消息没有被分发,而后从新分发给下一个订阅的消费者。(可能存在消息重复消费的隐患,须要去重)
  • 若是消费者接收到消息却没有确认消息,链接也未断开,则 RabbitMQ 认为该消费者繁忙,将不会给该消费者分发更多的消息。

问:如何保证RabbitMQ消息的可靠传输?

消息不可靠的状况多是消息丢失,劫持等缘由;

丢失又分为:生产者丢失消息、消息列表丢失消息、消费者丢失消息;

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

transaction机制就是说:发送消息前,开启事务(channel.txSelect()),而后发送消息,若是发送过程当中出现什么异常,事务就会回滚(channel.txRollback()),若是发送成功则提交事务(channel.txCommit())。然而,这种方式有个缺点:吞吐量降低;

confirm模式用的居多:一旦channel进入confirm模式,全部在该信道上发布的消息都将会被指派一个惟一的ID(从1开始),一旦消息被投递到全部匹配的队列以后;

rabbitMQ就会发送一个ACK给生产者(包含消息的惟一ID),这就使得生产者知道消息已经正确到达目的队列了;

若是rabbitMQ没能处理该消息,则会发送一个Nack消息给你,你能够进行重试操做。

消息队列丢数据:消息持久化。

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

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

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

那么如何持久化呢?

这里顺便说一下吧,其实也很容易,就下面两步

  1. 将queue的持久化标识durable设置为true,则表明是一个持久的队列
  2. 发送消息的时候将deliveryMode=2

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

消费者丢失消息:消费者丢数据通常是由于采用了自动确认消息模式,改成手动确认消息便可!

消费者在收到消息以后,处理消息以前,会自动回复RabbitMQ已收到消息;

若是这时处理消息失败,就会丢失该消息;

解决方案:处理消息成功后,手动回复确认消息。

问:为何不该该对全部的 message 都使用持久化机制?

首先,必然致使性能的降低,由于写磁盘比写 RAM 慢的多,message 的吞吐量可能有 10 倍的差距。

其次,message 的持久化机制用在 RabbitMQ 的内置 cluster 方案时会出现“坑爹”问题。矛盾点在于,若 message 设置了 persistent 属性,但 queue 未设置 durable 属性,那么当该 queue 的 owner node 出现异常后,在未重建该 queue 前,发往该 queue 的 message 将被 blackholed ;若 message 设置了 persistent 属性,同时 queue 也设置了 durable 属性,那么当 queue 的 owner node 异常且没法重启的状况下,则该 queue 没法在其余 node 上重建,只能等待其 owner node 重启后,才能恢复该 queue 的使用,而在这段时间内发送给该 queue 的 message 将被 blackholed 。

因此,是否要对 message 进行持久化,须要综合考虑性能须要,以及可能遇到的问题。若想达到 100,000 条/秒以上的消息吞吐量(单 RabbitMQ 服务器),则要么使用其余的方式来确保 message 的可靠 delivery ,要么使用很是快速的存储系统以支持全持久化(例如使用 SSD)。另一种处理原则是:仅对关键消息做持久化处理(根据业务重要程度),且应该保证关键消息的量不会致使性能瓶颈。

问:如何保证高可用的?RabbitMQ 的集群

RabbitMQ 是比较有表明性的,由于是基于主从(非分布式)作高可用性的,咱们就以 RabbitMQ 为例子讲解第一种 MQ 的高可用性怎么实现。RabbitMQ 有三种模式:单机模式、普通集群模式、镜像集群模式。

单机模式,就是 Demo 级别的,通常就是你本地启动了玩玩儿的?,没人生产用单机模式

普通集群模式,意思就是在多台机器上启动多个 RabbitMQ 实例,每一个机器启动一个。你建立的 queue,只会放在一个 RabbitMQ 实例上,可是每一个实例都同步 queue 的元数据(元数据能够认为是 queue 的一些配置信息,经过元数据,能够找到 queue 所在实例)。你消费的时候,实际上若是链接到了另一个实例,那么那个实例会从 queue 所在实例上拉取数据过来。这方案主要是提升吞吐量的,就是说让集群中多个节点来服务某个 queue 的读写操做。

镜像集群模式:这种模式,才是所谓的 RabbitMQ 的高可用模式。跟普通集群模式不同的是,在镜像集群模式下,你建立的 queue,不管元数据仍是 queue 里的消息都会存在于多个实例上,就是说,每一个 RabbitMQ 节点都有这个 queue 的一个完整镜像,包含 queue 的所有数据的意思。而后每次你写消息到 queue 的时候,都会自动把消息同步到多个实例的 queue 上。RabbitMQ 有很好的管理控制台,就是在后台新增一个策略,这个策略是镜像集群模式的策略,指定的时候是能够要求数据同步到全部节点的,也能够要求同步到指定数量的节点,再次建立 queue 的时候,应用这个策略,就会自动将数据同步到其余的节点上去了。这样的话,好处在于,你任何一个机器宕机了,没事儿,其它机器(节点)还包含了这个 queue 的完整数据,别的 consumer 均可以到其它节点上去消费数据。坏处在于,第一,这个性能开销也太大了吧,消息须要同步到全部机器上,致使网络带宽压力和消耗很重!RabbitMQ 一个 queue 的数据都是放在一个节点里的,镜像集群下,也是每一个节点都放这个 queue 的完整数据。

问:如何解决消息队列的延时以及过时失效问题?消息队列满了之后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?

消息积压处理办法:临时紧急扩容:

先修复 consumer 的问题,确保其恢复消费速度,而后将现有 cnosumer 都停掉。
新建一个 topic,partition 是原来的 10 倍,临时创建好原先 10 倍的 queue 数量。
而后写一个临时的分发数据的 consumer 程序,这个程序部署上去消费积压的数据,消费以后不作耗时的处理,直接均匀轮询写入临时创建好的 10 倍数量的 queue。
接着临时征用 10 倍的机器来部署 consumer,每一批 consumer 消费一个临时 queue 的数据。这种作法至关因而临时将 queue 资源和 consumer 资源扩大 10 倍,以正常的 10 倍速度来消费数据。
等快速消费完积压数据以后,得恢复原先部署的架构,从新用原先的 consumer 机器来消费消息。
MQ中消息失效:假设你用的是 RabbitMQ,RabbtiMQ 是能够设置过时时间的,也就是 TTL。若是消息在 queue 中积压超过必定的时间就会被 RabbitMQ 给清理掉,这个数据就没了。那这就是第二个坑了。这就不是说数据会大量积压在 mq 里,而是大量的数据会直接搞丢。咱们能够采起一个方案,就是批量重导,这个咱们以前线上也有相似的场景干过。就是大量积压的时候,咱们当时就直接丢弃数据了,而后等过了高峰期之后,好比你们一块儿喝咖啡熬夜到晚上12点之后,用户都睡觉了。这个时候咱们就开始写程序,将丢失的那批数据,写个临时程序,一点一点的查出来,而后从新灌入 mq 里面去,把白天丢的数据给他补回来。也只能是这样了。假设 1 万个订单积压在 mq 里面,没有处理,其中 1000 个订单都丢了,你只能手动写程序把那 1000 个订单给查出来,手动发到 mq 里去再补一次。

mq消息队列块满了:若是消息积压在 mq 里,你很长时间都没有处理掉,此时致使 mq 都快写满了,咋办?这个还有别的办法吗?没有,谁让你第一个方案执行的太慢了,你临时写程序,接入数据来消费,消费一个丢弃一个,都不要了,快速消费掉全部的消息。而后走第二个方案,到了晚上再补数据吧。

Kafka

基础题

问:一、Apache Kafka 是什么?

Apach Kafka 是一款分布式流处理框架,用于实时构建流处理应用。它有一个核心 的功能广为人知,即做为企业级的消息引擎被普遍使用。

你必定要先明确它的流处理框架地位,这样能给面试官留 下一个很专业的印象。

问:二、什么是消费者组?

消费者组是 Kafka 独有的概念,若是面试官问这 个,就说明他对此是有必定了解的。我先给出标准答案:
一、定义:即消费者组是 Kafka 提供的可扩展且具备容错性的消费者机制。
二、原理:在 Kafka 中,消费者组是一个由多个消费者实例 构成的组。多个实例共同订阅若干个主题,实现共同消费。同一个组下的每一个实例都配置有 相同的组 ID,被分配不一样的订阅分区。当某个实例挂掉的时候,其余实例会自动地承担起 它负责消费的分区。

此时,又有一个小技巧给到你:消费者组的题目,可以帮你在某种程度上掌控下面的面试方
向。

  • 若是你擅长位移值原理,就不妨再提一下消费者组的位移提交机制;
  • 若是你擅长 Kafka Broker,能够提一下消费者组与 Broker 之间的交互;
  • 若是你擅长与消费者组彻底不相关的 Producer,那么就能够这么说:“消费者组要消 费的数据彻底来自于 Producer 端生产的消息,我对 Producer 仍是比较熟悉的。”

问:三、在 Kafka 中,ZooKeeper 的做用是什么?

这是一道可以帮助你脱颖而出的题目。碰到这个题目,请在心中暗笑三声。

目前,Kafka 使用 ZooKeeper 存放集群元数据、成员管理、Controller 选举,以及其余一些管理类任务。以后,等 KIP-500 提案完成后,Kafka 将彻底再也不依赖 于 ZooKeeper。

记住,必定要突出“目前”,以彰显你很是了解社区的演进计划。“存放元数据”是指主题 分区的全部数据都保存在 ZooKeeper 中,且以它保存的数据为权威,其余“人”都要与它 保持对齐。“成员管理”是指 Broker 节点的注册、注销以及属性变动,等 等。“Controller 选举”是指选举集群 Controller,而其余管理类任务包括但不限于主题 删除、参数配置等。

不过,抛出 KIP-500 也多是个双刃剑。碰到很是资深的面试官,他可能会进一步追问你 KIP-500 是作的。一言以蔽之:KIP-500 思想,是使用社区自研的基于 Raft 的共识算法, 替代 ZooKeeper,实现 Controller 自选举

问:四、解释下 Kafka 中位移(offset)的做用

在 Kafka 中,每一个 主题分区下的每条消息都被赋予了一个惟一的 ID 数值,用于标识它在分区中的位置。这个 ID 数值,就被称为位移,或者叫偏移量。一旦消息被写入到分区日志,它的位移值将不能 被修改。

答完这些以后,你还能够把整个面试方向转移到你但愿的地方。常见方法有如下 3 种:

  1. 若是你深谙 Broker 底层日志写入的逻辑,能够强调下消息在日志中的存放格式;
  2. 若是你明白位移值一旦被肯定不能修改,能够强调下“Log Cleaner 组件都不能影响位 移值”这件事情;
  3. 若是你对消费者的概念还算熟悉,能够再详细说说位移值和消费者位移值之间的区别。

问:五、阐述下 Kafka 中的领导者副本(Leader Replica)和追随者副本 (Follower Replica)的区别

这道题表面上是考核你对 Leader 和 Follower 区别的理解,但很容易引伸到 Kafka 的同步 机制上。所以,我建议你主动出击,一次性地把隐含的考点也答出来,也许可以暂时把面试 官“唬住”,并体现你的专业性。

你能够这么回答:Kafka 副本当前分为领导者副本和追随者副本。只有 Leader 副本才能 对外提供读写服务,响应 Clients 端的请求。Follower 副本只是采用拉(PULL)的方 式,被动地同步 Leader 副本中的数据,而且在 Leader 副本所在的 Broker 宕机后,随时 准备应聘 Leader 副本。

一般来讲,回答到这个程度,其实才只说了 60%,所以,我建议你再回答两个额外的加分 项。

  • 强调 Follower 副本也能对外提供读服务。自 Kafka 2.4 版本开始,社区经过引入新的 Broker 端参数,容许 Follower 副本有限度地提供读服务。
  • 强调 Leader 和 Follower 的消息序列在实际场景中不一致。不少缘由均可能形成 Leader 和 Follower 保存的消息序列不一致,好比程序 Bug、网络问题等。这是很严重 的错误,必需要彻底规避。你能够补充下,以前确保一致性的主要手段是高水位机制, 但高水位值没法保证 Leader 连续变动场景下的数据一致性,所以,社区引入了 Leader Epoch 机制,来修复高水位值的弊端。关于“Leader Epoch 机制”,国内的资料不是 不少,它的普及度远不如高水位,不妨大胆地把这个概念秀出来,力求惊艳一把。

问:六、如何设置 Kafka 能接收的最大消息的大小?

这道题除了要回答消费者端的参数设置以外,必定要加上 Broker 端的设置,这样才算完整。毕竟,若是 Producer 都不能向 Broker 端发送数据很大的消息,又何来消费一说呢? 所以,你须要同时设置 Broker 端参数和 Consumer 端参数。

  • Broker 端参数:message.max.bytes、max.message.bytes(主题级别)和 replica.fetch.max.bytes。
  • Consumer 端参数:fetch.message.max.bytes。

Broker 端的最后一个参数比较容易遗漏。咱们必须调整 Follower 副本可以接收的最大消 息的大小,不然,副本同步就会失败。所以,把这个答出来的话,就是一个加分项。

问:七、监控 Kafka 的框架都有哪些?

面试官实际上是在 考察你对监控框架的了解广度,或者说,你是否知道不少能监控 Kafka 的框架或方法。下 面这些就是 Kafka 发展历程上比较有名气的监控系统。

  1. Kafka Manager:应该算是最有名的专属 Kafka 监控框架了,是独立的监控系统。
  2. Kafka Monitor:LinkedIn 开源的免费框架,支持对集群进行系统测试,并实时监控测
    试结果。
  3. CruiseControl:也是 LinkedIn 公司开源的监控框架,用于实时监测资源使用率,以及 提供经常使用运维操做等。无 UI 界面,只提供 REST API。
  4. JMX 监控:因为 Kafka 提供的监控指标都是基于 JMX 的,所以,市面上任何可以集成 JMX 的框架均可以使用,好比 Zabbix 和 Prometheus。
  5. 已有大数据平台本身的监控体系:像 Cloudera 提供的 CDH 这类大数据平台,自然就提 供 Kafka 监控方案。
  6. JMXTool:社区提供的命令行工具,可以实时监控 JMX 指标。答上这一条,属于绝对 的加分项,由于知道的人不多,并且会给人一种你对 Kafka 工具很是熟悉的感受。若是 你暂时不了解它的用法,能够在命令行以无参数方式执行一下kafka-run-class.sh kafka.tools.JmxTool,学习下它的用法。

问:八、Broker 的 Heap Size 如何设置?

如何设置 Heap Size 的问题,其实和 Kafka 关系不大,它是一类很是通用的面试题目。一 旦你应对不当,面试方向颇有可能被引到 JVM 和 GC 上去,那样的话,你被问住的概率就 会增大。所以,我建议你简单地介绍一下 Heap Size 的设置方法,并把重点放在 Kafka Broker 堆大小设置的最佳实践上。

好比,你能够这样回复:任何 Java 进程 JVM 堆大小的设置都须要仔细地进行考量和测 试。一个常见的作法是,以默认的初始 JVM 堆大小运行程序,当系统达到稳定状态后,手动触发一次 Full GC,而后经过 JVM 工具查看 GC 后的存活对象大小。以后,将堆大小设 置成存活对象总大小的 1.5~2 倍。对于 Kafka 而言,这个方法也是适用的。不过,业界有 个最佳实践,那就是将 Broker 的 Heap Size 固定为 6GB。通过不少公司的验证,这个大 小是足够且良好的。

问:九、如何估算 Kafka 集群的机器数量?

这道题目考查的是机器数量和所用资源之间的关联关系。所谓资源,也就是 CPU、内存、磁盘和带宽。

一般来讲,CPU 和内存资源的充足是比较容易保证的,所以,你须要从磁盘空间和带宽占用两个维度去评估机器数量。

在预估磁盘的占用时,你必定不要忘记计算副本同步的开销。若是一条消息占用 1KB 的磁 盘空间,那么,在有 3 个副本的主题中,你就须要 3KB 的总空间来保存这条消息。显式地 将这些考虑因素答出来,可以彰显你考虑问题的全面性,是一个可贵的加分项。

对于评估带宽来讲,常见的带宽有 1Gbps 和 10Gbps,但你要切记,这两个数字仅仅是最大值。所以,你最好和面试官确认一下给定的带宽是多少。而后,明确阐述出当带宽占用接 近总带宽的 90% 时,丢包情形就会发生。这样能显示出你的网络基本功。

问:十、Leader 老是 -1,怎么破?

在生产环境中,你必定碰到过“某个主题分区不能工做了”的情形。使用命令行查看状态的 话,会发现 Leader 是 -1,因而,你使用各类命令都无济于事,最后只能用“重启大 法”。

可是,有没有什么办法,能够不重启集群,就能解决此事呢?这就是此题的由来。

参考答案:删除 ZooKeeper 节点 /controller,触发 Controller 重选举。 Controller 重选举可以为全部主题分区重刷分区状态,能够有效解决因不一致致使的 Leader 不可用问题。我几乎能够判定,当面试官问出此题时,要么就是他真的不知道怎么 解决在向你寻求答案,要么他就是在等你说出这个答案。因此,千万别一上来就说“来个重 启”之类的话。

提升题

问:1.Kafka 的设计时什么样的呢?

Kafka 将消息以 topic 为单位进行概括

将向 Kafka topic 发布消息的程序成为 producers.

将预订 topics 并消费消息的程序成为 consumer.

Kafka 以集群的方式运行,能够由一个或多个服务组成,每一个服务叫作一个 broker.

producers 经过网络将消息发送到 Kafka 集群,集群向消费者提供消息

问:2.数据传输的事务定义有哪三种?

数据传输的事务定义一般有如下三种级别:

(1)最多一次: 消息不会被重复发送,最多被传输一次,但也有可能一次不传输

(2)最少一次: 消息不会被漏发送,最少被传输一次,但也有可能被重复传输.

(3)精确的一次(Exactly once): 不会漏传输也不会重复传输,每一个消息都传输被一次而

且仅仅被传输一次,这是你们所指望的

问:kafka事务。

分享一篇大佬讲kafka事务的博客,这一篇讲的更深刻:http://matt33.com/2018/11/04/kafka-transaction/

同时分享一下这两篇博文,感受这篇博文讲的更容易理解一些,面试我感受看这两篇就够了:https://www.jianshu.com/p/64c93065473e,https://www.cnblogs.com/middleware/p/9477133.html

Kafka从0.11版本开始引入了事务支持。事务能够保证Kafka在Exactly Once语义的基础上,生产和消费能够跨分区和会话,要么所有成功,要么所有失败。

1)Producer事务

为了实现跨分区跨会话的事务,须要引入一个全局惟一的Transaction ID,并将Producer得到的PID和Transaction ID绑定。这样当Producer重启后就能够经过正在进行的Transaction ID得到原来的PID。

为了管理Transaction,Kafka引入了一个新的组件Transaction Coordinator。Producer就是经过和Transaction Coordinator交互得到Transaction ID对应的任务状态。Transaction Coordinator还负责将事务全部写入Kafka的一个内部Topic,这样即便整个服务重启,因为事务状态获得保存,进行中的事务状态能够获得恢复,从而继续进行。

2)Consumer事务

上述事务机制主要是从Producer方面考虑,对于Consumer而言,事务的保证就会相对较弱,尤为时没法保证Commit的信息被精确消费。这是因为Consumer能够经过offset访问任意信息,并且不一样的Segment File生命周期不一样,同一事务的消息可能会出现重启后被删除的状况。

问:3.Kafka 判断一个节点是否还活着有那两个条件?

(1)节点必须能够维护和 ZooKeeper 的链接,Zookeeper 经过心跳机制检查每一个节点的连

(2)若是节点是个 follower,他必须能及时的同步 leader 的写操做,延时不能过久

问:4.producer 是否直接将数据发送到 broker 的 leader(主节点)?

producer 直接将数据发送到 broker 的 leader(主节点),不须要在多个节点进行分发,为了

帮助 producer 作到这点,全部的 Kafka 节点均可以及时的告知:哪些节点是活动的,目标

topic 目标分区的 leader 在哪。这样 producer 就能够直接将消息发送到目的地了

问:五、Kafa consumer 是否能够消费指定分区消息?

Kafa consumer 消费消息时,向 broker 发出"fetch"请求去消费特定分区的消息,consumer

指定消息在日志中的偏移量(offset),就能够消费从这个位置开始的消息,customer 拥有

了 offset 的控制权,能够向后回滚去从新消费以前的消息,这是颇有意义的

问:六、Kafka 消息是采用 Pull 模式,仍是 Push 模式?

Kafka 最初考虑的问题是,customer 应该从 brokes 拉取消息仍是 brokers 将消息推送到

consumer,也就是 pull 还 push。在这方面,Kafka 遵循了一种大部分消息系统共同的传统

的设计:producer 将消息推送到 broker,consumer 从 broker 拉取消息

一些消息系统好比 Scribe 和 Apache Flume 采用了 push 模式,将消息推送到下游的

consumer。

这样作有好处也有坏处:由 broker 决定消息推送的速率,对于不一样消费速率的

consumer 就不太好处理了。消息系统都致力于让 consumer 以最大的速率最快速的消费消

息,但不幸的是,push 模式下,当 broker 推送的速率远大于 consumer 消费的速率时,

consumer 恐怕就要崩溃了。

最终, Kafka 仍是选取了传统的 pull 模式。

Pull 模式的另一个好处是 consumer 能够自主决定是否批量的从 broker 拉取数据。Push

模式必须在不知道下游 consumer 消费能力和消费策略的状况下决定是当即推送每条消息还

是缓存以后批量推送。若是为了不 consumer 崩溃而采用较低的推送速率,将可能致使一

次只推送较少的消息而形成浪费。Pull 模式下,consumer 就能够根据本身的消费能力去决

定这些策略

Pull 有个缺点是,若是 broker 没有可供消费的消息,将致使 consumer 不断在循环中轮询,

直到新消息到 t 达。为了不这点,Kafka 有个参数可让 consumer 阻塞知道新消息到达

(固然也能够阻塞知道消息的数量达到某个特定的量这样就能够批量Pull)

问:7.Kafka 存储在硬盘上的消息格式是什么?

消息由一个固定长度的头部和可变长度的字节数组组成。头部包含了一个版本号和 CRC32

校验码。

消息长度: 4 bytes (value: 1+4+n)

版本号: 1 byte

CRC 校验码: 4 bytes

具体的消息: n bytes

问:8.Kafka 高效文件存储设计特色:

(1).Kafka 把 topic 中一个 parition 大文件分红多个小文件段,经过多个小文件段,就容易定

期清除或删除已经消费完文件,减小磁盘占用。

(2).经过索引信息能够快速定位 message 和肯定 response 的最大大小。

(3).经过 index 元数据所有映射到 memory,能够避免 segment file 的 IO 磁盘操做。

(4).经过索引文件稀疏存储,能够大幅下降 index 文件元数据占用空间大小。

问:9.Kafka 与传统消息系统之间有三个关键区别

(1).Kafka 持久化日志,这些日志能够被重复读取和无限期保留

(2).Kafka 是一个分布式系统:它以集群的方式运行,能够灵活伸缩,在内部经过复制数据

提高容错能力和高可用性

(3).Kafka 支持实时的流式处理

10.Kafka 建立 Topic 时如何将分区放置到不一样的 Broker 中

副本因子不能大于 Broker 的个数;

第一个分区(编号为 0)的第一个副本放置位置是随机从 brokerList 选择的;

其余分区的第一个副本放置位置相对于第 0 个分区依次日后移。也就是若是咱们有 5 个

Broker,5 个分区,假设第一个分区放在第四个 Broker 上,那么第二个分区将会放在第五

个 Broker 上;第三个分区将会放在第一个 Broker 上;第四个分区将会放在第二个

Broker 上,依次类推;

剩余的副本相对于第一个副本放置位置实际上是由 nextReplicaShift 决定的,而这个数也是

随机产生的

问:11.Kafka 新建的分区会在哪一个目录下建立

在启动 Kafka 集群以前,咱们须要配置好 log.dirs 参数,其值是 Kafka 数据的存放目录,

这个参数能够配置多个目录,目录之间使用逗号分隔,一般这些目录是分布在不一样的磁盘

上用于提升读写性能。

固然咱们也能够配置 log.dir 参数,含义同样。只须要设置其中一个便可。

若是 log.dirs 参数只配置了一个目录,那么分配到各个 Broker 上的分区确定只能在这个

目录下建立文件夹用于存放数据。

可是若是 log.dirs 参数配置了多个目录,那么 Kafka 会在哪一个文件夹中建立分区目录呢?

答案是:Kafka 会在含有分区目录最少的文件夹中建立新的分区目录,分区目录名为 Topic

名+分区 ID。注意,是分区文件夹总数最少的目录,而不是磁盘使用量最少的目录!也就

是说,若是你给 log.dirs 参数新增了一个新的磁盘,新的分区目录确定是先在这个新的磁

盘上建立直到这个新的磁盘目录拥有的分区目录不是最少为止。

问:12.partition 的数据如何保存到硬盘

topic 中的多个 partition 以文件夹的形式保存到 broker,每一个分区序号从 0 递增,

且消息有序

Partition 文件下有多个 segment(xxx.index,xxx.log)

segment 文件里的 大小和配置文件大小一致能够根据要求修改 默认为 1g

若是大小大于 1g 时,会滚动一个新的 segment 而且以上一个 segment 最后一条消息的偏移

量命名

问:13.kafka 的 ack 机制

request.required.acks 有三个值 0 1 -1

0:生产者不会等待 broker 的 ack,这个延迟最低可是存储的保证最弱当 server 挂掉的时候

就会丢数据

1:服务端会等待 ack 值 leader 副本确认接收到消息后发送 ack 可是若是 leader 挂掉后他

不确保是否复制完成新 leader 也会致使数据丢失

-1:一样在 1 的基础上 服务端会等全部的 follower 的副本受到数据后才会受到 leader 发出

的 ack,这样数据不会丢失

问:14.Kafka 的消费者如何消费数据

消费者每次消费数据的时候,消费者都会记录消费的物理偏移量(offset)的位置

等到下次消费时,他会接着上次位置继续消费

问:15.消费者负载均衡策略

一个消费者组中的一个分片对应一个消费者成员,他能保证每一个消费者成员都能访问,如

果组中成员太多会有空闲的成员

问:16.数据有序

一个消费者组里它的内部是有序的

消费者组与消费者组之间是无序的

问:17.kafaka 生产数据时数据的分组策略

生产者决定数据产生到集群的哪一个 partition 中

每一条消息都是以(key,value)格式

Key 是由生产者发送数据传入

因此生产者(key)决定了数据产生到集群的哪一个 partition

深度思考题

问:十一、LEO、LSO、AR、ISR、HW 都表示什么含义?

  • LEO:Log End Offset。日志末端位移值或末端偏移量,表示日志下一条待插入消息的 位移值。举个例子,若是日志有 10 条消息,位移值从 0 开始,那么,第 10 条消息的位 移值就是 9。此时,LEO = 10。
  • LSO:Log Stable Offset。这是 Kafka 事务的概念。若是你没有使用到事务,那么这个 值不存在(其实也不是不存在,只是设置成一个无心义的值)。该值控制了事务型消费 者可以看到的消息范围。它常常与 Log Start Offset,即日志起始位移值相混淆,由于 有些人将后者缩写成 LSO,这是不对的。在 Kafka 中,LSO 就是指代 Log Stable Offset。
  • AR:Assigned Replicas。AR 是主题被建立后,分区建立时被分配的副本集合,副本个 数由副本因子决定。
  • ISR:In-Sync Replicas。Kafka 中特别重要的概念,指代的是 AR 中那些与 Leader 保 持同步的副本集合。在 AR 中的副本可能不在 ISR 中,但 Leader 副本自然就包含在 ISR 中。关于 ISR,还有一个常见的面试题目是如何判断副本是否应该属于 ISR。目前的判断 依据是:Follower 副本的 LEO 落后 Leader LEO 的时间,是否超过了 Broker 端参数 replica.lag.time.max.ms 值。若是超过了,副本就会被从 ISR 中移除。
  • HW:高水位值(High watermark)。这是控制消费者可读取消息范围的重要字段。一 个普通消费者只能“看到”Leader 副本上介于 Log Start Offset 和 HW(不含)之间的 全部消息。水位以上的消息是对消费者不可见的。关于 HW,问法有不少,我能想到的 最高级的问法,就是让你完整地梳理下 Follower 副本拉取 Leader 副本、执行同步机制 的详细步骤。这就是咱们的第 20 道题的题目,一下子我会给出答案和解析。

问:十二、Kafka 能手动删除消息吗?

其实,Kafka 不须要用户手动删除消息。它自己提供了留存策略,可以自动删除过时消息。 固然,它是支持手动删除消息的。所以,你最好从这两个维度去回答。

  • 对于设置了 Key 且参数 cleanup.policy=compact 的主题而言,咱们能够构造一条 <Key,null> 的消息发送给 Broker,依靠 Log Cleaner 组件提供的功能删除掉该 Key 的消息。
  • 对于普通主题而言,咱们能够使用 kafka-delete-records 命令,或编写程序调用 Admin.deleteRecords 方法来删除消息。这两种方法异曲同工,底层都是调用 Admin 的 deleteRecords 方法,经过将分区 Log Start Offset 值抬高的方式间接删除消息。

问:1三、__consumer_offsets 是作什么用的?

这是一个内部主题,公开的官网资料不多涉及到。所以,我认为,此题属于面试官炫技一类 的题目。你要当心这里的考点:该主题有 3 个重要的知识点,你必定要所有答出来,才会显得对这块知识很是熟悉。

它是一个内部主题,无需手动干预,由 Kafka 自行管理。固然,咱们能够建立该主题。

它的主要做用是负责注册消费者以及保存位移值。可能你对保存位移值的功能很熟悉, 但其实该主题也是保存消费者元数据的地方。千万记得把这一点也回答上。另外,这里 的消费者泛指消费者组和独立消费者,而不只仅是消费者组。

Kafka 的 GroupCoordinator 组件提供对该主题完整的管理功能,包括该主题的建立、 写入、读取和 Leader 维护等。

问:1四、分区 Leader 选举策略有几种?

分区的 Leader 副本选举对用户是彻底透明的,它是由 Controller 独立完成的。你须要回答的是,在哪些场景下,须要执行分区 Leader 选举。每一种场景对应于一种选举策略。当前,Kafka 有 4 种分区 Leader 选举策略。

  • OfflinePartition Leader 选举:每当有分区上线时,就须要执行 Leader 选举。所谓的分区上线,多是建立了新分区,也多是以前的下线分区从新上线。这是最多见的分区 Leader 选举场景。
  • ReassignPartition Leader 选举:当你手动运行 kafka-reassign-partitions 命令,或者是调用 Admin 的 alterPartitionReassignments 方法执行分区副本重分配时,可能触发此类选举。假设原来的 AR 是[1,2,3],Leader 是 1,当执行副本重分配后,副本集 合 AR 被设置成[4,5,6],显然,Leader 必需要变动,此时会发生 Reassign Partition Leader 选举。
  • PreferredReplicaPartition Leader 选举:当你手动运行 kafka-preferred-replica- election 命令,或自动触发了 Preferred Leader 选举时,该类策略被激活。所谓的 Preferred Leader,指的是 AR 中的第一个副本。好比 AR 是[3,2,1],那么, Preferred Leader 就是 3。
  • ControlledShutdownPartition Leader 选举:当 Broker 正常关闭时,该 Broker 上 的全部 Leader 副本都会下线,所以,须要为受影响的分区执行相应的 Leader 选举。

这 4 类选举策略的大体思想是相似的,即从 AR 中挑选首个在 ISR 中的副本,做为新 Leader。固然,个别策略有些微小差别。不过,回答到这种程度,应该足以应付面试官 了。毕竟,微小差异对选举 Leader 这件事的影响很小。

问:Kafka中有那些地方须要选举?这些地方的选举策略又有哪些?

参考:http://www.javashuo.com/article/p-pkvcxbay-ra.html

控制器的选举

  • Kafka Controller的选举是依赖Zookeeper来实现的,在Kafka集群中哪一个broker可以成功建立/controller这个临时(EPHEMERAL)节点他就能够成为Kafka Controller。

分区leader的选举

消费者相关的选举

  • 组协调器GroupCoordinator须要为消费组内的消费者选举出一个消费组的leader,这个选举的算法也很简单,分两种状况分析。若是消费组内尚未leader,那么第一个加入消费组的消费者即为消费组的leader。若是某一时刻leader消费者因为某些缘由退出了消费组,那么会从新选举一个新的leader。

问:1五、Kafka 的哪些场景中使用了零拷贝(Zero Copy)?

Zero Copy 是特别容易被问到的高阶题目。在 Kafka 中,体现 Zero Copy 使用场景的地方有两处:基于 mmap 的索引和日志文件读写所用的 TransportLayer

先说第一个。索引都是基于 MappedByteBuffer 的,也就是让用户态和内核态共享内核态 的数据缓冲区,此时,数据不须要复制到用户态空间。不过,mmap 虽然避免了没必要要的 拷贝,但不必定就能保证很高的性能。在不一样的操做系统下,mmap 的建立和销毁成本可 能是不同的。很高的建立和销毁开销会抵消 Zero Copy 带来的性能优点。因为这种不确 定性,在 Kafka 中,只有索引应用了 mmap,最核心的日志并未使用 mmap 机制。

再说第二个。TransportLayer 是 Kafka 传输层的接口。它的某个实现类使用了 FileChannel 的 transferTo 方法。该方法底层使用 sendfile 实现了 Zero Copy。对 Kafka 而言,若是 I/O 通道使用普通的 PLAINTEXT,那么,Kafka 就能够利用 Zero Copy 特 性,直接将页缓存中的数据发送到网卡的 Buffer 中,避免中间的屡次拷贝。相反,若是 I/O 通道启用了 SSL,那么,Kafka 便没法利用 Zero Copy 特性了。

问:1六、Kafka 为何不支持读写分离?

这道题目考察的是你对 Leader/Follower 模型的思考。

Leader/Follower 模型并无规定 Follower 副本不能够对外提供读服务。不少框架都是允 许这么作的,只是 Kafka 最初为了不不一致性的问题,而采用了让 Leader 统一提供服 务的方式。

不过,在开始回答这道题时,你能够率先亮出观点:自 Kafka 2.4 以后,Kafka 提供了有限度的读写分离,也就是说,Follower 副本可以对外提供读服务

说完这些以后,你能够再给出以前的版本不支持读写分离的理由。

  • 场景不适用。读写分离适用于那种读负载很大,而写操做相对不频繁的场景,可 Kafka 不属于这样的场景。
  • 同步机制。Kafka 采用 PULL 方式实现 Follower 的同步,所以,Follower 与 Leader 存 在不一致性窗口。若是容许读 Follower 副本,就势必要处理消息滞后(Lagging)的问题。

问:1七、如何调优 Kafka?

回答任何调优问题的第一步,就是肯定优化目标,而且定量给出目标!这点特别重要。对于 Kafka 而言,常见的优化目标是吞吐量、延时、持久性和可用性。每个方向的优化思路都 是不一样的,甚至是相反的。

肯定了目标以后,还要明确优化的维度。有些调优属于通用的优化思路,好比对操做系统、 JVM 等的优化;有些则是有针对性的,好比要优化 Kafka 的 TPS。咱们须要从 3 个方向去考虑

  • Producer 端:增长 batch.size、linger.ms,启用压缩,关闭重试等。
  • Broker 端:增长 num.replica.fetchers,提高 Follower 同步 TPS,避免 Broker Full GC 等。
  • Consumer:增长 fetch.min.bytes 等

问:1八、Controller 发生网络分区(Network Partitioning)时,Kafka 会怎 么样?

这道题目可以诱发咱们对分布式系统设计、CAP 理论、一致性等多方面的思考。不过,针 对故障定位和分析的这类问题,我建议你首先言明“实用至上”的观点,即不论怎么进行理论分析,永远都要以实际结果为准。一旦发生 Controller 网络分区,那么,第一要务就是 查看集群是否出现“脑裂”,即同时出现两个甚至是多个 Controller 组件。这能够根据 Broker 端监控指标 ActiveControllerCount 来判断。

如今,咱们分析下,一旦出现这种状况,Kafka 会怎么样。

因为 Controller 会给 Broker 发送 3 类请求,即LeaderAndIsrRequest、 StopReplicaRequest 和 UpdateMetadataRequest,所以,一旦出现网络分区,这些请求将不能顺利到达 Broker 端。这将影响主题的建立、修改、删除操做的信息同步,表现为 集群仿佛僵住了同样,没法感知到后面的全部操做。所以,网络分区一般都是很是严重的问 题,要赶快修复。

问:1九、Java Consumer 为何采用单线程来获取消息?

在回答以前,若是先把这句话说出来,必定会加分:Java Consumer 是双线程的设计。一 个线程是用户主线程,负责获取消息;另外一个线程是心跳线程,负责向 Kafka 汇报消费者 存活状况。将心跳单独放入专属的线程,可以有效地规避因消息处理速度慢而被视为下线 的“假死”状况。

单线程获取消息的设计可以避免阻塞式的消息获取方式。单线程轮询方式容易实现异步非阻塞式,这样便于将消费者扩展成支持实时流处理的操做算子。由于不少实时流处理操做算子都不能是阻塞式的。另一个可能的好处是,能够简化代码的开发。多线程交互的代码是很是容易出错的。

问:20、简述 Follower 副本消息同步的完整流程

首先,Follower 发送 FETCH 请求给 Leader。接着,Leader 会读取底层日志文件中的消 息数据,再更新它内存中的 Follower 副本的 LEO 值,更新为 FETCH 请求中的 fetchOffset 值。最后,尝试更新分区高水位值。Follower 接收到 FETCH 响应以后,会把 消息写入到底层日志,接着更新 LEO 和 HW 值。

Leader 和 Follower 的 HW 值更新时机是不一样的,Follower 的 HW 更新永远落后于 Leader 的 HW。这种时间上的错配是形成各类不一致的缘由。

重点:kafka如何实现高吞吐?

问:一、简单说说:kafka如何实现高吞吐?

Kafka是分布式消息系统,须要处理海量的消息,Kafka的设计是把全部的消息都写入速度低容量大的硬盘,以此来换取更强的存储能力,但实际上,使用硬盘并无带来过多的性能损失。kafka主要使用了如下几个方式实现了超高的吞吐率:

    • 顺序读写;

    • 零拷贝

    • 文件分段

    • 批量发送

    • 数据压缩。

具体来讲:

读写文件依赖OS文件系统的页缓存,而不是在JVM内部缓存数据,利用OS来缓存,内存利用率高

sendfile技术(零拷贝),避免了传统网络IO四步流程

支持End-to-End的压缩

顺序IO以及常量时间get、put消息

Partition 能够很好的横向扩展和提供高并发处理

问:2 Kafka如何实现每秒上百万的超高并发写入?掌握好面试给你打满分

Kafka 是高吞吐低延迟的高并发、高性能的消息中间件,在大数据领域有极为普遍的运用。配置良好的 Kafka 集群甚至能够作到每秒几十万、上百万的超高并发写入。

页缓存技术 + 磁盘顺序写

首先 Kafka 每次接收到数据都会往磁盘上去写,以下图所示:

加粗样式

那么在这里咱们不由有一个疑问了,若是把数据基于磁盘来存储,频繁的往磁盘文件里写数据,这个性能会不会不好?你们确定都以为磁盘写性能是极差的。

没错,要是真的跟上面那个图那么简单的话,那确实这个性能是比较差的。

可是实际上 Kafka 在这里有极为优秀和出色的设计,就是为了保证数据写入性能,首先 Kafka 是基于操做系统的页缓存来实现文件写入的。

操做系统自己有一层缓存,叫作 Page Cache,是在内存里的缓存,咱们也能够称之为 OS Cache,意思就是操做系统本身管理的缓存。

你在写入磁盘文件的时候,能够直接写入这个 OS Cache 里,也就是仅仅写入内存中,接下来由操做系统本身决定何时把 OS Cache 里的数据真的刷入磁盘文件中。

仅仅这一个步骤,就能够将磁盘文件写性能提高不少了,由于其实这里至关因而在写内存,不是在写磁盘,你们看下图:

在这里插入图片描述

接着另一个就是 kafka 写数据的时候,很是关键的一点,它是以磁盘顺序写的方式来写的。

也就是说,仅仅将数据追加到文件的末尾,不是在文件的随机位置来修改数据。

普通的机械磁盘若是你要是随机写的话,确实性能极差,也就是随便找到文件的某个位置来写数据。

可是若是你是追加文件末尾按照顺序的方式来写数据的话,那么这种磁盘顺序写的性能基本上能够跟写内存的性能自己也是差很少的。

因此你们就知道了,上面那个图里,Kafka 在写数据的时候,一方面基于 OS 层面的 Page Cache 来写数据,因此性能很高,本质就是在写内存罢了。

另一个,它是采用磁盘顺序写的方式,因此即便数据刷入磁盘的时候,性能也是极高的,也跟写内存是差很少的。

基于上面两点,Kafka 就实现了写入数据的超高性能。那么你们想一想,假如说 Kafka 写入一条数据要耗费 1 毫秒的时间,那么是否是每秒就是能够写入 1000 条数据?

可是假如 Kafka 的性能极高,写入一条数据仅仅耗费 0.01 毫秒呢?那么每秒是否是就能够写入 10 万条数据?

因此要保证每秒写入几万甚至几十万条数据的核心点,就是尽最大可能提高每条数据写入的性能,这样就能够在单位时间内写入更多的数据量,提高吞吐量。

零拷贝技术

说完了写入这块,再来谈谈消费这块。

你们应该都知道,从 Kafka 里咱们常常要消费数据,那么消费的时候实际上就是要从 Kafka 的磁盘文件里读取某条数据而后发送给下游的消费者,以下图所示:

在这里插入图片描述

那么这里若是频繁的从磁盘读数据而后发给消费者,性能瓶颈在哪里呢?

假设要是 Kafka 什么优化都不作,就是很简单的从磁盘读数据发送给下游的消费者,那么大概过程以下所示:

先看看要读的数据在不在 OS Cache 里,若是不在的话就从磁盘文件里读取数据后放入 OS Cache。

接着从操做系统的 OS Cache 里拷贝数据到应用程序进程的缓存里,再从应用程序进程的缓存里拷贝数据到操做系统层面的 Socket 缓存里。

最后从 Socket 缓存里提取数据后发送到网卡,最后发送出去给下游消费。

整个过程,以下图所示:

在这里插入图片描述

你们看上图,很明显能够看到有两次不必的拷贝吧!一次是从操做系统的 Cache 里拷贝到应用进程的缓存里,接着又从应用程序缓存里拷贝回操做系统的 Socket 缓存里。

并且为了进行这两次拷贝,中间还发生了好几回上下文切换,一下子是应用程序在执行,一下子上下文切换到操做系统来执行。

因此这种方式来读取数据是比较消耗性能的。Kafka 为了解决这个问题,在读数据的时候是引入零拷贝技术。

也就是说,直接让操做系统的 Cache 中的数据发送到网卡后传输给下游的消费者,中间跳过了两次拷贝数据的步骤,Socket 缓存中仅仅会拷贝一个描述符过去,不会拷贝数据到 Socket 缓存。

你们看下图,体会一下这个精妙的过程:

在这里插入图片描述

经过零拷贝技术,就不须要把 OS Cache 里的数据拷贝到应用缓存,再从应用缓存拷贝到 Socket 缓存了,两次拷贝都省略了,因此叫作零拷贝。

对 Socket 缓存仅仅就是拷贝数据的描述符过去,而后数据就直接从 OS Cache 中发送到网卡上去了,这个过程大大的提高了数据消费时读取文件数据的性能。

并且你们会注意到,在从磁盘读数据的时候,会先看看 OS Cache 内存中是否有,若是有的话,其实读数据都是直接读内存的。

若是 Kafka 集群通过良好的调优,你们会发现大量的数据都是直接写入 OS Cache 中,而后读数据的时候也是从 OS Cache 中读。

至关因而 Kafka 彻底基于内存提供数据的写和读了,因此这个总体性能会极其的高。

RocketMQ

问:多个MQ如何选型?

RabbitMQ
erlang开发,对消息堆积的支持并很差,当大量消息积压的时候,会致使 RabbitMQ 的性能急剧降低。每秒钟能够处理几万到十几万条消息。

RocketMQ
java开发,面向互联网集群化,功能丰富,对在线业务的响应时延作了不少的优化,大多数状况下能够作到毫秒级的响应,每秒钟大概能处理几十万条消息。

Kafka
Scala开发,面向日志,功能丰富,性能最高。当你的业务场景中,每秒钟消息数量没有那么多的时候,Kafka 的时延反而会比较高。因此,Kafka 不太适合在线业务场景。

ActiveMQ
java开发,简单,稳定,性能不如前面三个。不推荐。

基础题

问:RocketMQ组成部分(角色)有哪些?

Nameserver
无状态,动态列表;这也是和zookeeper的重要区别之一。zookeeper是有状态的。

Producer
消息生产者,负责发消息到Broker。

Broker
就是MQ自己,负责收发消息、持久化消息等。

Consumer
消息消费者,负责从Broker上拉取消息进行消费,消费完进行ack。

问:RocketMQ消费模式有几种?

集群消费

  • 一条消息只会被同Group中的一个Consumer消费
  • 多个Group同时消费一个Topic时,每一个Group都会有一个Consumer消费到数据

广播消费

  • 消息将对一个Consumer Group 下的各个 Consumer 实例都消费一遍。即即便这些 Consumer 属于同一个Consumer Group ,消息也会被 Consumer Group 中的每一个 Consumer 都消费一次。

问:消息重复消费如何解决?

出现缘由
正常状况下在consumer真正消费完消息后应该发送ack,通知broker该消息已正常消费,从queue中剔除
当ack由于网络缘由没法发送到broker,broker会认为词条消息没有被消费,此后会开启消息重投机制把消息再次投递到consumer。

消费模式:在CLUSTERING模式下,消息在broker中会保证相同group的consumer消费一次,可是针对不一样group的consumer会推送屡次

解决方案

  • 数据库表:处理消息前,使用消息主键在表中带有约束的字段中insert
  • Map:单机时能够使用map作限制,消费时查询当前消息id是否是已经存在
  • Redis:使用分布式锁。

问:RocketMQ如何保证消息的顺序消费?

首先多个queue只能保证单个queue里的顺序,queue是典型的FIFO,自然顺序。多个queue同时消费是没法绝对保证消息的有序性的。
能够使用同一topic,同一个QUEUE,发消息的时候一个线程去发送消息,消费的时候 一个线程去消费一个queue里的消息。

问:RocketMQ如何保证消息不丢失?

Producer端

采起send()同步发消息,发送结果是同步感知的。
发送失败后能够重试,设置重试次数。默认3次。

Broker端
修改刷盘策略为同步刷盘。默认状况下是异步刷盘的。
集群部署

Consumer端
彻底消费正常后在进行手动ack确认

问:RocketMQ 由哪些角色组成?

生产者(Producer):负责产生消息,生产者向消息服务器发送由业务应用程序系统生成的消息。

消费者(Consumer):负责消费消息,消费者从消息服务器拉取信息并将其输入用户应用程序。

消息服务器(Broker):是消息存储中心,主要做用是接收来自 Producer 的消息并存储, Consumer 从这里取得消息。

名称服务器(NameServer):用来保存 Broker 相关 Topic 等元信息并给 Producer ,提供 Consumer 查找 Broker 信息。

问:RocketMQ执行流程

一、启动 Namesrv,Namesrv起 来后监听端口,等待 Broker、Producer、Consumer 连上来,至关于一个路由控制中心。

二、Broker 启动,跟全部的 Namesrv 保持长链接,定时发送心跳包。

三、收发消息前,先建立 Topic 。建立 Topic 时,须要指定该 Topic 要存储在 哪些 Broker上。也能够在发送消息时自动建立Topic。

四、Producer 发送消息。

五、Consumer 消费消息。

问:请说说你对 Producer 的了解?

一、得到 Topic-Broker 的映射关系。

Producer 启动时,也须要指定 Namesrv 的地址,从 Namesrv 集群中选一台创建长链接。

生产者每 30 秒从 Namesrv 获取 Topic 跟 Broker 的映射关系,更新到本地内存中。而后再跟 Topic 涉及的全部 Broker 创建长链接,每隔 30 秒发一次心跳。

二、生产者端的负载均衡。

生产者发送时,会自动轮询当前全部可发送的broker,一条消息发送成功,下次换另一个broker发送,以达到消息平均落到全部的broker上。

问:说说你对 Consumer 的了解?

一、得到 Topic-Broker 的映射关系。

Consumer 启动时须要指定 Namesrv 地址,与其中一个 Namesrv 创建长链接。消费者每隔 30 秒从 Namesrv 获取全部Topic 的最新队列状况,

Consumer 跟 Broker 是长链接,会每隔 30 秒发心跳信息到Broker .

二、消费者端的负载均衡。根据消费者的消费模式不一样,负载均衡方式也不一样。

问:消费者消费模式有几种?

消费者消费模式有两种:集群消费和广播消费。

  1. 集群消费

消费者的一种消费模式。一个 Consumer Group 中的各个 Consumer 实例分摊去消费消息,即一条消息只会投递到一个 Consumer Group 下面的一个实例。

  1. 广播消费

消费者的一种消费模式。消息将对一 个Consumer Group 下的各个 Consumer 实例都投递一遍。即即便这些 Consumer 属于同一个Consumer Group ,消息也会被 Consumer Group 中的每一个 Consumer 都消费一次。

问:消费者获取消息有几种模式?

消费者获取消息有两种模式:推送模式和拉取模式。

  1. PushConsumer

推送模式(虽然 RocketMQ 使用的是长轮询)的消费者。消息的能及时被消费。使用很是简单,内部已处理如线程池消费、流控、负载均衡、异常处理等等的各类场景。

  1. PullConsumer

拉取模式的消费者。应用主动控制拉取的时机,怎么拉取,怎么消费等。主动权更高。但要本身处理各类场景。

问:什么是定时消息?如何实现?

定时消息,是指消息发到 Broker 后,不能马上被 Consumer 消费,要到特定的时间点或者等待特定的时间后才能被消费。

提升题

问:RocketMQ如何实现分布式事务?

一、生产者向MQ服务器发送half消息。
二、half消息发送成功后,MQ服务器返回确认消息给生产者。
三、生产者开始执行本地事务。
四、根据本地事务执行的结果(UNKNOWcommitrollback)向MQ Server发送提交或回滚消息。
五、若是错过了(可能由于网络异常、生产者忽然宕机等致使的异常状况)提交/回滚消息,则MQ服务器将向同一组中的每一个生产者发送回查消息以获取事务状态。
六、回查生产者本地事物状态。
七、生产者根据本地事务状态发送提交/回滚消息。
八、MQ服务器将丢弃回滚的消息,但已提交(进行过二次确认的half消息)的消息将投递给消费者进行消费。

Half Message:预处理消息,当broker收到此类消息后,会存储到RMQ_SYS_TRANS_HALF_TOPIC的消息消费队列中

检查事务状态:Broker会开启一个定时任务,消费RMQ_SYS_TRANS_HALF_TOPIC队列中的消息,每次执行任务会向消息发送者确认事务执行状态(提交、回滚、未知),若是是未知,Broker会定时去回调在从新检查。

超时:若是超过回查次数,默认回滚消息。
也就是他并未真正进入Topic的queue,而是用了临时queue来放所谓的half message,等提交事务后才会真正的将half message转移到topic下的queue。

问:RocketMQ的消息堆积如何处理?

一、若是能够添加消费者解决,就添加消费者的数据量 二、若是出现了queue,可是消费者多的状况。能够使用准备一个临时的topic,同时建立一些queue,在临时建立一个消费者来把这些消息转移到topic中,让消费者消费。

相关文章
相关标签/搜索