前言
在当今大数据与实时处理的时代浪潮下,Kafka 作为一款卓越的分布式流处理平台,正发挥着举足轻重的作用。身为架构师,深入掌握 Kafka 的核心概念与设计理念,是构建高效、可靠数据处理系统的关键所在。接下来,就让我们一同开启 Kafka 的探索之旅。
一、Kafka 是什么
Kafka 传统上被定义为一个分布式的基于发布 / 订阅模式的消息队列,主要应用于大数据实时处理领域。而其最新定义为一个开源的分布式事件流平台,被数千家公司用于高性能数据管道、流分析、数据集成和关键任务应用。它最初由 LinkedIn 开发,现由 Apache 基金会维护。
从本质上讲,Kafka 就像是一个超级数据中转站,允许不同的应用程序发布(生产)和接收(消费)数据。它将数据组织成主题(Topic),每个主题可以看作是一个类别,比如 “用户行为日志”“交易记录” 等。生产者将消息发送到特定的主题,而消费者则从感兴趣的主题中获取消息进行处理。 Kafka 架构图 1:整体架构示意

如图所示,生产者、Kafka 集群和消费者构成了基本的数据流动架构。

二、Kafka 的核心组件
(一)生产者(Producer)
生产者负责将消息发布到 Kafka 主题。它可以是各种类型的应用程序,比如 Web 应用后端收集用户操作日志,然后作为生产者将日志消息发送到 Kafka 的 “用户日志” 主题。生产者在发送消息时,可以根据不同的策略选择将消息发送到主题的哪个分区中。例如,通过轮询的方式依次将消息发送到各个分区,或者根据消息的某个属性(如用户 ID)进行哈希计算,将具有相同属性值的消息发送到同一个分区,以保证特定业务逻辑下消息的顺序性。 生产者发送消息示例图

主线程处理
创建消息:
KafkaProducer在主线程中创建消息,将消息封装成ProducerRecord对象,该对象包含主题、分区、键、值等信息。拦截器处理:消息经过生产者拦截器(
ProducerInterceptors) ,可在此进行消息过滤、内容修改等准备工作 。比如过滤掉不符合格式要求的消息。序列化:通过序列化器(
Serializer)将消息的键和值对象转换成字节数组,便于在网络中传输。分区:利用分区器(
Partitioner)确定消息要发送到主题的哪个分区。若发送时指定了分区,分区器直接返回该分区;若未指定,可通过轮询、哈希等策略确定分区 。例如根据消息的某个属性(如用户 ID )进行哈希计算,相同属性值的消息发往同一分区。消息累加:处理后的消息被发送到消息累加器(
RecordAccumulator) 。它是一个双端队列,按分区缓存消息,每个分区下又有多个ProducerBatch,消息以ProducerBatch形式组织,便于批量发送,提升性能 。
Sender 线程处理
创建请求:
Sender线程不断轮询RecordAccumulator,当发现有消息需要发送时,创建ProducerRequest,将多个消息打包在一个请求中,实现批量发送。缓存请求:若创建的请求过多,会将部分请求缓存在
InFlightRequests中 。InFlightRequests按node(即 Kafka 集群中的节点)分类管理请求,每个node下可缓存多个Request,并通过相关参数(如max.in.flight.requests.per.connection)控制缓存数量。提交发送:将准备好的请求提交给
Selector,由Selector负责与 Kafka 集群建立网络连接并发送请求。接收响应:
Selector从 Kafka 集群接收响应(response) 。处理响应:
Sender线程处理响应,若消息成功写入 Kafka 集群,通知RecordAccumulator更新对应消息状态;若失败,根据配置进行重试等操作 。清理工作:最后进行一些清理工作,例如清理已成功发送且不再需要的消息相关资源等 。
(二)消费者(Consumer)
消费者从 Kafka 主题中订阅并消费消息。消费者可以单独工作,也可以组成消费组(Consumer Group)。在消费组模式下,同一消费组内的消费者会共同消费一个主题的消息,每个分区的消息只会被组内的一个消费者处理,从而实现负载均衡和并行处理。比如在一个电商系统中,多个订单处理服务组成一个消费组,共同消费 “新订单” 主题的消息,每个服务负责处理一部分订单,大大提高了订单处理的效率。 消费者组消费示意图


