Kafka

Kafka 需要理解掌握其基本概念,生产者,消费者,broker,分区,消费者组,offset,ack机制,ISR等。面试常问!

1. *Kafka和传统消息队列有何区别?

首先Kafka会将接收到的消息分区(partition),每个主题(topic)的消息有不同的分区,这样一方面消息的存储就不会受到单一服务器存储空间大小的限制,另一方面消息的处理也可以在多个服务器上并行。
其次为了保证高可用,每个分区都会有一定数量的副本(replica)。这样如果有部分服务器不可用,副本所在的服务器就会接替上来,保证应用的持续性。
另外Kafka保证分区内部消息有序性。
Kafka还具有 consumer group 的概念,每个分区只能被同一个group的一个consumer消费,但可以被多个group消费。
和 RabbitMQ进行对比:

  1. 架构模型方面
    RabbitMQ 遵循 AMQP 协议,RabbitMQ 的 brokerExchange,Binding,queue 组成,其中exchange 和 binding 组成了消息的路由器;客户端Producer 通过连接channel 和 server 进行通信,Consumer 从queue获取消息进行消费(长连接,queue有消息会推送到consumer端,consumer 循环从输入流读取数据)。rabbitMQ 以 broker 为中心;有消息的确认机制。
    Kafka遵从一般的MQ结构,producer,broker,consumer,以consumer为中心,消息的消费信息保存的客户端consumer上,consumer根据消费的点,从broker上批量pull数据;无消息确认机制。
  2. 吞吐量
    Kafka具有高的吞吐量,内部采用消息的批量处理,zero-copy机制,数据的存储和获取是本地磁盘顺序批量操作,具有O(1)的复杂度,消息处理的效率很高。
    rabbitMQ在吞吐量方面稍逊于Kafka,他们的出发点不一样,rabbitMQ支持对消息的可靠的传递,支持事务,不支持批量的操作;基于存储的可靠性的要求存储可以采用内存或者硬盘。
  3. 可用性
    rabbitMQ 支持mirror的queue,主queue失效,miror queue接管。
    Kafka的broker支持主备模式。
  4. 集群负载均衡
    Kafka采用zookeeper对集群中的broker,consumer进行管理,可用注册topic到zookeeper上;通过zookeeper的协调机制,producer保存对应topic的broker信息,可以随机或者轮询发送到broker上;并且producer可以基本语义指定分片,消息发送到broker的某分片上。
技巧

需要能够回答出Kafka的一些特点,可用在回答的时候,和RabbitMQ进行对比进行说明。可以从架构模型,吞吐量,可用性等几个方面进行回答。

2. Kafka的应用场景?

Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。简单来说,Kafka就相比是一个邮箱,生产者是发送邮件的人,消费者是接收邮件的人,Kafka就是用来存东西的,只不过它提供了一些处理邮件的机制。使用场景包括:

  • 日志收集:一个公司可以用Kafka可用收集各种服务的log,通过Kafka以统一接口服务的方式开始给各种consumer。
  • 消息系统:解耦生产者和消费者,缓存消息等。
  • 用户活动根踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页,搜索,点击等活动,这些活动信息被各个服务器发布到Kafka的topic中。然后消费者通过订阅这些topic来做实时的监控分析,亦可保存到数据库。
  • 运营指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。
  • 流式处理:比如SparkStreaming和storm。
技巧

考察Kafka的使用场景。了解即可。

3. *Kafka在高并发的情况下,如何避免消息丢失和消息重复?

1.消息丢失解决方案
  1. 对Kafka进行限速
  2. 启动重试机制,重试间隔时间设置长一点。
  3. Kafka设置 acks=all,即需要相应的所有处于ISR的分区都确认收到该消息后,才算发送成功。
2.消息重复解决方案
  1. 消息可以使用唯一id标识。
  2. 生产者(ask=all代表至少成功发送一次)。
  3. 消费者(offset手动提交,业务逻辑成功处理后,提交offset)。
  4. 落表(主键或者唯一索引的方式,避免重复数据)。
    业务逻辑处理(选择唯一主键存储到Redis或者mongdb中,先查询是否存在,若存在则不处理;若不存在,先插入Redis或者mongdb,再进行业务逻辑处理)。
技巧

考察高并发情况下,如何避免消息丢失和消息重复。需要能够回答出上文中加粗的点。

Kafka到SparkStreaming怎么保证数据完整性,怎么保证数据不重复消费?

