中间件面试专题:kafka高频面试问题

1,373 阅读7分钟

开篇介绍

大家好,近期会整理一些Java高频面试题分享给小伙伴,也希望看到的小伙伴在找工作过程中能够用得到!本章节主要针对Java一些消息中间件高频面试题进行分享。

Q1:

什么是消息和批次?

消息,Kafka里的数据单元,也就是我们一般消息中间件里的消息的概念。消息由字节数组组成。消息还可以包含键,用以对消息选取分区。

为了提高效率,消息被分批写入Kafka。

**批次,**就是一组消息,这些消息属于同一个主题和分区。如果只传递单个消息,会导致大量的网络开销,把消息分成批次传输可以减少这开销。但是,这个需要权衡,批次里包含的消息越多,单位时间内处理的消息就越多,单个消息的传输时间就越长。如果进行压缩,可以提升数据的传输和存储能力,但需要更多的计算处理。

Q2:

什么是主题和分区?

Kafka的消息用主题进行分类,主题下可以被分为若干个分区。分区本质上是个提交日志,有新消息,这个消息就会以追加的方式写入分区,然后用先入先出的顺序读取。

但是因为主题会有多个分区,所以在整个主题的范围内,是无法保证消息的顺序的,单个分区则可以保证。

Kafka通过分区来实现数据冗余和伸缩性,因为分区可以分布在不同的服务器上,那就是说一个主题可以跨越多个服务器。

前面我们说Kafka可以看成一个流平台,很多时候,我们会把一个主题的数据看成一个流,不管有多少个分区。

Q3:

Kafka中的ISR、AR代表什么?ISR的伸缩指的什么?

  • ISR :In-Sync Replicas 副本同步队列

  • AR :Assigned Replicas 所有副本

ISR是由leader维护,follower从leader同步数据有一些延迟(包括 延迟时间replica.lag.time.max.ms延迟条数replica.lag.max.message 两个维度,当前最新的版本0.10.x中只支持 replica.lag.time.max.ms 这个维度),任意一个超过阈值都会把follower剔除出ISR,存入OSR(Outof-Sync Replicas)列表,新加入的follower也会先存放在OSR中。

注:AR = ISR + OSR

Q4:

Broker 和 集群

一个独立的Kafka服务器叫Broker。broker的主要工作是,接收生产者的消息,设置偏移量,提交消息到磁盘保存;为消费者提供服务,响应请求,返回消息。在合适的硬件上,单个broker可以处理上千个分区和每秒百万级的消息量。

多个broker可以组成一个集群。每个集群中broker会选举出一个集群控制器。控制器会进行管理,包括将分区分配给broker和监控broker。

集群里,一个分区从属于一个broker,这个broker被称为首领。但是分区可以被分配给多个broker,这个时候会发生分区复制。

分区复制带来的好处是,提供了消息冗余。一旦首领broker失效,其他broker可以接管领导权。当然相关的消费者和生产者都要重新连接到新的首领上。

Q5:

kafka中的zookeeper起到什么作用?

zookeeper是一个分布式的协调组件,早期版本的kafaka用zk做 meta信息存储consumer的消费状态group的管理 以及 offset 的值。

考虑到zk本身的一些因素以及整个架构较大概率存在单点问题,新版本中逐渐弱化了zookeeper的作用。新的consumer使用了kafka内部的 group coordination 协议,也减少了对zookeeper的依赖。

Q6:

kafka follower如何与leader数据同步?

kafka的复制机制既不是完全的同步复制,也不是单纯的异步复制。

完全同步复制要求 All Alive Follower 都复制完,这条消息才会被认为commit,这种复制方式极大的影响了吞吐率。

一步复制方式下,Follower异步的从Leader复制数据,数据只要被Leader写入log就被认为已经commit,这种情况下,如果leader挂掉,会丢失数据;

kafka使用 ISR 的方式很好的均衡了确保数据不丢失以及吞吐率。Follower可以批量的从Leader复制数据,而且Leader充分利用磁盘顺序读以及 send file(zero copy) 机制,这样极大的提高复制性能,内部批量写磁盘,大幅减少了Follower与Leader的消息量差。

Q7:

kafka中的消息是否会丢失和重复消费?

消息发送

kafka消息发送有两种方式:同步(sync)和异步(async);

默认是同步方式,可通过 producer.type 属性进行配置;

kafka通过配置 request.required.acks 属性来确认消息的生产。

  • 0:表示不进行消息接收是否成功的确认;

  • 1:表示当Leader接收成功时确认;

  • -1:表示Leader和Follower都接收成功时确认;

综上所述,有6种消息产生的情况,消息丢失的场景有:

  • acks=0,不和kafka集群进行消息接收确认,则当网络异常、缓冲区满了等情况时,消息可能丢失;

  • acks=1、同步模式下,只有Leader确认接收成功后但挂掉了,副本没有同步,数据可能丢失;

消息消费

kafka消息消费有两个consumer接口, Low-level APIHigh-level API

  • Low-level API:消费者自己维护offset等值,可以实现对kafka的完全控制;

  • High-level API:封装了对parition 和 offset 的管理,使用简单;

如果使用高级接口High-level API,可能存在一个问题就是当消息消费者从集群中把消息取出来,并提交了新的消息offset值后,还没来得及消费就挂掉了,那么下次再消费时之前没消费成功的消息就"诡异"的消失了;

解决方案

1 针对消息丢失:同步模式下,确认机制设置为-1,即让消息写入Leader 和 Follower之后再确认消息发送成功;异步模式下,为防止缓冲区满,可以在配置文件设置不限制阻塞超时时间,当缓冲区满时让生产者一直处于阻塞状态。

2 针对消息重复:将消息的唯一标识保存到外部介质中,每次消费时判断是否处理过即可。

Q8:

kafka为什么不支持读写分离?

在kafka中,生产者写入消息、消费者读取消息的操作都是与Leader副本进行交互的,从而实现的是一种主写主读的生产消费模型。

kafka并不支持主写从读,因为主写从读有2个很明显的缺点:

  • 数据一致性问题:数据从主节点转到从节点必然会有一个延时的时间窗口,这个时间窗口会导致主从节点之间的数据不一致。某一时刻,在主节点和从节点中A数据的值都为X,之后将主节点中A的值修改为Y,那么在这个变更通知到从节点之前,应用读取从节点中的A数据的值并不为最新的Y值,由此便产生了数据不一致的问题。

  • 延时问题:类似Redis这种组件,数据从写入主节点到同步至从节点的过程中需要经历 网络→主节点内存→网络→从节点内存 这几个阶段,整个过程会耗费一定的时间。而在kafka中,主从同步会比Redis更加耗时,它需要经历 网络→主节点内存→主节点磁盘→网络→从节点内存→从节点磁盘 这几个阶段。对延时敏感的应用而言,主写从读的功能场景并不太适用。

点关注、不迷路

如果觉得文章不错,欢迎关注点赞收藏,你们的支持是我创作的动力,感谢大家。

如果文章写的有问题,请不要吝啬,欢迎留言指出,我会及时核查修改。

如果你还想更加深入的了解我,可以私信我。每天8:00准时推送技术文章,让你的上班路不在孤独,而且每月还有送书活动,助你提升硬实力!