Kafka
阅读提示
这页题量很大,建议先吃透 4 条主线:Kafka 是什么 -> 为什么快 -> 可靠性怎么保 -> 顺序与幂等如何落地。
面试回答时先给结论,再给关键参数(如 acks、ISR、offset),最后补一个业务场景。
推荐训练法
- 第一遍只看问题标题,先建立知识地图。
- 第二遍优先掌握“可靠性、顺序性、重复消费”三块高频追问。
- 第三遍用 2 分钟口述 1 题,训练可表达性。
什么是消息中间件?(了解)
- 消息中间件是基于队列与消息传递技术,在网络环境中为应用系统提供同步或异步、可靠的消息传输的支撑性软件系统。
- 消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。
Kafka是什么?有什么作用?(了解)
- Kafka 是一个分布式的流式处理平台,它以高吞吐、可持久化、可水平扩展、支持流数据处理等多种特性而被广泛使用

主要功能体现于三点:
消息系统:kafka与传统的消息中间件都具备系统解耦、冗余存储、流量削峰、缓冲、异步通信、扩展性、可恢复性等功能。与此同时,kafka还提供了大多数消息系统难以实现的消息顺序性保障及回溯性消费的功能。
存储系统:kafka把消息持久化到磁盘,相比于其他基于内存存储的系统而言,有效的降低了消息丢失的风险。这得益于其消息持久化和多副本机制。也可以将kafka作为长期的存储系统来使用,只需要把对应的数据保留策略设置为“永久”或启用主题日志压缩功能。
流式处理平台:kafka为流行的流式处理框架提供了可靠的数据来源,还提供了一个完整的流式处理框架,比如窗口、连接、变换和聚合等各类操作。
Kafka中有哪几个组件?
- 主题:Kafka主题是一堆或一组消息。
- 生产者:在Kafka,生产者发布通信以及向Kafka主题发布消息。
- 消费者:Kafka消费者订阅了一个主题,并且还从主题中读取和处理消息。
- 经纪人:在管理主题中的消息存储时,我们使用Kafka Brokers。
Kafka Replicas是怎么管理的?(了解)

