关于kafka,你需要知道的

1、Apache Kafka是什么?

Apach Kafka是一款分布式流处理平台,用于实时构建流处理应用。

它有一个核心的功能广为人知,即作为企业级的消息引擎被广泛使用(通常也会称之为消息总线message bus)。

 

2、Kafka 的设计是什么样的?

Kafka 将消息以 topic 为单位进行归纳

将向 Kafka topic 发布消息的程序称为 producer,将预订 topics 并消费消息的程序称为 consumer

Kafka 以集群的方式运行,可以由一个或多个服务组成,每个服务叫做一个 broker,producers 通过网络将消息发送到 Kafka 集群,集群向消费者提供消息

消费者消费消息可以以分组group形式来消费,一个group内消费同一个消息时,只有一个成员会消费到消息

 

3、 Kafka 如何保证高可用?

Kafka 的基本架构组成是:由多个 broker 组成一个集群,每个 broker 是一个节点。

当创建一个topic 时,这个 topic 会被划分为多个 partition ,每个 partition 可以存在于不同的 broker上,每个 partition 只存放一部分数据。就是说一个 topic 的数据,是分散放在多个机器上的,每个机器就放一部分数据。

在 Kafka 0.8 版本之前,是没有 HA 机制的,当任何一个 broker 所在节点宕机了,这个 broker 上的 partition 就无法提供读写服务,所以这个版本之前, Kafka 没有什么高可用性可言。

在 Kafka 0.8 以后,提供了 HA 机制,就是 replica 副本机制。每个 partition 上的数据都会同步到其它机器,形成自己的多个 replica 副本。所有 replica 会选举一个 leader 出来,消息的生产者和消费者都跟这个 leader 打交道,其他 replica 作为 follower 。follower会从leader处pull数据, Kafka 负责均匀的将一个 partition 的所有 replica 分布在不同的机器上,提高了容错性。

拥有了 replica 副本机制,如果某个 broker 宕机了,这个 broker 上的 partition 在其他机器上还存在副本。如果这个宕机的 broker 上面有某个 partition 的 leader ,那么此时会从其follower 中重新选举一个新的 leader 出来,这个新的 leader 会继续提供读写服务,这就有达到了所谓的高可用性。

写数据的时候,生产者只将数据写入 leader 节点, leader 会将数据写入本地磁盘,接着其他follower 会主动从 leader 来拉取数据, follower 同步好数据了,就会发送 ack 给 leader ,leader 收到所有 follower 的 ack 之后,就会返回写成功的消息给生产者。

消费数据的时候,消费者只会从 leader 节点去读取消息,但是只有当一个消息已经被所有 follower都同步成功返回 ack 的时候,这个消息才会被消费者读到。

 

4、 Kafka 消息是采用 Pull 模式,还是 Push 模式?

生产者使用push模式将消息发布到Broker,消费者使用pull模式从Broker订阅消息。

 

5、Kafka 与传统消息系统之间的区别
  • Kafka 持久化日志,这些日志可以被重复读取和无限期保留

  • Kafka 是一个分布式系统:它以集群的方式运行,可以灵活伸缩,在内部通过复制数据提升容错能力和高可用性

  • Kafka 支持实时的流式处理

 

6、什么是消费者组?

消费者组是Kafka独有的概念。

Kafka允许你将同一份消息广播到多个消费者组里,一个消费者组中可以包含多个消费者,每个消费者有自己的ID(我们设置的),消息到达一个消费者组后,会被该消费者组下的随机一个成员进行消费。

也就是消息到达消费者组,一个消费者组下只有一个消费者可以消费到消息,其他消费者并不会接收到消息。

 

7、在Kafka中,ZooKeeper的作用是什么?

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

“存放元数据”是指主题分区的所有数据都保存在 ZooKeeper 中,且以它保存的数据为权威,其他“人” 都要与它保持对齐。

“成员管理” 是指 Broker 节点的注册、注销以及属性变更,等等。

“Controller 选举” 是指选举集群 Controller,而其他管理类任务包括但不限于主题删除、参数配置等。

 

8. 解释下Kafka中位移(offset)的作用

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

 

9、 kafka 为什么那么快?
  • Cache Filesystem Cache PageCache缓存

  • 顺序写 :由于现代的操作系统提供了预读和写技术,磁盘的顺序写大多数情况下比随机写内存还要快。

  • Zero-copy :零拷技术减少拷贝次数

  • Batching of Messages :批量处理。合并小的请求,然后以流的方式进行交互,直顶网络上限。

  • Pull 模式 :使用pull模式进行消息的获取消费,与消费端处理能力相符。

 

10、 kafka producer发送数据,ack为0,1,-1分别是什么意思?

1 (默认) 数据发送到Kafka后,经过leader成功接收消息的的确认,就算是发送成功了。如果leader宕机了,则会丢失数据

0 生产者将数据发送出去就不管了,不去等待任何返回。这种情况下数据传输效率最高,但是数据可靠性确是最低的。

-1 producer需要等待ISR中的所有follower都确认接收到数据后才算一次发送完成,可靠性最高。当ISR中所有Replica都向Leader发送ACK时,leader才commit,这时候producer才能认为一个请求中的消息都commit了。

 

