Kafka面试题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kafka面试题相关的知识,希望对你有一定的参考价值。
参考技术AKafka是分布式发布-订阅消息系统,它最初是由LinkedIn公司开发的,之后成为Apache项目的一部分,Kafka是一个分布式,可划分的,冗余备份的持久性的日志服务,它主要用于处理流式数据。
为什么要使用 kafka,为什么要使用消息队列
消息发送
解决方案
1.配置ack=all/-1,tries > 1,unclean.leader.election.enable = false
producer发送完消息,等待follower同步完成再返回,如果异常则重试,副本数量可能影响吞吐量
不允许选举ISR的副本作为leader
2.配置min.insync.replicas>1
副本指定必须写操作成功的最小副本数量,如果不能满足这个最小值,则生产者引发一个异常(NotEnoughReplicash或者NotEnoughReplicashAfterAppend)
消费
先commit再处理消息,如果处理消息的时候异常了,但offset已经提交了,这条消息对于消费者来说丢失了
broker的刷盘
减少刷盘的间隔
kafka如何保证不重复消费又不丢失数据
1.必须要求至少一个 Follower 在 ISR 列表里。
2.第二条,每次写入数据的时候,要求 Leader 写入成功以外,至少一个 ISR 里的 Follower 也写成功。
pull模式
push模式
缺点:速率固定,忽略了consumer的消费能力,可能导致拒绝服务或者网络阻塞等情况
1. Broker注册 Broker是分布式部署并且相互之间相互独立,但是需要有一个注册系统能够将整个集群中的Broker管理起来 /brokers/ids
2. Topic注册 在Kafka中,同一个Topic的消息会被分成多个分区并将其分布在多个Broker上,这些分区信息及与Broker的对应关系也都是由Zookeeper在维护 /borkers/topics
3. 生产者负载均衡 由于同一个Topic消息会被分区并将其分布在多个Broker上,因此,生产者需要将消息合理地发送到这些分布式的Broker上,那么如何实现生产者的负载均衡,Kafka支持传统的四层负载均衡,也支持Zookeeper方式实现负载均衡。
4. 消费者负载均衡 与生产者类似,Kafka中的消费者同样需要进行负载均衡来实现多个消费者合理地从对应的Broker服务器上接收消息,每个消费者分组包含若干消费者,每条消息都只会发送给分组中的一个消费者,不同的消费者分组消费自己特定的Topic下面的消息,互不干扰。
5. 分区与消费者 的关系 在Kafka中,规定了每个消息分区 只能被同组的一个消费者进行消费,因此,需要在 Zookeeper 上记录 消息分区 与 Consumer 之间的关系,每个消费者一旦确定了对一个消息分区的消费权力,需要将其Consumer ID 写入到 Zookeeper 对应消息分区的临时节点上,例如:
/consumers/[group_id]/owners/[topic]/[broker_id-partition_id]
其中,[broker_id-partition_id]就是一个 消息分区 的标识,节点内容就是该 消息分区 上 消费者的Consumer ID。
6. 消息消费进度Offset 记录 在消费者对指定消息分区进行消息消费的过程中,需要定时地将分区消息的消费进度Offset记录到Zookeeper上,以便在该消费者进行重启或者其他消费者重新接管该消息分区的消息消费后,能够从之前的进度开始继续进行消息消费。Offset在Zookeeper中由一个专门节点进行记录,其节点路径为:
/consumers/[group_id]/offsets/[topic]/[broker_id-partition_id]
节点内容就是Offset的值。
7. 消费者注册 消费者服务器在初始化启动时加入消费者分组的步骤如下
注册到消费者分组。每个消费者服务器启动时,都会到Zookeeper的指定节点下创建一个属于自己的消费者节点,例如/consumers/[group_id]/ids/[consumer_id],完成节点创建后,消费者就会将自己订阅的Topic信息写入该临时节点。
Kafka不基于内存,而是硬盘存储,因此消息堆积能力更强
1.顺序写磁盘(相比磁盘的随机写快很多)。如果你是追加文件末尾按照顺序的方式来写数据的话,那么这种磁盘顺序写的性能基本上可以跟写内存的性能本身也是差不多的。
2.利用Page Cache(页高速缓冲存储器,简称页高缓)空中接力的方式来实现高效读写,操作系统本身有一层缓存,叫做page cache,是在内存里的缓存,我们也可以称之为os cache,意思就是操作系统自己管理的缓存。原理就是Page Cache可以把磁盘中的数据缓存到内存中,把对磁盘的访问改为对内存的访问。
3.零拷贝 零拷贝技术是一种避免CPU将数据从一块存储拷贝到另一块存储的技术。Kafka使用零拷贝技术将数据直接从磁盘复制到网卡设备缓冲区中,而不需要经过应用程序的转发。
通常应用程序将磁盘上的数据传送至网卡需要经过4步:
-调用read(),将数据从磁盘复制到内核模式的缓冲区;
-CPU会将数据从内核模式复制到用户模式下的缓冲区;
-调用write(),将数据从用户模式下复制到内核模式下的Socket缓冲区;
-将数据从内核模式的Socket缓冲区复制到网卡设备。
上面的步骤中,第2、3步将数据从内核模式经过用户模式再绕回内核模式,浪费了两次复制过程。采用零拷贝技术,Kafka可以直接请求内核把磁盘中的数据复制到Socket缓冲区,而不用再经过用户模式
Rebalance 本质上是一种协议,规定了一个 Consumer Group 下的所有consumer如何达成一致,来分配订阅 Topic 的每个分区。
Rebalance 的触发条件有3个
Rebalance 发生时,Group 下所有 consumer 实例都会协调在一起共同参与,kafka 能够保证尽量达到最公平的分配。但是 Rebalance 过程对 consumer group 会造成比较严重的影响。在 Rebalance 的过程中 consumer group 下的所有消费者实例都会停止工作,等待 Rebalance 过程完成。
GroupCoordinator(协调者):协调消费者组完成消费者Rebalance的重要组件,每一个broker都会启动一个GroupCoodinator,Kafka 按照消费者组的名称将其分配给对应的GroupCoodinator进行管理;每一个GroupCoodinator只负责管理一部分消费者组,而非集群中全部的消费者组。通常是partition的leader节点的broker
如果C1消费消息超时,出入rebalance,重新分配后该消息被其他消费者消费,此时C1消费完成提交offset,导致错误
解决:Coordinator每次进行rebalance,会标记一个generation给consumer,每次rebalance该generation会+1,consumer提交offset时,会对比generation,不一致则拒绝提交。
ISR :In-Sync Replicas 副本同步队列
AR :Assigned Replicas 所有副本
ISR是由leader维护,follower从leader同步数据有一些延迟(包括延迟时间replica.lag.time.max.ms和延迟条数replica.lag.max.messages两个维度, 当前最新的版本0.10.x中只支持replica.lag.time.max.ms这个维度),任意一个超过阈值都会把follower剔除出ISR, 存入OSR(Outof-Sync Replicas)列表,新加入的follower也会先存放在OSR中。AR=ISR+OSR。
在 Kafka 中,每个 主题分区下的每条消息都被赋予了一个唯一的 ID 数值,用于标识它在分区中的位置。这个 ID 数值,就被称为位移,或者叫偏移量。一旦消息被写入到分区日志,它的位移值将不能被修改。
auto.offset.reset:消费规则,默认earliest 。
earliest: 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费
latest: 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该分区下的数据
none: topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常
Kafka 副本当前分为领导者副本和追随者副本。只有Leader副本才能 对外提供读写服务,响应Clients端的请求。Follower 副本只是采用拉(PULL)的方 式,被动地同步Leader副本中的数据,并且在Leader副本所在的 Broker 宕机后,随时准备应聘 Leader 副本。
kafka在所有broker中选出一个controller,所有Partition的Leader选举都由controller决定。controller会将Leader的改变直接通过RPC的方式(比Zookeeper Queue的方式更高效)通知需为此作出响应的Broker。同时controller也负责增删Topic以及Replica的重新分配。
分区的 Leader 副本选举对用户是完全透明的,它是由 Controller 独立完成的。你需要回答的是,在哪些场景下,需要执行分区 Leader 选举。每一种场景对应于一种选举策略。当前,Kafka 有 4 种分区 Leader 选举策略。
集群 partition 备份 Kafka 支持设置针对每个 partition 备份,可以将 partition 备份到不同的 broker 上,其中 leader partition 负责读写,其他 follower 仅负责同步,当 leader 挂掉后会从 follower 中选取新的 leader 。
消息消费顺序 一个 partition 同一时刻在一个 consumer group 中只能有一个 consumer 实例在消费,从而保证了消费顺序。consumer group 中的 consumer 实例的数量不能比一个 topic 中的 partition 的数量多,否则,多出来的 consumer 无法消费到消息。Kafka 的消息在单个 partition 上是可以保证顺序的,但是在整体上无法保证顺序消费
消息消费模式 关于消费模式,Kafka 通过 消费组的概念可以灵活设置。如常见的 队列模式 即 所有的 consumer 在同一个 consumer group 下。发布订阅模式 则设置多个 consumer group 进行消费即可
acks:消息的确认机制,默认值是0。
acks=0:如果设置为0,生产者不会等待kafka的响应。
acks=1:这个配置意味着kafka会把这条消息写到本地日志文件中,但是不会等待集群中其他机器的成功响应。
acks=all:这个配置意味着leader会等待所有的follower同步完成。这个确保消息不会丢失,除非kafka集群中所有机器挂掉。这是最强的可用性保证。
kafka面试题2
kafka面试题2
- 31.Kafka中有那些索引文件:
- 32.如果我指定了一个offset,Kafka怎么查找到对应的消息:
- 33.如果我指定了一个timestamp,Kafka怎么查找到对应的消息:
- 34.聊一聊你对Kafka的Log Retention的理解(留存期):
- 36.聊一聊你对Kafka的Log Compaction的理解:
- 37.聊一聊你对Kafka底层存储的理解(页缓存、内核层、块层、设备层):
- 38.聊一聊Kafka的延时操作的原理:
- 39.聊一聊Kafka控制器的作用:
- 40.消费再均衡的原理是什么:
- 41.Kafka中的幂等性是怎么实现的:
- 42.Kafka中的事务是怎么实现的:
- 43.Kafka中有那些地方需要选举,这些地方的选举策略又有哪些:
- 44.失效副本是指什么?有那些应对措施:
- 45.多副本下,各个副本中的HW和LEO的演变过程:
- 46.为什么Kafka不支持读写分离:
- 47.Kafka在可靠性方面做了哪些改进:
- 48.Kafka中怎么实现死信队列和重试队列:
- 49.Kafka中的延迟队列怎么实现:
- 50.Kafka中怎么做消息审计:
- 51.Kafka中怎么做消息轨迹:
- 52.Kafka有哪些指标需要着重关注:
- 53.怎么计算Lag(注意read_uncommitted和read_committed状态下的不同):
- 54.Kafka的那些设计让它有如此高的性能:
- 55.Kafka有什么优缺点:
- 56.还用过什么同质类的其它产品,与Kafka相比有什么优缺点:
- 57.为什么选择Kafka:
- 58.在使用Kafka的过程中遇到过什么困难,怎么解决的:
- 59.怎么样才能确保Kafka极大程度上的可靠性:
- 60.Kafka的用途有哪些,使用场景如何:
31.Kafka中有那些索引文件:
-
- .index:位移索引文件:保存的是于索引未见起始位移的差值,存储的是位移和真是物理文件位置的映射——帮助broker更快的定位记录所在的物理文件位置;
-
- .timeindex:时间戳索引文件,保存的是时间戳于位移的映射关系,给定时间戳之后根据索引文件只能找到不大于改时间戳的最大位移,稍后Kafka还要拿着返回的位移再去位移索引文件中定位真实的物理文件位置——根据时间戳查找对应的位移信息;
- 3.索引文件都属于稀疏索引文件,写入若干条记录后才会添加一个索引项,且索引升序顺序存储;
32.如果我指定了一个offset,Kafka怎么查找到对应的消息:
-
- 在位移索引文件中根据二分查找算法找到小于等于该offset的最大索引项<offset,XXXX>;
- 2.Kafka在对应的.log文件中从第XXXX位置开始顺序搜寻记录,直到找到位移为offset的消息记录为止;
33.如果我指定了一个timestamp,Kafka怎么查找到对应的消息:
- 1.首先查找时间戳索引项定位到找到小于等于timestamp最大timestamp,得到这个timestamp对应的索引位置index;
- 2.在位移索引文件中根据二分查找算法找到小于等于该index的最大索引项<offset,XXXX>;
- 3.Kafka在对应的.log文件中从第XXXX位置开始顺序搜寻记录,直到找到位移为offset的消息记录为止;
34.聊一聊你对Kafka的Log Retention的理解(留存期):
- 1.清除单位:日志清除的单位是日志段,即删除符合清楚策略的日志段文件和对应的索引文件;
- 2.清除策略:
- 1.基于时间的留存策略:Kafka默认会清除7天前的日志算数据,可以根据参数进行配置;
- 2.基于大小的留存策略:Kafka默认只会为每个log保留log.retention.bytes参数值大小的字节数,可以根据参数进行配置;
- 3.清除过程:日志清除过程是一个异步过程,Kafkabroker启动后会创建单独的县城处理日志清除事宜;
- 4.注意事项:日志清除对于当前日志段是不生效的;
36.聊一聊你对Kafka的Log Compaction的理解:
- 日志压实:确保Kafka topic每个分区下的每条具有相同key的消息都至少保存最新的value的消息,它提供了更加细粒度话的留存策略,也就是说,如果要使用log.compaction1,Kafka必须为每条消息设置key;
- 特点:log.compaction只会根据某种策略有选择的移除.log中的消息,并不会更改分区日志的offset值;
- 配置:log.compaction是topic级别的配置,逻辑划分上,log.compaction会将日志划分为已清理部分和未清理部分,后者又可以进一步划分为可清理和不可清理部分;
- 注意事项:当前日志段永远属于不可清理部分;
- 典型应用:__consumer_offsets内部topic用来保存位移信息,这个topic就是采用log.compaction留存期策略的。
37.聊一聊你对Kafka底层存储的理解(页缓存、内核层、块层、设备层):
- 页缓存:
- 1.本质:页缓存是操作系统实现的一种主要的磁盘缓存,以次用来减少对磁盘I/O的操作,具体来说,就是把磁盘的数据缓存在内存中,把对磁盘的访问变为对内存的访问;
- 2.数据读取:当一个进程准备读取磁盘上的文件内容时,操作系统回先查看待读取的数据所在的页(page)是否在页缓存上,如果命中,则直接返回数据,从而避免了队伍里磁盘的I/O操作,如果没有命中,操作系统会向磁盘发起读取请求并将读取的数据页存入页缓存中,之后再将数据返回给进程;
- 3.数据写入:如果一个进程需要将数据写入磁盘,那么操作系统也会监测数据对应的页是否在页缓存中,如果不在,则会先在页缓存中添加相应的页,最后将数据写入对应的页,被修改过的页也就变成了脏页,操作系统会在合适的时间把脏页中的数据写入磁盘中,以保持数据的一致性;
- 4.java的劣势:Java中,对象的内存开销非常大,通常时真实数据大笑的几倍甚至更多,空间使用率底下,Java的垃圾回收会随着堆内数据的增多而变得越来越慢,基于这些因素,使用文件系统并依赖也缓存的做法明显要由于维护一个进程内缓存或其他结构,至少我们可以省去了以根进程内部的缓存消耗,同时还可以通过结构紧凑的字节码来替代使用对象的方式以节省更多的空间。
- 5.其他优势:积时Kafka服务重启,页缓存还是会保持有效,然而进程中的缓存却需要重建,这样页极大的简化了代码逻辑,因为维护页缓存和文件之间的一致性交给操作系统来负责,比在进程内维护更加安全有效;
- 零拷贝:
- 除了消息顺序追加,页缓存等技术,Kafka还使用了零拷贝技术来进一步提升性能,所谓零拷贝是指将数据直接从磁盘文件复制到网卡设备中,而不需要经过应用程序之手,零拷贝大大提高了应用程序的性能,减少了内核态和用户态之间的上下文切换,对于linux操作系统而言,零拷贝技术依赖于底层的sendfile()方法实现,对于Java语言,FileChannal.transferTo()方法的底层实现就是sendfile()方法;
- 注:这一段完全是抄的,我只略懂大概,后续去学;
38.聊一聊Kafka的延时操作的原理:
-
- Kafka中由多种延时操作,比如延时生产,延时拉取,延时数据删除等;
-
- 延时操作创建之后会被加入到延时操作管理器中来做专门的处理,演示操作有时候会超时,每个延时操作管理器都会配备一个定时器来做超时管理,定时器的底层就是采用时间轮实现的。
- 注:这个不咋懂,感觉也不重要,用到再学吧。
39.聊一聊Kafka控制器的作用:
- 1.controller生成:Kafka集群启动时,第一个在zookeeper的/controller目录下新建子节点的broker被选举为该kafka集群的控制器;
- 2.controller高可用:通过zookeeper的临时节点+watcher事件实现,/controller下的子节点为临时节点,controller所在的broker崩溃就会消失,这样其他broker通过watcher事件收到消息,又会进行新的controller选举(第一个在zookeeper的/controller目录下新建子节点的broker为新的controller);
- 3.controller职责:负责管理集群中所有分区和读本状态,当某个分区的leader副本出现故障时,由controller负责为该分区选举出新的leader副本,检测到某个分区的ISR集合发生变化时,由controller负责将元数据信息同步到Kafka集群中,他还负责topic的增加于删除,分区的重分配,优先副本的选举,topic的分区扩展,Kafka集群的扩展,broker崩溃,受控关闭,controller leader的选举等等事项;
- 4.总结:就是处理集群中所有的管理事务,并向集群中各个broker同步元数据信息的。
40.消费再均衡的原理是什么:
- 触发操作:
- 1.组成员发生变更:比如新的consumer加入组,或者已有的conusmer主动离开组,或者已有的consumer崩溃触发rebalance;
- 2.组订阅topic数发生变更:比如使用基于正则表达式的订阅,当匹配到正则表达式的topic被创建时就会触发rebalance;
- 3.组订阅topic的分区数发生变化:比如使用命令行脚本增加了订阅topic的分区数;
- rebalance协议:
- 1.JoinGroup:consumer请求加入组;
- 2.SyncGroup:group leader把分配方案同步更新到组内所有成员中;
- 3.HeartBeat:cousumer定期向coordinate汇报心跳表示自己依然存活;
- 4.LeaveGroup:consumer主动通知coordinate自己即将离组;
- 5.DescribeGroup:查看组信息,包括成员信息,协议信息,分配方案,订阅信息等;
- rebalance流程:
- 1.首先确定coordinate所在的broker,并创建与该broker相互通信的socket连接;
- 2.成功连接coordinate之后就可以进行热balance操作;
- 3.rebalance:
- 1.加入组:
- 1.所有consumer(group.id相同的所有consumer实例)向coordinate发送JoinGroup请求;
- 2.当收集全JoinGroup后,coordinate会从中选择一个consumer担任group的leader,并把所有成员信息以及他们的的订阅信息发送给leader;
- 1.加入组:
- 2.同步更新分配方案:
- 1.leader开始制定分配方案,即根据前面提到的分区分配策略决定每个consumer都负责哪些topic的哪些分区;
- 2.分配完成后,leader就会将分配方案装进SyncGroup请求中并发送给coordinate;
- 3.coordinate接收到分配方案后,把属于每个consumer的方案单独取出来作为SyncGroup请求的response返还给各自的consumer;
41.Kafka中的幂等性是怎么实现的:
- 生产者的幂等性:
- 1.producer id:PID,每个生产者在初始化时都会被分配一个PID,这个过程对用户而言是完全透明的;
- 2.序列号:对于每个 PID,消息发送到的每一个分区都有对应的序列号,这些序列号从0开始单调递增。生产者每发送一条消息就会将 <PID,分区> 对应的序列号的值加1;
- 3.broker端:broker 端会在内存中为每一对 <PID,分区> 维护一个序列号。对于收到的每一条消息,只有当它的序列号的值(SN_new)比 broker 端中维护的对应的序列号的值(SN_old)大1(即 SN_new = SN_old + 1)时,broker 才会接收它。
42.Kafka中的事务是怎么实现的:
- Kafka中的事务:可以使应用程序将消费消息、生产消息、提交消费位移当作原子操作来处理,同时成功或失败,即使该生产或消费会跨多个分区。
- 实现:
- 1.Kafka为实现事务要求应用程序必须提供唯一一个id表证事务(事务ID),他必须在应用程序所有的会话上是唯一的,事务ID和PID不同,事务ID是用户显式提供,后者是prodcuer自行分配的;
- 2.有了事务Id后,Kafka就能确保:
- 1.跨应用程序会话间幂等性发送语义(类似generation);
- 2.支持跨会话的事务恢复;
- 3.Kafka在消息属性字段中添加控制信息来实现事务,控制信息有两类——COMMIT和ABORT,分别表示事务提交和事务种植,将控制信息保存在Kafka日志中的目的是为了让consumer能够识别事务边界,从而整体的读取某个事务下的所有消息;
- 4.通俗地说,凡是被标记事务ID的消息都在一个事务里,然后在消息中保存事务控制信息 ,可以使consumer分辨事务边界,停止事务;
- consumer端事务支持:略微弱一点,原因如下:
- 1.对于compactted的topic而言,事务中的消息可能已经被删除了;
- 2.事务可能跨日志段,若老的日志段被删除,则用户将丢失事务中的部分消息;
- 3.consumer层序可能使用seek方法定位事务中的任意为止,造成部分消息的丢失;
- 4.consumer可能选择不消费事务中的所有消息,即无法保证读取失去的全部消息;
43.Kafka中有那些地方需要选举,这些地方的选举策略又有哪些:
- controller:在Kafka集群中选取一个broker用于管理Kafka集群,Kafka集群启动时,第一个注册到zookeeper的/controller节点上的broker称为该集群的controller;
- Leader Replica:负责partition中的数据读写,而follower副本会被动从leader中同步数据,leader的选举由controller负责(设置优先副本时,按照优先副本来确定);
- coordinator:负责协调consumer group的管理事宜,由controller进行选举;
- Leader consumer:负责指定rebalance分配方案,第一个发送给coordinate JoinGroup消息的consumer会被选举为Leader consumer;
44.失效副本是指什么?有那些应对措施:
- 失效副本:follower replica中消息的进度落后于leader;
- 应对措施:
- 1.将失效副本移除LEO组,当失效副本中消息进度赶上leader副本时,再将其加入LEO组合;
- 2.找到副本追赶不上的原因,是broker端参数配置不合理,还是follower副本端程序有问题,还是网络问题等,排查出原因后解决。
- 副本失效场景:
- 1.follower 副本进程卡住,在一段时间内根本没有向 leader 副本发起同步请求,比如频繁的 Full GC;
- 2.follower 副本进程同步过慢,在一段时间内都无法追赶上 leader 副本,比如 I/O 开销过大;
- 3.如果通过工具增加了副本因子,那么新增加的副本在赶上 leader 副本之前也都是处于失效状态的;
- 4.如果一个 follower 副本由于某些原因(比如宕机)而下线,之后又上线,在追赶上 leader 副本之前也处于失效状态;
45.多副本下,各个副本中的HW和LEO的演变过程:
- 1.副本属性初始状态图:
- 2.leader副本写入消息后follower副本发送FETCH请求:
- 1.leader写入消息到底层日志,同时更新inleader副本的LEO属性;
- 2.尝试更新leader副本的HW值(失败);
- 3.follower发送fetch请求,leader端读取底层log数据;
- 4.更新remote LEO=0;
- 5.尝试更新分区HW,此时Leader LEo=1,remoteLEO=0,所以HW=0,更新失败;
- 6.把数据和当前分区的HW值发送给follower副本;
- 7.follower副本接收到fetch response后,将数据写入本地log,同时更新follower LEO;
- 8.更新follow HW(失败);
- 3.第二轮Fetch请求:
- 1.leader端姐到请求后,读取底层log数据;
- 2.更新remote LEO=1;
- 3.尝试更新分区HW=1,更新成功,因为此时的lEO和remote LEO都等于1;
- 4.把数据(实际上没有数据)和当前分区HW值(已经为1)发送给follower副本;
- 5.follower副本接收到Fetch response请求后,写入本地log(无东西可写);
- 6.更新LEO,没有写数据,就不会更新,故LEO=1;
- 7更新HW,比较本地LEO和当前leader的LEO取最小值,最小值为1,此时更新follower上的HW=1;
46.为什么Kafka不支持读写分离:
- 读写分离缺点:
- 数据一致性问题:数据从主节点转到从节点,必然会有一个延时的时间窗口,这个时间窗口会导致主从节点之间的数据不一致;
- 延时问题:数据从写入主节点到同步至从节点中的过程,需要经历经历网络→主节点内存→主节点磁盘→网络→从节点内存→从节点磁盘阶段,对延时敏感的应用而言,主写从读的功能并不太适用。
- 当前方案收益:
- 1.可以简化代码的实现逻辑,减少出错的可能;
- 2.将负载粒度细化均摊,与主写从读相比,不仅负载效能更好,而且对用户可控(使用partition);
- 3.没有延时的影响;
- 4.在副本稳定的情况下,不会出现数据不一致的情况。
参考资料:https://mp.weixin.qq.com/s?src=11×tamp=1592144166&ver=2400&signature=Xe3Gf6EBvhM5BmpsLraQ-7la5teApL2pEXvAxNnGgEbL2JRu9hNCGkjmMEz-2Il40w4FQilETxHBgTRPuGZlUSKX4BKuIuNutiqPm0KnJU6E7PL3FOO7aXvQZu0sop&new=1
47.Kafka在可靠性方面做了哪些改进:
- HW:高水位,消费者只能消费位移再HW之前的消息,分区 ISR 集合中的每个副本都会维护自身的 LEO,而 ISR 集合中最小的 LEO 即为分区的 HW;
- leader epoch:leader epoch 代表 leader 的纪元信息(epoch),初始值为0。每当 leader 变更一次,leader epoch 的值就会加1,相当于为 leader 增设了一个版本号。epoch是一对值<epoch,offset>,每个leader会保存一个缓存,定期将其写入一个检查点文件中,如果leader首次写消息,则会在缓存中增加一个条目,负责不做更新,每次副本称为新的leader是会查询这部分缓存,获取对应的leader版本位移
- 46题描述的数据丢失的情况:
- 1.丢失数据:在第二轮fetch中,leader的HW已更新,follower未更新,此时follower宕机,follow恢复好,按照HW进行日志截断,丢失了最新一条消息,准备从leader中拉取,leader宕机了,follower称为leader,则那一条数据永远丢失,而epoch可以按照下图所示进行规避:
- 2.数据不一致:在第二轮fetch中,leader的HW已更新,follower未更新,此时follower和leader同时宕机,follower先恢复好,按照HW进行日志截断,丢失了最新一条消息,此时follower变成新leader,然后producer又发送一条消息,新leader的HW+1,此时旧leader恢复,旧leader和新leader的HW相同,不进行数据同步,故造成了数据不一致,epoch可以按照下图所示进行规避:
- 1.丢失数据:在第二轮fetch中,leader的HW已更新,follower未更新,此时follower宕机,follow恢复好,按照HW进行日志截断,丢失了最新一条消息,准备从leader中拉取,leader宕机了,follower称为leader,则那一条数据永远丢失,而epoch可以按照下图所示进行规避:
参考资料:apache kafka实战第183页。
48.Kafka中怎么实现死信队列和重试队列:
- 死信队列:可以看作消费者不能处理收到的消息,也可以看作消费者不想处理收到的消息,还可以看作不符合处理要求的消息。比如消息内包含的消息内容无法被消费者解析,为了确保消息的可靠性而不被随意丢弃,故将其投递到死信队列中;
- 重试队列:可以看作一种回退队列,具体指消费端消费消息失败时,为了防止消息无故丢失而重新将消息回滚到 broker 中,重试队列一般分成多个重试等级,每个重试等级一般也会设置重新投递延时,重试次数越多投递延时就越大;
- 设置重试队列:消息第一次消费失败入重试队列 Q1,Q1 的重新投递延时为5s,5s过后重新投递该消息;如果消息再次消费失败则入重试队列 Q2,Q2 的重新投递延时为10s,10s过后再次投递该消息;
- 设置死信队列:重试越多次重新投递的时间就越久,并且需要设置一个上限,超过投递次数就进入死信队列;
- 注:仅作了解即可。
49.Kafka中的延迟队列怎么实现:
- 延迟队列:在发送延时消息的时候并不是先投递到要发送的真实主题中,而是先投递到一些 Kafka 内部的主题中,这些内部主题对用户不可见,然后通过一个自定义的服务拉取这些内部主题中的消息,并将满足条件的消息再投递到要发送的真实的主题中,消费者所订阅的还是真实的主题。
- 注:仅作了解即可。
50.Kafka中怎么做消息审计:
- 消息审计:在消息生产、存储和消费的整个过程之间对消息个数及延迟的审计,以此来检测是否有数据丢失、是否有数据重复、端到端的延迟又是多少等内容。
- 实现:主要通过在消息中内嵌消息对应的时间戳 timestamp 或全局的唯一标识 ID来实现消息的审计功能。
- 内嵌 timestamp: 设置一个审计的时间间隔 time_bucket_interval,根据这个 time_bucket_interval 和消息所属的 timestamp 来计算相应的时间桶(time_bucket)。
- 内嵌 ID :对于每一条消息都会被分配一个全局唯一标识 ID。如果主题和相应的分区固定,则可以为每个分区设置一个全局的 ID。当有消息发送时,首先获取对应的 ID,然后内嵌到消息中,最后才将它发送到 broker 中。消费者进行消费审计时,可以判断出哪条消息丢失、哪条消息重复
51.Kafka中怎么做消息轨迹:
- 消息轨迹:指的是一条消息从生产者发出,经由 broker 存储,再到消费者消费的整个过程中,各个相关节点的状态、时间、地点等数据汇聚而成的完整链路信息。生产者、broker、消费者这3个角色在处理消息的过程中都会在链路中增加相应的信息,将这些信息汇聚、处理之后就可以查询任意消息的状态;
- 实现:封装客户端,在保证正常生产消费的同时添加相应的轨迹信息埋点逻辑。无论生产,还是消费,在执行之后都会有相应的轨迹信息,我们需要将这些信息保存起来。
52.Kafka有哪些指标需要着重关注:
- BytesIn/BytesOut:Broker 端每秒入站和出站字节数,接近网络带宽会出现网络丢包;
- NetworkProcessorAvgIdlePercent:即网络线程池线程平均的空闲比例。
- RequestHandlerAvgIdlePercent:即 I/O 线程池线程平均的空闲比例。
- UnderReplicatedPartitions:即未充分备份的分区数。
- ISRShrink/ISRExpand:即 ISR 收缩和扩容的频次指标。
- Broker 端每秒入站和出站字节数:即当前处于激活状态的控制器的数量。正常情况下,Controller 所在 Broker 上的这个 JMX 指标值应该是 1,其他 Broker 上的这个值是 0。如果你发现存在多台 Broker 上该值都是 1 的情况,表示集群出现了脑裂。
- 注:仅做了解,实际应用时使用;
53.怎么计算Lag(注意read_uncommitted和read_committed状态下的不同):
- 1.如果消费者客户端为“read_uncommitted”,它对应的 Lag 等于HW – ConsumerOffset 的值,其中 ConsumerOffset 表示当前的消费位移。
- -2.如果这个参数配置为“read_committed”,它对应的 Lag 等于 LSO(LastStableOffset ) – ConsumerOffset 的值。
54.Kafka的那些设计让它有如此高的性能:
- 1.partition,producer和consumer端的批处理:提高并行度;
- 2.页缓存:大量使用页缓存,内存操作比磁盘操作快很多,数据写入直接写道页缓存,由操作系统负责刷盘,数据读取也是直接命中页缓存,从内存中直接拿到数据;
- 3.零拷贝:如果数据读取命中了页缓存,数据会从页缓存直接发送到网卡进行数据传输,省略了用户态和内核态的切换以及多次的数据拷贝;
- 4.顺序读写:Kafka的数据是顺序追加的,避免了低效率的随机读写;
- 5.优秀的文件存储机制:分区规则设置合理的话,所有消息都可以均匀的分不到不同分区,分区日志还可以分段,相当于举行文件被平均分配为多个相对较小的文件,便于文件维护和清理;
- 索引文件:Kafka含有.index和.timeindex索引,以稀疏索引的方式进行构造,查找时可以根据二分法在索引文件中快速定位到目标数据附近位置,然后再.log文件中顺序读取到目标数据;
55.Kafka有什么优缺点:
- kafka的优点:
- 1.支持多个生产者和消费者;
- 2.支持broker的横向拓展;
- 3.副本集机制,实现数据冗余,保证数据不丢失;
- 4.通过分批发送压缩数据的方式,减少数据传输开销,提高吞高量
- 5.支持点对点和发布订阅;
- 6.基于磁盘实现数据的持久化;
- 7.毫秒级延迟;
- 8.对CPU和内存,网络的消耗比较小;
- 缺点:
- 1.由于是批量发送,所以数据达不到真正的实时;
- 2.只能支持统一分区内消息有序,无法实现全局消息有序;
- 3.需要配合zookeeper进行元数据管理;
- 4.可能会重复消费数据,消息会乱序;
56.还用过什么同质类的其它产品,与Kafka相比有什么优缺点:
57.为什么选择Kafka:
- 1.kafka特点:
- 1.支持点对点以及发布订阅模式:Kafka的consumer group策略,同一个consumer group中的consumer不能同时订阅同一个partition,这实现了点对点策略,一个topic中的partition可以被不同的consumer group订阅,这是实现了发布订阅模式;
- 2.语言支持:支持多种语言,Java优先,新版本的produce和consumer都是用Java语言写的;
- 3.单机吞吐量:十万级,因为Kafka的写入策略是将消息写入到页缓存,写入内存速度自然是非常高的;
- 4.消息延迟:毫秒级,因为消息读取时首先从页缓存中进行命中,且采用了零拷贝策略,省略了消息传递时的IO时间,以及消息传递时再用户态和内核态切换的时间;
- 5.API完备性:高;
- 6.可用性:非常高,使用zookeeper实现,kafka中的元数据都存储在zookeeper的节点上,利用zookeeper的临时节点+watcher事件机制实现数据一致性,故可用性非常高;
- 7.消息丢失:可以配置produce端和consumer端的参数保证消息不会丢失;
- producer端:
- ack=all/-1:全部ISR中的服务器将消息写入到页缓存时给客户端返回相应消息;
- retire=Interger.MaAX_VALUE:全部ISR中的服务器将消息写入到页缓存时给客户端返回相应消息;
- max.in.flight.requests.per.connection=1:单次只能send一个消息给broker,避免消息分区offset错乱;
- 使用待回调机制的send发送消息;
- unclean.leader.election.enable=flase:不允许非ISR的节点被选举为leader;
- replication.factor=3:多副本保存;
- min.insync.replicas:ISR至少拥有的节点数量;
- replication.factor>min.insync.replicas;
- producer端:
- consumer端:
- enable.auto.commit = false:对消息进行处理后,再进行位移提交;
- 8.消息重复:理论上会有重复,但是kafka给重复消息赋了一个相同的ID来达到消息的幂等性;
- 9.文档完备性:高;
- 10.提供快速入门:高;
58.在使用Kafka的过程中遇到过什么困难,怎么解决的:
- 1.数据丢失:数据接入时,采用完全异步方式接入导致数据丢失
- 解决方案:使用异步+回调的方式进行数据接入;
- 2.多线程消费数据冲突:日志报错多线程消费数据冲突;
- 解决方案:使用一个consumer+worker线程池的方式解决问题;
- 多线程消费数据:
- 1.多线程维护专属consumer:
- 2.单consumer+worker线程池,数据拉取和数据处理解耦:
- 3.两种多线程方法实现的区别:
- 1.多线程维护专属consumer:
- 3.Kafka的优先副本:注:明天过去回顾下,和张蕾讨论下;
59.怎么样才能确保Kafka极大程度上的可靠性:
- HW:consumer只能消费位移在HW以下的数据;
- epoch:用于在更新HW和LEO时保证消息不丢失,且不发生消息不一致的情况;
- 保证消费者不重复消费:可以根据业务指定唯一性的key, 如果发现已经消费过,则直接跳过(事务机制)。
- 消费者消息不遗漏:关闭自动提交offset, 消息消费成功后,手动提交offset.
- 生产者不重复发消息:生产者不重复发消息,生产者会为每个消息附一个PID,broker发现PID相同的消息会自动丢弃去重;
- 生产者发消息不遗漏:生产者开启消息重试机制;
- 保证生产者消息的顺序是正确的:sender线程每次发送消息只发送一条;
- 不允许非ISr中的broker成为新的leader:可以保证broker端不会丢数据;
- ISR中存活的broker不能少于一个:保证数据高可靠性;
60.Kafka的用途有哪些,使用场景如何:
- 1.异步处理:
- 场景:用户注册账号后需要发送注册邮件和注册短信:
- 方案:引入消息队列将不是必须的业务逻辑,异步处理。
- 2.应用解耦:
- 场景:用户下订单后,订单系统需要通知库存系统,缺点是订单系统和库存系统耦合,如果库存系统无法访问,那么订单则减库存失败,导致用户下订单失败;
- 方案:引入消息队列进行应用解耦。
- 3.数据削峰:
- 场景:秒杀活动,会因为流量过大,导致流量暴增,应用挂掉
- 方案:引入消息队列控制活动的人数,缓解短时间内高流量压垮应用:
- 步骤:1.用户发出请求后,服务器接收,首先写入消息队列中,加入消息队列长度超过最大数量,则直接抛弃用户请求或者直接跳转到用户界面;2.秒杀业务根据消息队列中的请求消息,在做后续处理;
- 4.日志处理:
- 场景:秒杀活动,会因为流量过大,导致流量暴增,应用挂掉
- 方案:引入消息队列控制活动的人数,缓解短时间内高流量压垮应用:
- 步骤:1.用户发出请求后,服务器接收,首先写入消息队列中,加入消息队列长度超过最大数量,则直接抛弃用户请求或者直接跳转到用户界面;2.秒杀业务根据消息队列中的请求消息,在做后续处理;
- 5.审计数据收集;
- 6.流式处理;
参考博客1:https://www.cnblogs.com/luozhiyun/p/11909315.html
参考博客2:https://www.cnblogs.com/luozhiyun/p/11811835.html
参考博客3:https://www.cnblogs.com/luozhiyun/p/12079527.html
以上是关于Kafka面试题的主要内容,如果未能解决你的问题,请参考以下文章