保证数据不丢失(at-least):

  • Spark RDD内部机制可以保证数据at-least语义。
  • Receiver方式。开启WAL(预写日志),将从Kafka中接受到的数据写入到日志文件中,所有数据从失败中可恢复。
    Direct 方式:
  1. 依靠checkpoint机制来保证。
  2. 要保证数据不重复,即Exactly once语义。
  • 幂等操作:重复执行不会产生问题,不需要做额外的工作即可保证数据不重复。
  • 业务代码添加事务操作。就是说针对每个partition的数据,产生一个uniqueld,只有这个partition的所有数据被完全消费,则算成功,否则算失效,要回滚。下次重复执行这个uniqueld时,如果已经被执行成功,则skip掉。
技巧

面试重点。保证消费Kafka数据丢失,可以回答使用Direct方式,然后回答出checkpoint机制,手动维护offset。

5. *Kafka的消费者高阶和低阶API有什么区别

Kafka提供了两套consumer APIThe high-level Consumer APIThe SimpleConsumer API,其中 high-level consumer API 提供了一个从 Kafka消费数据的高层抽象,而 SimpleConsumer API 则需要开发人员更多地关注细节。

1.The high-level Consumer API

high-level consumer API 提供了 consumer group 的语义,一个消息只能被group内的一个consumer所消费,且 consumer消费消息时不关注offset,最后一个offset由zookeeper保存。
使用 high-level Consumer API 可以是多线程的应用,应当注意:

  1. 如果消费线程大于 partition 数量,则有些线程将收不到消息。
  2. 如果partition数量大于线程数,则有些线程会收到多个partition的消息。
  3. 如果一个线程消费多个 partition,则无法保证收到的消息的顺序,而一个 partition内的消息是有序的。
2.The SimpleConsumer API

如果你相要对 partition 有更多的控制权,那就应该使用 SimpleConsumer API,比如:

  1. 多次读取一个消息。
  2. 只消费一个partition中的部分消息。
  3. 使用事务来保证一个消息仅被消费一次。
    但是使用此API 时,partition,offset,broker,leader 等对你不再透明,需要自己去管理。需要做大量的额外工作:
  • 必须在应用程序中跟踪offset,从而确定下一条应该消费哪条消息。
  • 应用程序需要通过程序获知每个 Partition的leader是谁。
  • 需要处理leader的变更。
技巧

重点需要回答出SimpleConsumer API相对于 high-level Consumer API,offset需要手动维护。

6. Kafka怎么保证数据消费一次仅且消费一次

  • 幂等producer:保证发送单个分区的消息只会发送一次,不会出现重复消息。
  • 事务(transaction):保证原子性地写入到多个分区,即写入到多个分区的消息要么全部成功,要么全部回滚。
技巧

回答关键点:producer 的幂等性,事务。

7. Kafka保证数据一致性和可靠性

1.数据一致性保证

一致性定义:若某条消息对client可见,那么即使Leader挂掉了,在新的leader上数据依然可以被读到。
HW-HightWaterMark:client可以从Leader读到最大msg offset,即对外可见的最大offset,HW=max(replica.offset)。
对于Leader新收到的msg,client不能立刻消费,Leader会等待该消息被所有ISR中的replica同步后,更新HW,此刻该消息才能被client消费,这样就保证了如果 Leader fail,该消息仍然可以从新选举的Leader中获取。
对于来自内部 Broker 的读取请求,没有 HW 的限制。同时,Follower 也会维护一份自己的HW,Folloer.HW=min(Leader.HW,Follower.offset)。

2.数据可靠性保证

当 Producer 向 Leader 发送数据时,可以通过acks参数设置数据可靠性的级别。

  • 0:不论写入是否成功,server 不需要给 Producer 发送 Response,如果发生异常,server 会终止连接,触发 Producer 更新 meta数据;
  • 1:Leader写入成功后即发送Response,此种情况如果发生 Leader fail,会丢失数据;
  • -1:等待所有ISR接收到消息后再给Producer 发送 Response,这是最强保证。
技巧

考察Kafka数据一致性是如何保证的。偏底层。

8. Spark实时作业宕掉,Kafka指定的topic数据堆积怎么办?

应对措施:

  1. spark.streaming.concurrentJobs=10:提高Job并发数,从源码中可以察觉到,这个参数其实是指定了一个线程池的核心线程数而已,没有指定时,默认为1。
  2. spark.streaming.kafka.maxRatePerPartition=2000:设置每秒每个分区最大获取日志数,控制处理数据量,保证数据均匀处理。
  3. spark.streaming.kafka.maxRetries=50:获取topic分区Leaders及其最新offsets时,调大重试次数。
  4. 在应用级别配置重试。spark.yarn.maxAppAttempts=5。
  5. 尝试失败有效间隔时间设置。spark.yarn.am.attemptFailuresValidityInterval=1h