- AR:分区中的所有 Replica 统称为 AR
- ISR:所有与 Leader 副本保持一定程度同步的Replica(包括 Leader 副本在内)组成 ISR
- OSR:与 Leader 副本同步滞后过多的 Replica 组成了 OSR
- Leader 负责维护和跟踪 ISR 集合中所有 Follower 副本的滞后状态,当 Follower 副本落后过多时,就会将其放入 OSR 集合,当 Follower 副本追上了 Leader 的进度时,就会将其放入 ISR 集合。
- 默认情况下,只有 ISR 中的副本才有资格晋升为 Leader。
kafka的消费者是pull(拉)还是push(推)模式,这种模式有什么好处?
- Kafka 遵循了一种大部分消息系统共同的传统的设计:producer 将消息推送到 broker,consumer 从broker 拉取消息。
- 优点:pull模式消费者自主决定是否批量从broker拉取数据,而push模式在无法知道消费者消费能力情况下,不易控制推送速度,太快可能造成消费者奔溃,太慢又可能造成浪费。
- 缺点:如果 broker 没有可供消费的消息,将导致 consumer 不断在循环中轮询,直到新消息到到达。为了避免这点,Kafka 有个参数可以让 consumer阻塞知道新消息到达(当然也可以阻塞知道消息的数量达到某个特定的量这样就可以批量发送)。
kafka维护消息状态的跟踪方法(了解)
- Kafka中的Topic 被分成了若干分区,每个分区在同一时间只被一个 consumer 消费。然后再通过offset进行消息位置标记,通过位置偏移来跟踪消费状态。相比其他一些消息队列使用“一个消息被分发到consumer 后 broker 就马上进行标记或者等待 customer 的通知后进行标记”的优点是,避免了通信消息发送后,可能出现的程序奔溃而出现消息丢失或者重复消费的情况。同时也无需维护消息的状态,不用加锁,提高了吞吐量。
kafka判断一个节点还活着的有那两个条件?
- 节点必须维护和 ZooKeeper 的连接,Zookeeper 通过心跳机制检查每个节点的连接
- 如果节点是个 follower,他必须能及时的同步 leader 的写操作,延时不能太久
讲一讲 kafka 的 ack 的三种机制
- request.required.acks 有三个值 0 1 -1(all),具体如下:
- 0:生产者不会等待 broker 的 ack,这个延迟最低但是存储的保证最弱当 server 挂掉的时候就会丢数据。
- 1:服务端会等待 ack 值 leader 副本确认接收到消息后发送 ack 但是如果 leader挂掉后他不确保是否复制完成新 leader 也会导致数据丢失。
- -1(all):服务端会等所有的 follower 的副本受到数据后才会受到 leader 发出的ack,这样数据不会丢失。
kafka 分布式(不是单机)的情况下,如何保证消息的顺序消费?
- Kafka 中发送 1 条消息的时候,可以指定(topic, partition, key) 3 个参数,partiton 和 key 是可选的。
- Kafka 分布式的单位是 partition,同一个 partition 用一个 write ahead log 组织,所以可以保证FIFO 的顺序。不同 partition 之间不能保证顺序。因此你可以指定 partition,将相应的消息发往同 1个 partition,并且在消费端,Kafka 保证1 个 partition 只能被1 个 consumer 消费,就可以实现这些消息的顺序消费。
- 另外,你也可以指定 key(比如 order id),具有同 1 个 key 的所有消息,会发往同 1 个partition,那这样也实现了消息的顺序消息。
kafka 如何不消费重复数据?比如扣款,我们不能重复的扣。
- 幂等性生产者:使用Kafka的幂等性生产者功能,确保即使发送多次,消息也只被记录一次。这通过唯一的生产者ID和序列号实现,防止了生产端的重复。
- 事务支持:Kafka事务特性允许生产者确保消息要么全部成功提交,要么全部失败回滚,适用于需要精确一次性处理的操作。
- 消费者端幂等处理:设计消费逻辑,使其对重复消息具有幂等性,如使用唯一键去重或数据库的唯一键约束,确保重复消息处理结果一致。
- 手动提交Offset:消费者处理消息后手动提交Offset,确保只有在消息被成功处理后才更新消费位置,避免未提交Offset导致的重复消费。
partition的数据文件(offffset,MessageSize,data)(了解)
partition的数据文件是存储消息的核心结构,每个数据文件主要包含三个关键元素:offset、MessageSize和data。
offset:这是消息在partition中的唯一标识符,类似于消息的“序号”或“位置”。offset是一个64位的长整型数值,用于确保消息的顺序性和定位能力。消费者可以通过指定offset来精确地找到分区中的某条消息,或者从某个位置开始消费消息。
MessageSize:这个字段记录了消息内容data的大小,即消息体的字节长度。通过MessageSize,Kafka可以快速地跳过或定位到消息体的起始位置,提高消息处理的效率。
data:这是消息的实际内容,可以是文本、JSON、二进制数据等任何格式。data字段存储了生产者发送到Kafka的具体信息,消费者通过读取这些数据来进行后续处理。
在Kafka中,partition被划分为多个segment文件,每个segment文件包含一定数量的消息。这些文件以顺序读写的方式进行操作,提高了磁盘利用率和读写性能。同时,Kafka为每个segment文件建立了索引文件,通过稀疏索引的方式记录了消息的offset和其在物理文件中的位置,进一步加速了消息的查找速度。
kafka如何实现数据的高效读取?(顺序读写、分段命令、二分查找)
Kafka实现数据的高效读取主要依赖于其独特的设计,包括顺序读写、分段存储和二分查找等机制。具体来说:
顺序读写:Kafka采用顺序写入的方式,新消息会被追加到已有消息的末尾。这种写入模式减少了磁盘I/O操作的随机访问,大大提高了写入效率。同样,读取时也是顺序读取,这与磁盘的物理特性相契合,进一步提升了读取性能。
分段存储:Kafka将每个partition划分为多个segment,每个segment包含固定大小的数据和对应的索引文件。这样设计避免了管理大文件的复杂性,同时方便了对旧数据的清理。每个segment文件独立存储,使得数据管理和维护更加高效。
二分查找:Kafka为每个segment维护了一个索引文件,其中存储了消息的offset和物理位置的映射关系。当需要查找特定offset的消息时,Kafka会利用二分查找算法在索引文件中快速定位消息所在的segment和数据文件中的具体位置,从而实现了高效的数据访问。
此外,Kafka还通过内存缓存、消息压缩等技术手段进一步提升了数据的读取效率。内存缓存使得Kafka可以将索引文件的部分内容保留在内存中,加速查找操作;而消息压缩则减少了磁盘和网络带宽的使用,使得数据在传输和存储时更加高效。
Kafka 消费者端的 Rebalance 操作什么时候发生?(了解)
在Kafka中,消费者端的Rebalance操作主要发生在以下几种情况,以确保消费者组能够公平且高效地分配订阅主题的分区:
消费者组成员变化:当有新消费者加入消费者组或现有消费者离开(无论是正常关闭、崩溃还是长时间未发送心跳被判定为“死亡”)时,会触发Rebalance。这是因为消费者组的成员变化可能导致分区分配不再均衡。
订阅主题分区数变化:如果消费者组订阅的任一主题的分区数发生变化(如分区增加或减少),也会触发Rebalance。这是为了根据新的分区情况重新分配消费者与分区之间的关系。
消费者组订阅变化:当消费者组订阅的主题列表发生变化,比如消费者取消了对某些主题的订阅,同样可能引发Rebalance。
协调者故障或变化:负责管理消费者组的协调者(Coordinator)如果发生故障,或者消费者组被重新分配给了另一个协调者,也可能触发Rebalance。
Rebalance过程是一个协调消费者组内成员重新分配分区的过程,它确保了消费者组能够动态地适应变化,保持高效的消息处理能力。然而,频繁的Rebalance可能会对性能产生负面影响,因此在设计和使用Kafka时,需要合理设置相关参数和配置,以减少不必要的Rebalance操作。
Kafka的那些设计让它有如此高的性能?
- 顺序写入与零拷贝技术:与传统的数据库系统不同,Kafka采用顺序写入的方式,这大大减少了磁盘寻道时间,提高了写入性能。同时,Kafka利用零拷贝技术,减少了数据传输过程中CPU和内存的开销,进一步提升了性能。
- 分区与副本机制:Kafka将数据分散到多个分区中,每个分区都可以独立处理数据写入和读取请求,充分利用了集群的计算和存储能力。同时,每个分区都有多个副本,既保证了数据的可靠性,又通过异步复制方式减少了数据同步的开销。
- 批量操作与压缩:Kafka支持批量写入和压缩功能,批量写入减少了网络传输和磁盘IO的次数,而压缩功能则降低了磁盘存储空间的使用,并减少了数据传输的开销。
- 高效的消费者组机制:消费者组允许多个消费者并行地消费同一个分区的消息,提高了并发处理能力。同时,Kafka支持多种消费模式,如发布订阅模式和队列模式,以适应不同的业务需求。
- 可扩展的架构:Kafka的分布式架构可以轻松通过添加更多的节点来扩展处理能力。这种水平扩展的能力使得Kafka能够应对大规模数据处理和实时流处理场景。
Kafka为什么不支持读写分离?
- 设计哲学:Kafka的设计目标是高吞吐量、低延迟和可扩展性。它采用发布-订阅模型,通过单一的Broker集群处理读写请求,这种架构简洁高效,避免了读写分离带来的复杂性。
- 数据一致性:在读写分离架构中,主从数据库之间存在复制延迟,这可能导致读操作读取到过时的数据,从而影响数据一致性。而Kafka通过分区和副本机制确保数据的一致性和可靠性,每个分区有多个副本,其中一个副本作为领导者处理读写请求,其他副本作为追随者同步数据,这种设计保证了数据的强一致性。
- 性能考量:Kafka已经通过优化读写性能来满足实时数据流处理的需求。在Kafka中,读写操作通常是连续的,且读取操作的性能已经非常高。因此,引入读写分离并不会显著提升Kafka的性能,反而可能增加系统的复杂性。
- 适用场景:Kafka主要用于实时数据流处理和日志聚合等场景,这些场景通常对数据的一致性和可靠性要求较高。读写分离架构更适合于读取密集型的应用场景,如在线事务处理系统,与Kafka的适用场景不完全匹配。
分区Leader选举策略有几种?
- 默认选举策略:Kafka默认采用一种基于ISR(In-Sync Replicas,同步副本集)的选举策略。当Leader副本故障时,Kafka会从ISR中选择一个新的副本作为Leader。通常,这个新Leader是具有最高偏移量(即数据最“领先”的副本),以保证数据的一致性和可靠性。
- ISR优先选举:这是一种优化策略,旨在提高ISR中副本被选举为Leader的概率。在选举过程中,Kafka会优先考虑ISR中的副本,只有当ISR副本不可用或数量不足时,才会考虑其他副本。这种方式有助于减少选举成本和延迟,提升分区性能。
- 自定义选举策略:虽然Kafka没有直接提供多种预定义的选举策略供用户选择,但用户可以根据自己的需求和场景,通过实现自定义的选举逻辑来灵活应对特定情况。自定义选举策略可以根据副本的状态、健康状况、负载情况等因素进行决策,以满足分布式系统的特定需求。
请简述下你在哪些场景下会选择 Kafka?
- 实时数据流处理:Kafka擅长处理大规模、高吞吐量的实时数据流。当需要实时收集、处理和分析大量数据时,比如日志聚合、监控数据、用户行为追踪等,Kafka是一个理想的选择。
- 微服务间通信:在微服务架构中,服务间需要高效、可靠的通信机制。Kafka作为消息中间件,可以提供解耦、异步和可靠的通信方式,帮助微服务实现松耦合和高内聚。
- 事件驱动架构:Kafka支持事件驱动架构,允许系统根据事件进行响应和处理。这对于需要实时处理事件、触发后续操作或进行复杂工作流协调的应用场景非常有用。
- 日志和数据湖:Kafka可以作为日志和数据湖的存储引擎,为大数据分析、机器学习等提供数据源。它的顺序存储和高效读取特性使得处理大规模数据变得更加容易和高效。
- 分布式系统的消息总线:在需要构建分布式系统的消息总线时,Kafka可以提供高可用、可扩展和容错的消息传递服务,确保系统组件之间的通信畅通无阻。
请谈一谈 Kafka 数据一致性原理
- 副本机制:每个分区的数据都会被复制到多个副本中,包括一个领导者副本和多个追随者副本。所有读写操作都由领导者副本处理,追随者副本则从领导者副本同步数据。这种方式确保了数据的高可用性和容错性。
- ISR列表:ISR是指与领导者副本保持同步的副本集合。只有处于ISR中的副本才能参与到消息的写入和读取过程中。当某个副本与领导者副本的同步延迟超过一定阈值后,就会被踢出ISR,直到同步恢复正常。这样可以确保只有可靠的副本参与到数据的读写操作,提高数据的一致性和可靠性。
- 幂等性和事务性:Kafka还引入了幂等性机制来确保消息的精确一次传递,通过生产者ID和序列号来实现。同时,Kafka支持事务性操作,允许生产者发送一批消息作为一个事务,确保这批消息要么全部成功,要么全部失败,进一步保障了数据的一致性和可靠性。
生产者发送消息有哪些模式?
- 发后即忘(fire-and-forget):它只管往 Kafka 里面发送消息,但是不关心消息是否正确到达,这种方式的效率最高,但是可靠性也最差,比如当发生某些不可充实异常的时候会造成消息的丢失
- 同步(sync):producer.send()返回一个Future对象,调用get()方法变回进行同步等待,就知道消息是否发送成功,发送一条消息需要等上个消息发送成功后才可以继续发送
- 异步(async):Kafka支持 producer.send() 传入一个回调函数,消息不管成功或者失败都会调用这个回调函数,这样就算是异步发送,我们也知道消息的发送情况,然后再回调函数中选择记录日志还是重试都取决于调用方
发送消息的分区策略有哪些?