Kafka 消费者通过 poll 来获取消息,但是获取消息时并不是立刻返回结果,需要考虑两个因素:
消费者通过 customer.poll(time) 中设置等待时间
Broker 会等待累计一定量数据,然后发送给消费者。这样可以减少网络开销。

poll 除了获取消息外,还有其他作用:
发送心跳信息。
消费者通过向被指派为群组协调器的 Broker 发送心跳来维护他和群组的从属关系,当机器宕掉后,群组协调器触发再均衡。
(三)代理(Broker)
Broker 是 Kafka 集群中的服务器节点,负责存储和传输消息。一个 Kafka 集群由一个或多个 Broker 组成。当生产者发送消息时,消息会被存储在 Broker 上;消费者消费消息时,也是从 Broker 中读取。Broker 之间会相互协作,进行数据的复制和同步,以保证数据的高可用性和容错性。例如,当某个 Broker 出现故障时,其他 Broker 可以接替它的工作,确保整个系统的正常运行。 Broker 集群架构图

整体架构组件
Producer(生产者):负责将数据发布到 Kafka 的 Topic(主题)中。生产者可决定消息发往 Topic 的哪个 Partition(分区),能通过轮询等策略实现多个服务器间的负载均衡。比如,在一个电商系统中,订单创建相关的消息由生产者发送到 “订单消息” Topic。
Broker(代理):Kafka 集群的服务器节点,日志的分区分布其上,每个分区有一个 leader 副本和零个或多个 follower 副本 。leader 处理分区的读写请求,follower 被动同步 leader 数据。当 leader 宕机,follower 中一台会成为新 leader,实现集群负载均衡。如 Broker 1 上 Topic A 的 Partition 0 是 leader,负责接收读写请求,Broker 2 和 Broker 3 上对应的 Partition 0 副本为 follower,进行数据同步。
Consumer(消费者):以 Consumer Group(消费组)形式存在,发布到 Topic 的每条记录会分配给订阅消费组中的一个消费者。若消费者实例在同一消费组,消息记录负载均衡到各实例;若在不同消费组,消息记录广播到所有消费组 。例如 Consumer Group 1 中的 Consumer 1 和 Consumer 2 会共同消费 Topic A 的消息。
Zookeeper Cluster(Zookeeper 集群):用于管理和协调 Kafka 集群,保存集群元数据和状态信息 。Kafka 集群的重要操作如 Broker 加入退出、分区分配、选举控制器 Broker 等都依赖它。
核心机制
Controller Broker 选举机制
选举过程:Kafka 集群启动时,每个 Broker 尝试在 Zookeeper 上创建 /controller 临时节点并写入自己的 brokerid ,仅一个 Broker 创建成功成为 Controller(控制器)。若 Controller 故障,Zookeeper 删除对应节点,其他 Broker 竞争创建节点以选举新控制器。
职责:管理集群内所有分区和副本状态 。如分区 leader 副本故障时,选举新 leader;ISR 集合变化时,通知所有 Broker 更新元数据;增加 Topic 分区数量时,告知其他节点。
Leader Partition 选举机制
相关概念:
AR(Assigned Replicas):分区中的所有副本(存活和不存活的)。
ISR(In - Sync Replicas):AR 中存活且能与 leader 正常同步的分区副本 。副本需满足与 ZK 和 leader 保持稳定联系、能正常同步且数据滞后不多等条件才能进入 ISR。
OSR(Out - Sync Replicas):从 ISR 中踢出的节点,即服务有问题、延迟过多的副本。
选举过程:控制器感知到分区 leader 副本所在的 Broker 出现故障时,按 AR 排名顺序,靠前且在 ISR 中的副本优先成为 leader。
Leader Partition 自平衡机制
原理:默认 Kafka 尽量将 leader 分区分散到不同 Broker,避免压力集中。但选举后平衡可能被打破,控制器定期检查,当 Broker 的分区数量高于阈值,触发自平衡 。
注意事项:该操作涉及大量数据同步转移,可能丢消息,业务要求高时建议关闭。
消费者消费消息的 offset 记录机制:消费者定期将消费分区的 offset 提交给 Kafka 内部 Topic(_consumer_offsets ) ,Kafka 定期清理该 Topic 消息,保留最新数据。该 Topic 默认 50 个分区,可通过增加机器应对高并发。
消费者 Rebalance 机制
触发条件:消费组内消费者数量变化、动态给 Topic 增加分区、消费组订阅更多 Topic 等 。
过程:
选出组协调器:每个消费组选一个 Broker 作为组协调器,负责监控消费者存活情况(心跳) 。消费者启动时发送查找请求找组协调器并建立连接,选择方式为 hash (consumer group id) % __consumer_offsets 主题的分区数。
加入消费组:消费者向组协调器发送加入请求并处理响应,组协调器选第一个加入的消费者作为 leader(消费组协调器),让其制定分区方案。
同步消费组:消费者 leader 通过组协调器发送同步请求,组协调器将分区方案发给各消费者,消费者据此连接指定分区的 leader broker 并消费消息。
影响:Rebalance 过程中消费者无法消费消息,影响 TPS,应避免高峰期重平衡,且只针对 subscribe(不指定分区消费),assign(指定分区消费)不触发。
(四)主题(Topic)
Topic 类似于消息队列的逻辑通道,用于分类和存储消息。它是一个逻辑概念,每个 Topic 可以被看作是一类特定数据流的集合。比如在一个社交媒体平台中,可能会有 “用户动态发布”“点赞评论”“关注关系变更” 等不同的 Topic,分别用于存储相关类型的消息。通过将不同类型的消息划分到不同的 Topic,方便了数据的管理和不同应用程序对特定类型消息的消费。 Topic 分类示意图

