Kafka面试题总结

2021年11月26日 阅读数:14
这篇文章主要向大家介绍Kafka面试题总结,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

一、Kafka 都有哪些特色?

高吞吐量、低延迟:kafka每秒能够处理几十万条消息,它的延迟最低只有几毫秒,每一个topic能够分多个partition, consumer group 对partition进行consume操做。
可扩展性:kafka集群支持热扩展
持久性、可靠性:消息被持久化到本地磁盘,而且支持数据备份防止数据丢失
容错性:容许集群中节点失败(若副本数量为n,则容许n-1个节点失败)
高并发:支持数千个客户端同时读写web

二、请简述下你在哪些场景下会选择 Kafka?

日志收集:一个公司能够用Kafka能够收集各类服务的log,经过kafka以统一接口服务的方式开放给各类consumer,例如hadoop、HBase、Solr等。
消息系统:解耦和生产者和消费者、缓存消息等。
用户活动跟踪:Kafka常常被用来记录web用户或者app用户的各类活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,而后订阅者经过订阅这些topic来作实时的监控分析,或者装载到hadoop、数据仓库中作离线分析和挖掘。
运营指标:Kafka也常常用来记录运营监控数据。包括收集各类分布式应用的数据,生产各类操做的集中反馈,好比报警和报告。
流式处理:好比spark streaming和 Flink缓存

三、Kafka 的设计架构?

简单架构以下:安全

Kafka简单架构

详细架构以下:服务器

Kafka详细架构

Kafka 架构分为如下几个部分:
Producer:消息生产者,就是向 kafka broker 发消息的客户端。
Consumer:消息消费者,向 kafka broker 取消息的客户端。
Topic:能够理解为一个队列,一个 Topic 又分为一个或多个分区。
Consumer Group:这是 kafka 用来实现一个 topic 消息的广播(发给全部的 consumer)和单播(发给任意一个 consumer)的手段。一个 topic 能够有多个 Consumer Group。
Broker:一台 kafka 服务器就是一个 broker。一个集群由多个 broker 组成。一个 broker 能够容纳多个 topic。
Partition:为了实现扩展性,一个很是大的 topic 能够分布到多个 broker上,每一个 partition 是一个有序的队列。partition 中的每条消息都会被分配一个有序的id(offset)。将消息发给 consumer,kafka 只保证按一个 partition 中的消息的顺序,不保证一个 topic 的总体(多个 partition 间)的顺序。
Offset:kafka 的存储文件都是按照 offset.kafka 来命名,用 offset 作名字的好处是方便查找。例如你想找位于 2049 的位置,只要找到 2048.kafka 的文件便可。固然 the first offset 就是 00000000000.kafka。网络

四、Kafka 分区的目的?

分区对于 Kafka 集群的好处是:实现负载均衡。分区对于消费者来讲,能够提升并发度,提升效率。架构

五、Kafka 是如何作到消息的有序性?

kafka 中的每一个 partition 中的消息在写入时都是有序的,并且单独一个 partition 只能由一个消费者去消费,能够在里面保证消息的顺序性。可是分区之间的消息是不保证有序的。并发

六、Kafka 的高可靠性是怎么实现的?

可回答:
Kafka 在什么状况下会出现消息丢失?