11、. Kafka如何保证消息不丢失

对于一个消息队列,会有生产者 、 MQ 、 消费者这三个角色,在这三个角色数据处理和传输过程中,都有可能会出现消息丢失。

 

(1)生产者消息投递失败

对于生产者数据传输导致的数据丢失主常见情况是生产者发送消息给 Kafka ,由于网络等原因导致消息丢失,对于这种情况通过在 producer 端设置 acks=all 来处理,这个参数是要求 leader 接收到消息后,需要等到所有的 follower 都同步到了消息之后,才认为本次写成功了。如果没满足这个条件,生产者会自动不断的重试。从而保证消息100%投递成功,类似于rabbitmq的confirm机制中set ack handle 和set nack handle。

(2)Kafka 导致的消息丢失

Kafka 导致的数据丢失一个常见的场景就是 Kafka 某个 broker 宕机,,而这个节点正好是某个partition 的 leader 节点,这时需要重新重新选举该 partition 的 leader 。如果该 partition的 leader 在宕机时刚好还有些数据没有同步到 follower ,此时 leader 挂了,在选举某个follower 成 leader 之后,就会丢失一部分数据。

对于这个问题, Kafka 可以设置如下 4 个参数,来尽量避免消息丢失:

给 topic 设置 replication.factor 参数:这个值必须大于 1 ,要求每个 partition 必须有至少 2 个副本;

在 Kafka 服务端设置 min.insync.replicas 参数:这个值必须大于 1 ,这个参数的含义是一个leader 至少感知到有至少一个 follower 还跟自己保持联系,没掉队,这样才能确保 leader挂了还有一个 follower 节点。

在 producer 端设置 acks=all ,这个是要求每条数据,必须是写入所有 replica 之后,才能认为是写成功了;

在 producer 端设置 retries=MAX (很大很大很大的一个值,无限次重试的意思):这个参数的含义是一旦写入失败,就无限重试,卡在这里了。

(3)消费者丢失消息

消费者可能导致数据丢失的情况是:消费者获取到了这条消息后,还未处理, Kafka 就自动提交了offset ,这时 Kafka 就认为消费者已经处理完这条消息,其实消费者才刚准备处理这条消息,这时如果消费者宕机,那这条消息就丢失了。

消费者引起消息丢失的主要原因就是消息还未处理完 Kafka 会自动提交了 offset ,那么只要关闭自动提交 offset ,消费者在处理完之后手动提交 offset ,就可以保证消息不会丢失。但是此时需要注意重复消费问题,比如消费者刚处理完,还没提交 offset ,这时自己宕机了,此时这条消息肯定会被重复消费一次,这就需要通过生产者生产消息时添加一唯一ID,消费者消费消息时通过缓存查询等方式验证该消息是否已经被消费过来保证幂等性。

 

12、Kafka 如何保证消息的顺序性

在某些业务场景下,我们需要保证对于有逻辑关联的多条MQ消息被按顺序处理,比如对于某一条数据,正常处理顺序是 新增-更新-删除 ,最终结果是数据被删除;如果消息没有按序消费,处理顺序可能是 删除-新增-更新 ,最终数据没有被删掉,可能会产生一些逻辑错误。

对于如何保证消息的顺序性,主要需要考虑如下两点:

  • 如何保证消息在 Kafka 中顺序性;

  • 如何保证消费者处理消费的顺序性。

(1)如何保证消息在 Kafka 中顺序性

对于 Kafka ,如果我们创建了一个 topic ,默认有三个 partition 。生产者在写数据的时候,可以指定一个 key ,比如在订单 topic 中我们可以指定订单 id 作为 key ,那么相同订单 id 的数据,一定会被分发到同一个 partition 中去,而且这个 partition 中的数据一定是有顺序的。消费者从partition 中取出来数据的时候,也一定是有顺序的。通过制定 key 的方式首先可以保证在 kafka内部消息是有序的。

(2)如何保证消费者处理消费的顺序性

生产者在写消息的时候,可以指定一个 key,比如说我们指定了某个订单 id 作为 key,那么这个订单相关的数据,一定会被分发到同一个 partition 中去,而且这个 partition 中的数据一定是有顺序的。

消费者端创建多个内存队列,具有相同 key 的数据都路由到同一个内存队列;然后每个线程分别消费一个内存队列即可,这样就能保证顺序性。

 

13、描述下 Kafka 中的领导者副本(Leader Replica)和追随者副本(Follower Replica)的区别

Kafka副本当前分为领导者副本和追随者副本。只有Leader副本才能对外提供读写服务,响应Clients端的请求。

Follower副本只是采用拉(PULL)的方式,同步Leader副本中的数据,并且在Leader副本所在的Broker宕机后,随时准备应聘Leader副本。

但自Kafka 2.4版本开始,社区通过引入新的Broker端参数,允许Follower副本有限度地提供读服务。

 

14、分区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选举。

 

15、Kafka的哪些场景中使用了零拷贝(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特性了。

 

16、为什么Kafka不支持读写分离

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

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

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

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