一个 Topic 被划分为多个 Partition,每个 Partition 又被划分为多个 Segment。消息首先被发送到 Topic 下的某个 Partition 中,然后按照顺序追加到该 Partition 对应的 Segment 中。
例如,对于一个名为 “user_events” 的 Topic,它可能被分为 3 个 Partition:“user_events - Partition 0”“user_events - Partition 1”“user_events - Partition 2”。每个 Partition 都有自己独立的消息序列和 Offset 编号,并且可以分布在不同的 Broker 上,以实现数据的分布式存储和并行处理。而每个 Partition 中的消息又会根据一定的规则被划分到不同的 Segment 中,每个 Segment 包含一个或多个消息,以及对应的索引文件,用于快速定位和检索消息。
(五)分区(Partition)
每个主题可以划分为多个分区,Partition 是 Kafka 并行处理的基本单元。分区实际上是一个有序的、不可变的消息队列。将一个主题划分为多个分区有诸多好处,一方面可以实现消息的并行处理,提升系统的吞吐量。例如,当有大量生产者同时向一个主题发送消息时,这些消息可以被分散到不同的分区进行存储和处理,避免了单个队列的性能瓶颈。另一方面,分区也有助于实现数据的分布式存储,不同的分区可以存储在不同的 Broker 上,提高了系统的可扩展性。 分区并行处理示意图