注意

spark.yarn.maxAppAttempts 值不能超过 Hadoop 集群中 yarn.resourcemanager.am.max-attempts。

技巧

考察 Kafka topic 数据堆积的处理方法。需要回答出几种有效的解决方法。比如提高并发,提高每个分区最大处理数据量,增加重试次数等。

9. *Kafka的acks

  1. acks=0 意味着生产者能够通过网络把消息发送出去,那么就认为消息已成功写入Kafka,一定会丢失一些数据。
  2. acks=1 意味着首领在疏导消息并把它写到分区数据问津是会返回确认或者错误响应,还是可能会丢数据。
  3. acks=all 意味着首领在返回确认或错误响应之前,会等待所有同步副本都收到消息。如果和min.insync.replicas 参数结合起来,就可以决定在返回确认前至少有多个副本能够收到消息。但是效率较低。可以通过一部模式和更大的批次来加快速度,但这样做会降低吞吐量。
技巧

考察 acks 的三种设置方式分布表示的含义。重点问题,经常会被考察。需要能够分别回答出相应的含义。
另外,这种问题一般通过怎么控制Kafka数据不丢失这种方式来问,以及自己在工作中怎么设置acks等。结合消息的准确性和吞吐量,综合考虑,来决定实际是设置为1还是设置为all。

10. Kafka 的读写流程?

1.写流程
  1. 连接ZK集群,从ZK中拿到对应topic的partition信息和partition的Leader的相关。
  2. 连接到对应Leader对应的broker。
  3. 将消息发送到partition的Leader上。
  4. 其他Follower从Leader上复制数据。
  5. 依次返回ACK。
  6. 直到所有ISR中的数据写完成,才完成提交,整个写过程结束。因为是描述写流程,没有将replica与zk的心跳通讯表达出来,心跳通讯就是为了保证Kafka高可用。一旦Leader挂了,或者Follower同步超时或者同步过慢,都会通过心跳将信息报告给zk,由zk做Leader选举或者将Follower从ISR中移动到OSR中。
2.读流程
  1. 连接zk集群,从ZK中拿到对应于topic的partition信息和partition的Leader的相关。
  2. 连接到对应Leader对应对应的broker。
  3. consumer将自己保存的offset发送给Leader。
  4. Leader根据offset等信息定位到segment(索引文件和日志文件)。
  5. 根据索引文件中的内容,定位到日志文件中该偏移量对应的开始位置读取相应长度的数据并返回给consumer。
技巧

需要能够回答出Kafka读写数据的流程。

11. Kafka为什么只让Leader进行读写?

Kafka只有Leader负责读写,follower只负责备份,如果Leader宕机的话,Kafka动态维护了一个同步状态的副本的集合(a set of in-sync replicas),简称ISR,ISR中有f+1个节点,就可以允许在f个节点down掉的情况下不会丢失消息并正常提供服务。ISR的成员是动态的,如果一个节点被淘汰了,当它重新达到“同步中”的状态时,他可以重新加入ISR。因此如果Leader宕机了,直接从ISR中选择一个follower就行。
Kafka在引入Replication之后,同一个Partition可能会有多个Replica,而这时需要在这些Replication之间选出一个Leader,Producer和Consumer只与这个Leader交互,其它Replica作为Follower从Leader中复制数据。因为需要保证同一个Partiton的多个Replica之间的数据一致性(其中一个宕机后其它Replica必须要能继续服务并且即不能造成数据重复也不能造成数据丢失)。如果没有一个Leader,所有Replica都可同时读/写数据,那就需要保证多个Replica之间互相(N X N条通路)同步数据,数据的一致性和有序性非常难保证,大大增加了Replication实现的复杂性,同时也增加了出现异常的几率。而引入Leader后,只有Leader负责数据读写,Follower只向Leader顺序Fetch数据(N条通路),系统更加简单且高效。

技巧

考察Kafka为什么只让Leader读写,重点回答出数据一致性。其次对相关内容展开进行分析回答。

12. 为了避免磁盘被沾满,Kafka会周期性的删除旧消息,请问删除策略有哪些?分别是什么?控制粒度到什么程度?请具体描述一下。

Kafka中有两种“保留策略”:
一种是根据消息保留的时间,当消息在Kafka中保留的时间超过了指定时间,就可以被删除。
另一种是根据Topic存储的数据大小,当Topic所占的日志文件大小大于一个阀值,则可以开始删除最旧的消息。
Kafka会启动一个后台线程,定期检查是否存在可以删除的消息。
“保留策略”的配置是非常灵活的,可以有全局的配置,也可以针对Topic进行配置覆盖全局配置。