1)数据可靠性(可回答 怎么尽量保证 Kafka 的可靠性?)
Kafka 做为一个商业级消息中间件,消息可靠性的重要性可想而知。本文从 Producter 往 Broker 发送消息、Topic 分区副本以及 Leader 选举几个角度介绍数据的可靠性。
Topic分区副本
在 Kafka 0.8.0 以前,Kafka 是没有副本的概念的,那时候人们只会用 Kafka 存储一些不重要的数据,由于没有副本,数据极可能会丢失。可是随着业务的发展,支持副本的功能愈来愈强烈,因此为了保证数据的可靠性,Kafka 从 0.8.0 版本开始引入了分区副本(详情请参见 KAFKA-50)。也就是说每一个分区能够人为的配置几个副本(好比建立主题的时候指定 replication-factor,也能够在 Broker 级别进行配置 default.replication.factor),通常会设置为3。
Kafka 能够保证单个分区里的事件是有序的,分区能够在线(可用),也能够离线(不可用)。在众多的分区副本里面有一个副本是 Leader,其他的副本是 follower,全部的读写操做都是通过 Leader 进行的,同时 follower 会按期地去 leader 上的复制数据。当 Leader 挂了的时候,其中一个 follower 会从新成为新的 Leader。经过分区副本,引入了数据冗余,同时也提供了 Kafka 的数据可靠性。
Kafka 的分区多副本架构是 Kafka 可靠性保证的核心,把消息写入多个副本可使 Kafka 在发生崩溃时仍能保证消息的持久性
Producer 往 Broker 发送消息
若是咱们要往 Kafka 对应的主题发送消息,咱们须要经过 Producer 完成。前面咱们讲过 Kafka 主题对应了多个分区,每一个分区下面又对应了多个副本;为了让用户设置数据可靠性, Kafka 在 Producer 里面提供了消息确认机制。也就是说咱们能够经过配置来决定消息发送到对应分区的几个副本才算消息发送成功。能够在定义 Producer 时经过 acks 参数指定(在 0.8.2.X 版本以前是经过 request.required.acks 参数设置的)。
这个参数支持如下三种值:
acks = 0:意味着若是生产者可以经过网络把消息发送出去,那么就认为消息已成功写入Kafka。在这种状况下仍是有可能发生错误,好比发送的对象无能被序列化或者网卡发生故障,但若是是分区离线或整个集群长时间不可用,那就不会收到任何错误。在 acks=0 模式下的运行速度是很是快的(这就是为何不少基准测试都是基于这个模式),你能够获得惊人的吞吐量和带宽利用率,不过若是选择了这种模式, 必定会丢失一些消息。
acks = 1:意味若 Leader 在收到消息并把它写入到分区数据文件(不必定同步到磁盘上)时会返回确认或错误响应。在这个模式下,若是发生正常的 Leader 选举,生产者会在选举时收到一个 LeaderNotAvailableException 异常,若是生产者能恰当地处理这个错误,它会重试发送悄息,最终消息会安全到达新的 Leader 那里。不过在这个模式下仍然有可能丢失数据,好比消息已经成功写入 Leader,但在消息被复制到 follower 副本以前 Leader发生崩溃。
acks = all(这个和 request.required.acks = -1 含义同样):意味着 Leader 在返回确认或错误响应以前,会等待全部同步副本都收到悄息。若是和 min.insync.replicas 参数结合起来,就能够决定在返回确认前至少有多少个副本可以收到悄息,生产者会一直重试直到消息被成功提交。不过这也是最慢的作法,由于生产者在继续发送其余消息以前须要等待全部副本都收到当前的消息。
根据实际的应用场景,咱们设置不一样的 acks,以此保证数据的可靠性。
另外,Producer 发送消息还能够选择同步(默认,经过 producer.type=sync 配置) 或者异步(producer.type=async)模式。若是设置成异步,虽然会极大的提升消息发送的性能,可是这样会增长丢失数据的风险。若是须要确保消息的可靠性,必须将 producer.type 设置为 sync。
Leader 选举
在介绍 Leader 选举以前,让咱们先来了解一下 ISR(in-sync replicas)列表。每一个分区的 leader 会维护一个 ISR 列表,ISR 列表里面就是 follower 副本的 Borker 编号,只有跟得上 Leader 的 follower 副本才能加入到 ISR 里面,这个是经过 replica.lag.time.max.ms 参数配置的。只有 ISR 里的成员才有被选为 leader 的可能。
2)数据一致性(可回答 Kafka数据一致性原理?)
这里介绍的数据一致性主要是说不管是老的 Leader 仍是新选举的 Leader,Consumer 都能读到同样的数据。那么 Kafka 是如何实现的呢?app

数据一致性