(六)偏移量(Offset)
Offset 是消息在分区中的唯一标识,用于跟踪消费进度。每个分区中的消息都有一个递增的 Offset 值,消费者通过记录 Offset 来标记自己已经消费到了哪个位置。这样,当消费者下次重新启动或者在消费过程中出现故障恢复后,可以根据之前记录的 Offset 继续从上次的位置开始消费,确保了消息消费的准确性和连续性。例如,在一个实时数据分析系统中,消费者需要对源源不断的用户行为数据进行分析,通过 Offset 就可以保证在系统出现故障时,不会遗漏任何数据的分析处理。 Offset 跟踪消费进度示意图
(七)ZooKeeper
ZooKeeper 用于管理和协调 Kafka 集群中的节点,保存集群的元数据和状态信息。Kafka 集群的许多重要操作,如 Broker 的加入和退出、分区的分配、选举控制器 Broker 等,都依赖于 ZooKeeper。可以说,ZooKeeper 就像是 Kafka 集群的 “大管家”,确保整个集群的稳定运行和有序管理。例如,当一个新的 Broker 加入集群时,ZooKeeper 会将这个信息通知给其他 Broker,并协调进行相关的元数据更新和分区分配调整。 ZooKeeper 协调 Kafka 集群示意图
三、Kafka 的核心设计理念
(一)高吞吐量和低延迟
顺序写入磁盘:Kafka 采用顺序写入磁盘的方式来存储消息。与传统的随机写入磁盘相比,顺序写入具有更高的性能。在大量数据写入的场景下,随机写入会导致磁盘的寻道时间增加,而顺序写入则可以避免频繁的寻道操作,大大提高了写入速度。例如,当生产者向 Kafka 写入海量的日志数据时,顺序写入磁盘的方式能够保证数据快速持久化到磁盘,从而实现高吞吐量。 顺序写入与随机写入对比图
零拷贝技术:Kafka 利用零拷贝技术减少数据在内存中的拷贝次数。传统的数据传输过程中,数据往往需要在用户空间和内核空间之间多次拷贝,这会消耗大量的 CPU 资源和时间。而零拷贝技术可以直接将数据从磁盘缓存传输到网络接口,避免了不必要的内存拷贝,从而降低了延迟,提高了数据传输的效率。例如,在消费者从 Kafka 读取消息并发送到其他系统的过程中,零拷贝技术能够让消息更快地到达目的地,实现低延迟的数据处理。 零拷贝技术原理图
(二)持久性和可靠性
日志文件存储:Kafka 将消息以日志文件的形式持久化存储在磁盘上。每个分区对应一个或多个日志段文件,消息会按照顺序追加到日志段中。即使系统出现故障,重启后也可以从磁盘上的日志文件中恢复数据,保证了数据的持久性。 Kafka 日志文件存储结构示意图
复制机制:Kafka 通过分区复制机制确保数据的可靠性。每个分区可以有多个副本,其中一个副本作为领导者(Leader),其他副本作为追随者(Follower)。生产者发送的消息会首先被写入领导者副本,然后领导者副本会将消息同步给追随者副本。当领导者副本所在的 Broker 出现故障时,Kafka 会从追随者副本中选举出新的领导者,继续提供服务,保证了数据的不丢失和系统的高可用性。 Kafka 分区复制示意图
(三)可扩展性
水平扩展:Kafka 可以通过添加更多的 Broker 节点来实现水平扩展。当系统的负载增加,现有的 Broker 节点无法满足性能要求时,可以方便地添加新的 Broker 到集群中。新加入的 Broker 会自动参与到集群的工作中,分担原有 Broker 的负载,从而提高整个系统的处理能力。例如,在一个电商促销活动期间,订单量急剧增加,通过添加 Broker 节点,可以轻松应对大量的订单消息处理。 Kafka 水平扩展示意图
分区扩展:对于单个主题,可以通过增加分区数量来提高其处理能力。当一个主题的消息量持续增长,现有的分区无法满足吞吐量需求时,可以动态地为该主题增加分区。新增加的分区会分布到不同的 Broker 上,进一步提升了系统的并行处理能力和可扩展性。 Kafka 分区扩展示意图
(四)容错性
Broker 故障处理:如前文所述,Kafka 通过分区复制和领导者选举机制来处理 Broker 故障。当某个 Broker 发生故障时,ZooKeeper 会检测到这一情况,并协助集群进行故障转移。从追随者副本中选举出新的领导者,保证数据的正常读写,使得整个系统在部分节点出现故障的情况下仍能继续运行。 Broker 故障处理流程图

网络故障处理:Kafka 在设计上考虑了网络故障的情况。生产者和消费者在与 Broker 进行通信时,会进行重试操作。当网络出现短暂中断或者延迟时,客户端会自动尝试重新连接 Broker,确保消息的发送和消费不会因为网络问题而中断。同时,Kafka 集群内部的节点之间也会通过心跳机制来检测网络连接状态,及时发现并处理网络故障。 Kafka 网络故障处理示意图
评论区