- 1.轮询:依次将消息发送该topic下的所有分区,如果在创建消息的时候 key 为 null,Kafka 默认采用这种策略。
- 2.key 指定分区:在创建消息是 key 不为空,并且使用默认分区器,Kafka 会将 key 进行 hash,然后根据hash值映射到指定的分区上。这样的好处是 key 相同的消息会在一个分区下,Kafka 并不能保证全局有序,但是在每个分区下的消息是有序的,按照顺序存储,按照顺序消费。在保证同一个 key 的消息是有序的,这样基本能满足消息的顺序性的需求。但是如果 partation 数量发生变化,那就很难保证 key 与分区之间的映射关系了。
- 3.自定义策略:实现 Partitioner 接口就能自定义分区策略。
- 4.指定 Partiton 发送
Kafka 支持读写分离吗?为什么?(了解)
Kafka 是不支持读写分离的,那么读写分离的好处是什么?主要就是让一个节点去承担另一个节点的负载压力,也就是能做到一定程度的负载均衡,而且 Kafka 不通过读写分离也可以一定程度上去实现负载均衡。
但是对于 Kafka 的架构来说,读写分离有两个很大的缺点
1.数据不一致的问题:读写分离必然涉及到数据的同步,只要是不同节点之间的数据同步,必然会有数据不一致的问题存在。
2.延时问题:由于 Kafka 独特的数据处理方式,导致如果将数据从一个节点同步到另一个节点必然会经过主节点磁盘和从节点磁盘,对一些延时性要求较高的应用来说,并不太适用
那 Kafka 是怎么去实现负载均衡的?(了解)
- Kafka 的负责均衡主要是通过分区来实现的,我们知道 Kafka 是主写主读的架构,如下图:

- 共三个 broker ,里面各有三个副本,总共有三个 partation, 深色的是 leader,浅色的是 follower,上下灰色分别代表生产者和消费者,虚线代表 follower 从 leader 拉取消息。
- 我们从这张图就可以很明显的看出来,每个 broker 都有消费者拉取消息,每个 broker 也都有生产者发送消息,每个 broker 上的读写负载都是一样的,这也说明了 kafka 独特的架构方式可以通过主写主读来实现负载均衡。
Kafka 的可靠性是怎么保证的?

1.acks:这个参数用来指定分区中有多少个副本收到这条消息,生产者才认为这条消息是写入成功的,这个参数有三个值:
1.acks = 1,默认为1。生产者发送消息,只要 leader 副本成功写入消息,就代表成功。这种方案的问题在于,当返回成功后,如果 leader 副本和 follower 副本还没有来得及同步,leader 就崩溃了,那么在选举后新的 leader 就没有这条消息,也就丢失了。
2.acks = 0。生产者发送消息后直接算写入成功,不需要等待响应。这个方案的问题很明显,只要服务端写消息时出现任何问题,都会导致消息丢失。
3.acks = -1 或 acks = all。生产者发送消息后,需要等待 ISR 中的所有副本都成功写入消息后才能收到服务端的响应。毫无疑问这种方案的可靠性是最高的,但是如果 ISR 中只有leader 副本,那么就和 acks = 1 毫无差别了。
2.消息发送的方式:我们可以通过同步或者异步获取响应结果,失败做重试来保证消息的可靠性。
3.手动提交位移:默认情况下,当消费者消费到消息后,就会自动提交位移。但是如果消费者消费出错,没有进入真正的业务处理,那么就可能会导致这条消息消费失败,从而丢失。我们可以开启手动提交位移,等待业务正常处理完成后,再提交offset。
分区数越多越好吗?吞吐量就会越高吗?(了解)
- 在一定条件下,分区数的数量是和吞吐量成正比的,分区数和性能也是成正比的
客户端/服务器端需要使用的内存就越多(超过了一定限度,就会对性能造成影响)
- 服务端在很多组件中都维护了分区级别的缓存,分区数越大,缓存成本也就越大。
- 消费端的消费线程数是和分区数挂钩的,分区数越大消费线程数也就越多,线程的开销成本也就越大
- 生产者发送消息有缓存的概念,会为每个分区缓存消息,当积累到一定程度或者时间时会将消息发送到分区,分区越多,这部分的缓存也就越大
什么情况下 kafka 会丢失消息?
Kafka 有三次消息传递的过程:生产者发消息给 Broker,Broker 同步消息和持久化消息,Broker 将消息传递给消费者。
1.生产者发送数据:
当 acks 为 0,只要服务端写消息时出现任何问题,都会导致消息丢失。
当 acks 配置为 1 时,生产者发送消息,只要 leader 副本成功写入消息,就代表成功。这种方案的问题在于,当返回成功后,如果 leader 副本和 follower 副本还没有来得及同步,leader 就崩溃了,那么在选举后新的 leader 就没有这条消息,也就丢失了。
2.Broker 存储数据:kafka 通过 Page Cache 将数据写入磁盘。
Page Cache 就是当往磁盘文件写入的时候,系统会先将数据流写入缓存中,但是什么时候将缓存的数据写入文件中是由操作系统自行决定。所以如果此时机器突然挂了,也是会丢失消息的。
3.消费者消费数据:在开启自动提交 offset 时,只要消费者消费到消息,那么就会自动提交偏移量,如果业务还没有来得及处理,那么消息就会丢失。