假设分区的副本为3,其中副本0是 Leader,副本1和副本2是 follower,而且在 ISR 列表里面。虽然副本0已经写入了 Message4,可是 Consumer 只能读取到 Message2。由于全部的 ISR 都同步了 Message2,只有 High Water Mark 以上的消息才支持 Consumer 读取,而 High Water Mark 取决于 ISR 列表里面偏移量最小的分区,对应于上图的副本2,这个很相似于木桶原理。
这样作的缘由是尚未被足够多副本复制的消息被认为是“不安全”的,若是 Leader 发生崩溃,另外一个副本成为新 Leader,那么这些消息极可能丢失了。若是咱们容许消费者读取这些消息,可能就会破坏一致性。试想,一个消费者从当前 Leader(副本0) 读取并处理了 Message4,这个时候 Leader 挂掉了,选举了副本1为新的 Leader,这时候另外一个消费者再去重新的 Leader 读取消息,发现这个消息其实并不存在,这就致使了数据不一致性问题。
固然,引入了 High Water Mark 机制,会致使 Broker 间的消息复制由于某些缘由变慢,那么消息到达消费者的时间也会随之变长(由于咱们会先等待消息复制完毕)。延迟时间能够经过参数 replica.lag.time.max.ms 参数配置,它指定了副本在复制消息时可被容许的最大延迟时间。负载均衡

七、ISR、OSR、AR 是什么?

ISR:In-Sync Replicas 副本同步队列
OSR:Out-of-Sync Replicas
AR:Assigned Replicas 全部副本
ISR是由leader维护,follower从leader同步数据有一些延迟(具体能够参见 图文了解 Kafka 的副本复制机制),超过相应的阈值会把 follower 剔除出 ISR, 存入OSR(Out-of-Sync Replicas )列表,新加入的follower也会先存放在OSR中。AR=ISR+OSR。dom

八、LEO、HW、LSO、LW等分别表明什么?

LEO:是 LogEndOffset 的简称,表明当前日志文件中下一条
HW:水位或水印(watermark)一词,也可称为高水位(high watermark),一般被用在流式处理领域(好比Apache Flink、Apache Spark等),以表征元素或事件在基于时间层面上的进度。在Kafka中,水位的概念反而与时间无关,而是与位置信息相关。严格来讲,它表示的就是位置信息,即位移(offset)。取 partition 对应的 ISR中 最小的 LEO 做为 HW,consumer 最多只能消费到 HW 所在的位置上一条信息。
LSO:是 LastStableOffset 的简称,对未完成的事务而言,LSO 的值等于事务中第一条消息的位置(firstUnstableOffset),对已完成的事务而言,它的值同 HW 相同
LW:Low Watermark 低水位, 表明 AR 集合中最小的 logStartOffset 值。

九、数据传输的事务有几种?

数据传输的事务定义一般有如下三种级别:
最多一次:消息不会被重复发送,最多被传输一次,但也有可能一次不传输
最少一次:消息不会被漏发送,最少被传输一次,但也有可能被重复传输
精确的一次(Exactly once):不会漏传输也不会重复传输,每一个消息都传输被接收

十、Kafka 消费者是否能够消费指定分区消息?

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阻塞知道新消息到达(固然也能够阻塞知道消息的数量达到某个特定的量这样就能够批量发送)

十二、Kafka 高效文件存储设计特色?

1)Kafka把topic中一个parition大文件分红多个小文件段,经过多个小文件段,就容易按期清除或删除已经消费完文件,减小磁盘占用。
2)经过索引信息能够快速定位message和肯定response的最大大小。
3)经过index元数据所有映射到memory,能够避免segment file的IO磁盘操做。
4)经过索引文件稀疏存储,能够大幅下降index文件元数据占用空间大小。

1三、Kafka建立Topic时如何将分区放置到不一样的Broker中?

1)副本因子不能大于 Broker 的个数;
2)第一个分区(编号为0)的第一个副本放置位置是随机从 brokerList 选择的;
3)其余分区的第一个副本放置位置相对于第0个分区依次日后移。也就是若是咱们有5个 Broker,5个分区,假设第一个分区放在第四个 Broker 上,那么第二个分区将会放在第五个 Broker 上;第三个分区将会放在第一个 Broker 上;第四个分区将会放在第二个 Broker 上,依次类推;
4)剩余的副本相对于第一个副本放置位置实际上是由 nextReplicaShift 决定的,而这个数也是随机产生的;

1四、Kafka新建的分区会在哪一个目录下建立?