技巧

考察删除策略。需要回答出两种保留策略,自己在项目中使用的是哪一条。

13. *简要描述Kafka数据高可用的原理是什么?

1.数据存储格式

Kafka的高可靠性的保障来源于其健壮的副本(replication)策略。一个Topic可以分成多个Partitin,而一个Partition物理上由多个Segment组成。
Segment分2部分:索引文件和数据文件。索引文件保存元数据,记录了消息在数据文件中的偏移(offset),消息有固定物理结构,保证了正确的读取长度。
Segment文件带来好处:方便过期文件清理。只需要整体删除过期的Segment。以追加的方式写消息,顺序写磁盘极大提高了效率。
读取某offset消息的步骤变为:通过二分查找,找到offset所在Segment。通过Segment的索引文件,找到offset所在数据文件的物理偏移。读取数据。

2.副本复制与同步

从外部来看Partition类似一个不断增长,存储消息的数组,每个Partition有一个类似MySQL binlog的文件用来记录数据的写入。有两个新名词,HW(HighWatermark)表示当前Consumer可以看到Partiton的offset位置,LEO(LogEndOffset) 表示当前Partition最新消息的offset,各个副本单独维护。为了提高消息可靠性,Partition有N个副本。
N个副本中,有一个Leader,余下N-1个Follower。Kafka的写操作只在Leader副本上进行。通常这种副本写有两种方式:

  1. Leader写日志文件成功即返回成功。这样如果Folloer在同步完数据前Leader宕机,数据丢失。这种方式带来较高效率。
  2. Leader等待Follower写日志成功并收到返回的acks后,才返回成功。这样Leader宕机,重新选举的Leader与宕机Leader数据一致,数据不丢失。但因为要等待Follow返回,效率较慢。一般采用少数服从多数的选举方式,如果要应对f个副本宕机,则至少需要2f+1个副本并使中的f+1个写成功。Kafka没有使用上述机制。它实现了ISR(In-Sync Replication)的机制。
技巧

考察Kafka数据高可用。

14. *Kafka的偏移量offset存放在哪儿,为什么?

从Kafka-0.9版本及以后,Kafka的消费者组和offset信息就不存在zookeeper了,而是存到broker服务器上,所以,如果你为某个消费者指定了一个消费者组名称(group.id),那么,一旦这个消费者启动,这个消费者组名和它要消费的那个topic的offset信息就会被记录在broker服务器上。

1.概述

Kafka版本 [0.10.1.1],已默认将消费的offset迁入到了Kafka一个名为 _consumer_offsets 的Topic中。其实,早在 0.8.2.2版本,已支持存入消费的offset到Topic中,只是那时候默认是将消费的offset存放在Zookeeper集群中。那现在,官方默认将消费的offset存储在Kafka的Topic中,同时,也保留了存储在Zookeeper的接口,通过offsets.storage属性来进行设置。

2.内容

其实,官方这样推荐,也是有其道理的。之前版本,Kafka其实存在一个比较大的隐患,就是利用Zookeeper来存储记录每个消费者/组的消费进度。虽然,在使用过程当中,JVM帮距我们完成了一些优化,但是消费者需要频繁的去与Zookeeper进行交互,而利用ZKClient的API操作Zookeeper频繁的Write其本身就是一个比较低效的Action,对于后期水平扩展也是一个比较头疼的问题。如果期间Zookeeper集群发生变化,那Kafka集群的吞吐量也跟着受影响。在此之后,官方其实很早就提出了迁移到Kafka的概念,只是,之前是一直默认存储在Zookeeper集群中,需要手动的设置,如果,对Kafka的使用不是很熟悉的话,一般我们就接受了默认的存储(即:存在ZK中)。在新版Kafka以及之后的版本,Kafka消费的offset都会默认存放在Kafka集群中的一个叫 _consumer_offsets的topic中。

技巧

考察对Kafka offset 的理解。需能够回答出新版本是默认将消费的 offset 迁入到了 Kafka 一个名为 _consumer_offsets 的 Topic 中。

15. *如何保证Kafka的消息有序

Kafka只能保证一个partition中的消息被某个consumer消费时是顺序的,事实上,从Topic角度来说,当有多个partition时,消息仍然不是全局有序的。

技巧

需要能够回答出Kafka消息分区内有序,无法保证全局有序。如果想要全局有序,需要设置成只有一个partition。

16. Kafka分区数

分区数并不是越多越好,一般分区数不要超过集群机器数量。分区数越多占用内存越大(ISR等),一个节点集中的分区也就越多,当它宕机的时候,对系统的影响也就越大。
分区数一般设置为:3-10个。