咱们知道,在启动 Kafka 集群以前,咱们须要配置好 log.dirs 参数,其值是 Kafka 数据的存放目录,这个参数能够配置多个目录,目录之间使用逗号分隔,一般这些目录是分布在不一样的磁盘上用于提升读写性能。固然咱们也能够配置 log.dir 参数,含义同样。只须要设置其中一个便可。
若是 log.dirs 参数只配置了一个目录,那么分配到各个 Broker 上的分区确定只能在这个目录下建立文件夹用于存放数据。
可是若是 log.dirs 参数配置了多个目录,那么 Kafka 会在哪一个文件夹中建立分区目录呢?答案是:Kafka 会在含有分区目录最少的文件夹中建立新的分区目录,分区目录名为 Topic名+分区ID。注意,是分区文件夹总数最少的目录,而不是磁盘使用量最少的目录!也就是说,若是你给 log.dirs 参数新增了一个新的磁盘,新的分区目录确定是先在这个新的磁盘上建立直到这个新的磁盘目录拥有的分区目录不是最少为止。

1五、谈一谈 Kafka 的再均衡

在Kafka中,当有新消费者加入或者订阅的topic数发生变化时,会触发Rebalance(再均衡:在同一个消费者组当中,分区的全部权从一个消费者转移到另一个消费者)机制,Rebalance顾名思义就是从新均衡消费者消费。Rebalance的过程以下:
第一步:全部成员都向coordinator发送请求,请求入组。一旦全部成员都发送了请求,coordinator会从中选择一个consumer担任leader的角色,并把组成员信息以及订阅信息发给leader。
第二步:leader开始分配消费方案,指明具体哪一个consumer负责消费哪些topic的哪些partition。一旦完成分配,leader会将这个方案发给coordinator。coordinator接收到分配方案以后会把方案发给各个consumer,这样组内的全部成员就都知道本身应该消费哪些分区了。
因此对于Rebalance来讲,Coordinator起着相当重要的做用。

1六、Kafka分区分配策略

Kafka分区分配策略

在 Kafka 内部存在两种默认的分区分配策略:Range 和 RoundRobin。当如下事件发生时,Kafka 将会进行一次分区分配:
1)同一个 Consumer Group 内新增消费者
2)消费者离开当前所属的Consumer Group,包括shuts down 或 crashes
3)订阅的主题新增分区
将分区的全部权从一个消费者移到另外一个消费者称为从新平衡(rebalance),如何rebalance就涉及到下面提到的分区分配策略。下面咱们将详细介绍 Kafka 内置的两种分区分配策略。本文假设咱们有个名为 T1 的主题,其包含了10个分区,而后咱们有两个消费者(C1,C2)来消费这10个分区里面的数据,并且 C1 的 num.streams = 1,C2 的 num.streams = 2。
Range strategy
Range策略是对每一个主题而言的,首先对同一个主题里面的分区按照序号进行排序,并对消费者按照字母顺序进行排序。在咱们的例子里面,排完序的分区将会是0, 1, 2, 3, 4, 5, 6, 7, 8, 9;消费者线程排完序将会是C1-0, C2-0, C2-1。而后将partitions的个数除于消费者线程的总数来决定每一个消费者线程消费几个分区。若是除不尽,那么前面几个消费者线程将会多消费一个分区。
在咱们的例子里面,咱们有10个分区,3个消费者线程,10 / 3 = 3,并且除不尽,那么消费者线程 C1-0 将会多消费一个分区,因此最后分区分配的结果看起来是这样的:
C1-0 将消费 0, 1, 2, 3 分区
C2-0 将消费 4, 5, 6 分区
C2-1 将消费 7, 8, 9 分区
假如咱们有11个分区,那么最后分区分配的结果看起来是这样的:
C1-0 将消费 0, 1, 2, 3 分区
C2-0 将消费 4, 5, 6, 7 分区
C2-1 将消费 8, 9, 10 分区
假如咱们有2个主题(T1和T2),分别有10个分区,那么最后分区分配的结果看起来是这样的:
C1-0 将消费 T1主题的 0, 1, 2, 3 分区以及 T2主题的 0, 1, 2, 3分区
C2-0 将消费 T1主题的 4, 5, 6 分区以及 T2主题的 4, 5, 6分区
C2-1 将消费 T1主题的 7, 8, 9 分区以及 T2主题的 7, 8, 9分区
能够看出,C1-0 消费者线程比其余消费者线程多消费了2个分区,这就是Range strategy的一个很明显的弊端。
RoundRobin strategy
使用RoundRobin策略有两个前提条件必须知足:
同一个Consumer Group里面的全部消费者的num.streams必须相等;
每一个消费者订阅的主题必须相同。
因此这里假设前面提到的2个消费者的num.streams = 2。RoundRobin策略的工做原理:将全部主题的分区组成 TopicAndPartition 列表,而后对 TopicAndPartition 列表按照 hashCode 进行排序,这里文字可能说不清,看下面的代码应该会明白:

val allTopicPartitions = ctx.partitionsForTopic.flatMap { case(topic, partitions) =>
  info("Consumer %s rebalancing the following partitions for topic %s: %s"
       .format(ctx.consumerId, topic, partitions))
  partitions.map(partition => {
   TopicAndPartition(topic, partition)
  })
}.toSeq.sortWith((topicPartition1, topicPartition2) => {
  /*
   * Randomize the order by taking the hashcode to reduce the likelihood of all partitions of a given topic ending
   * up on one consumer (if it has a high enough stream count).
   */
  topicPartition1.toString.hashCode < topicPartition2.toString.hashCode
})

最后按照round-robin风格将分区分别分配给不一样的消费者线程。
在咱们的例子里面,假如按照 hashCode 排序完的topic-partitions组依次为T1-5, T1-3, T1-0, T1-8, T1-2, T1-1, T1-4, T1-7, T1-6, T1-9,咱们的消费者线程排序为C1-0, C1-1, C2-0, C2-1,最后分区分配的结果为:
C1-0 将消费 T1-5, T1-2, T1-6 分区;
C1-1 将消费 T1-3, T1-1, T1-9 分区;
C2-0 将消费 T1-0, T1-4 分区;
C2-1 将消费 T1-8, T1-7 分区。
多个主题的分区分配和单个主题相似。

1七、Kafka 是如何实现高吞吐率的?

Kafka是分布式消息系统,须要处理海量的消息,Kafka的设计是把全部的消息都写入速度低容量大的硬盘,以此来换取更强的存储能力,但实际上,使用硬盘并无带来过多的性能损失。kafka主要使用了如下几个方式实现了超高的吞吐率:
1)顺序读写
2)零拷贝
3)文件分段
4)批量发送
5)数据压缩

1八、Kafka 缺点?

1)因为是批量发送,数据并不是真正的实时;
2)对于mqtt协议不支持;
3)不支持物联网传感数据直接接入;
4)仅支持统一分区内消息有序,没法实现全局消息有序;
5)监控不完善,须要安装插件;
6)依赖zookeeper进行元数据管理。

1九、Kafka 新旧消费者的区别?

旧的 Kafka 消费者 API 主要包括:SimpleConsumer(简单消费者) 和 ZookeeperConsumerConnectir(高级消费者)。SimpleConsumer 名字看起来是简单消费者,可是其实用起来很不简单,可使用它从特定的分区和偏移量开始读取消息。高级消费者和如今新的消费者有点像,有消费者群组,有分区再均衡,不过它使用 ZK 来管理消费者群组,并不具有偏移量和再均衡的可操控性。
如今的消费者同时支持以上两种行为,因此为啥还用旧消费者 API 呢?

20、Kafka 分区数能够增长或减小吗?为何?

咱们可使用 bin/kafka-topics.sh 命令对 Kafka 增长 Kafka 的分区数据,可是 Kafka 不支持减小分区数。 Kafka 分区数据不支持减小是由不少缘由的,好比减小的分区其数据放到哪里去?是删除,仍是保留?删除的话,那么这些没消费的消息不就丢了。若是保留这些消息如何放到其余分区里面?追加到其余分区后面的话那么就破坏了 Kafka 单个分区的有序性。若是要保证删除分区数据插入到其余分区保证有序性,那么实现起来逻辑就会很是复杂。

猜你喜欢

Hive计算最大连续登录天数
Hadoop 数据迁移用法详解
Hbase修复工具Hbck
数仓建模分层理论
一文搞懂Hive的数据存储与压缩
大数据组件重点学习这几个