技巧

需要结合项目来回答。一般数据量100G以内,10台机器,3台Kafka节点即可。分区数3-10左右。

17. 副本数设定

一般我们设置成2个或3个,很多企业设置为2个。

18.多少个Topic

通常情况:多少个日志类型就多少个Topic。也有对日志类型进行合并的。

19. *Kafka分区分配策略

在Kafka内部存在两种默认的分区分配策略:Range 和 RoundRobin。

1.Range是默认策略

Range是对每个Topic而言的(即一个一个Topic的分),首先对同一个Topic里面的分区按照序号进行排序,并对消费者按照字母进行排序。然后用Partitions分区的个数除以消费者线程的总数来决定每个消费者线程消费几个分区。如果除不尽,那么前面几个消费者线程将会多消费一个分区。
例如:我们有10个分区,两个消费者(C1,C2),3个消费者线程,10 / 3 = 3而且除不尽。

  • C1-0 将消费 0,1,2,3 分区
  • C2-0 将消费 4,5,6 分区
  • C2-1 将消费 7,8,9 分区
2.RoundRobin

前提:同一个Consumer Group里面的所有消费者的 num.streams(消费者消费线程数)必须相等;每个消费者订阅的主题必须相同。
将所有主题分区组成 TopicAndPartition 列表,然后对 TopicAndPartition 列表按照hashCode 进行排序,最后按照轮询的方式发给每一个消费线程。

技巧

需要能够回答出 Kafka 的分区策略。默认分区策略。以及每个分区策略相对应的流程。

20. *Kafka中数据量计算

每天总数据量100g,每天产生1亿条日志,10000 万/24/60/60=1150条/每秒钟。

  • 平均每秒钟:1150条
  • 低估每秒钟:400条
  • 高峰每秒钟:1150条*(2-20倍) =2300 条 - 23000条
  • 每条日志大小:0.5-2k
  • 每秒多少数据量:2.3M-20MB
技巧

以上内容作为数据量计算的参考。

21. *Kafka消息数据积压,Kafka消费能力不足怎么处理?

如果是Kafka消费能力不足,则可以考虑增加Topic的分区数,并且同时提升消费组的消费者数量,消费者数=分区数。(两者缺一不可)
如果是下游的数据处理不及时:提高每批次拉取的数量。批次拉取数据过少(拉取数据/处理时间<生产速度),使处理的数据小于生产的数据,也会造成数据积压。

技巧

面试可能会问,你们有没有遇到过Kafka消息数据积压,是怎么处理的?可有从以上两个方面进行分析回答。

22. Kafka监控

开源的监控器:KafkaManager,KafkaMonitor。

技巧

这里回答开源的Kafka监控工具即可。有些大企业是自己开发的。

23. *Kafka高吞吐的实现

1.顺序读写

Kafka的消息是不断追加到文件中的,这个特性使Kafka可有充分利用磁盘的顺序写性能。顺序读写不需要硬盘磁头的寻道时间,只需很少的扇区旋转时间,所以速度远快于随机读写。

2.零拷贝

在Linux kernel2.2之后出现了一种叫做“零拷贝(zero-copy)”系统调用机制,就是跳过“用户缓冲区”的拷贝,建立一个磁盘空间和内存的直接映射,数据不再复制到“用户态缓冲区”。

零拷贝并不是不需要拷贝,而不是减少不必要的拷贝次数。通常是说在IO读写过程中。“零拷贝技术”只用将磁盘文件的数据复制到页面缓存中一次,然后将数据从页面缓存直接发送到网络中。

kafka不确定执行时间手动ack超时问题 kafka checkpoint_spark

3.分区

Kafka的队列topic被分为了多个区partition,每个partition又分为多个段segment,所以一个队列中的消息实际上是保存在N多个片段文件中通过分段的方式,每次文件操作都是对一个小文件的操作,非常轻便,同时也增加了并行处理能力。

4.批量发送

Kafka允许进行批量发送消息,先将消息缓存在内存中,然后一次请求批量发送出去比如可以指定缓存的消息达到某个量的时候就发出去,或者缓存了固定的时间后就发送出去,如100条消息就发送,或者每5秒发送一次这种策略将大大减少服务端的I/O次数。

5.数据压缩

Kafka还支持对消息集合进行压缩,Producer可以通过GZIP或Snappy格式对消息集合进行压缩,压缩的好处就是减少传输的数据量,减轻对网络传输的压力。

6.Consumer的负载均衡

当一个group中有consumer加入或者离开时,会触发partitions均衡,均衡的最终目的,是提升topic的并发消费能力。