2. Kafka核心概念与架构
理解Kafka的架构,关键不是背下八个名词,而是搞清楚一条消息从产生到被消费,中间经过了哪些角色、每个角色承担什么职责、它们之间如何协作。本章围绕Topic、Partition、Replica、Broker、Producer、Consumer、Controller、ZooKeeper/KRaft这条主线,把静态概念还原成动态流程。
一、Topic与Partition:逻辑分类与物理并行
Topic是消息的逻辑分类,比如order-events、user-behavior。Producer发消息时指定Topic,Consumer订阅Topic。但Topic本身不存储数据,真正存储和并行的是Partition。
一个Topic可以划分为多个Partition,每个Partition是一个有序、不可变的消息序列,消息以追加方式写入,每条消息获得一个单调递增的offset。Partition是Kafka并行度的基本单位:同一Consumer Group内,一个Partition同一时刻只能被一个Consumer实例消费;因此Partition数决定了该Group的最大并行消费能力。
假设创建Topic时指定3个Partition,消息按key哈希或轮询分配到不同Partition。若key为订单ID,相同订单的消息进入同一Partition,从而保证该订单内消息有序;若key为null,则轮询分配,全局有序性不再保证。这是实际设计时必须明确的取舍。
bin/kafka-topics.sh --create \
--topic order-events \
--partitions 3 \
--replication-factor 2 \
--bootstrap-server localhost:9092
执行后可用--describe查看分区分布:每个Partition有一个Leader和若干Follower,分布在不同的Broker上。这里已经引出下一个概念:Replica。
二、Replica:数据高可用的复制机制
Replica是Partition的副本。每个Partition有一个Leader副本和零个或多个Follower副本。Producer和Consumer只与Leader交互读写,Follower主动向Leader拉取消息保持同步。
副本集合中有一个ISR(In-Sync Replicas)列表,表示与Leader保持同步的副本。判断“保持同步”的依据是Follower的LEO(Log End Offset)与Leader的LEO差距未超过replica.lag.time.max.ms(默认30秒)。当Leader宕机,Controller会从ISR中选出一个新Leader,从而保证数据不丢失(在acks=all且min.insync.replicas满足时)。
举例:3副本、min.insync.replicas=2、Producer设置acks=all。此时消息必须写入Leader并同步到至少1个Follower才返回成功。若可用ISR只剩1个,写入会被拒绝,这是用可用性换一致性的典型配置。面试中常问“acks取值与可靠性关系”,答案就落在这里。
三、Broker与Controller:集群的存储与协调
Broker是Kafka服务实例,负责接收Producer写入、响应Consumer读取、存储Partition数据。多个Broker组成集群,每个Broker有唯一broker.id。Partition的Leader分散在不同Broker上,实现负载均衡。
Controller是集群中一个特殊的Broker角色,由选举产生。它负责Partition Leader选举、副本分配、Broker上下线处理等集群级管理。Controller不直接参与消息读写,而是维护集群元数据的一致性。当某个Broker宕机,Controller感知后为受影响Partition重新选主,并把新状态同步给其他Broker。
四、Producer与Consumer:写入与读取的两端
Producer发送消息时,先经过序列化器、分区器,确定目标Partition,再批量发送到该Partition的Leader。关键参数包括:acks(0/1/all)、retries、batch.size、linger.ms。批量越大、等待越久,吞吐越高但延迟越大,需要按业务权衡。
Consumer以Consumer Group为单位消费。Group内每个Partition分配给一个Consumer,分配由Group Coordinator协调。Consumer通过fetch.min.bytes、max.poll.records等参数控制拉取行为。offset提交方式分自动与手动,手动提交能更精确控制重复消费范围。
一个常见面试点:Consumer数量超过Partition数时,多出的Consumer会空闲。因此扩容Consumer前应先评估Partition数是否足够。
五、ZooKeeper与KRaft:元数据管理的演进
早期Kafka依赖ZooKeeper存储元数据:Broker注册、Topic配置、Controller选举、ACL等。ZooKeeper是独立集群,运维成本高,且Controller故障恢复依赖ZooKeeper,规模大时成为瓶颈。
KRaft模式用Kafka自身实现元数据管理,引入Controller Quorum(一组Controller节点),元数据以日志形式在Controller间复制。KRaft去掉了ZooKeeper依赖,支持更大规模集群和更快故障恢复。Kafka 3.3起KRaft可用于生产,新项目建议直接采用KRaft。
六、角色关系串联:一条消息的完整旅程
把上述角色串起来:Producer根据key选定Partition,向该Partition的Leader Broker发送消息;Leader写入本地日志,Follower拉取同步,ISR维护同步状态;消息持久化后,Consumer Group中的某个Consumer从Leader拉取消息,按offset消费并提交位。若Leader所在Broker宕机,Controller从ISR选出新Leader,Producer和Consumer通过元数据刷新感知新Leader并继续工作。整个过程由ZooKeeper或KRaft维护元数据一致性。
七、面试速查表
| 概念 | 核心职责 | 关键点 |
|---|---|---|
| Topic | 消息逻辑分类 | 不存储数据,由Partition承载 |
| Partition | 存储与并行单位 | 有序、offset递增、决定并行度 |
| Replica | 数据高可用 | Leader/Follower、ISR、选主 |
| Broker | 服务实例 | 存储Partition、读写请求 |
| Controller | 集群管理 | 选主、副本分配、故障处理 |
| Producer | 写入端 | 分区、批量、acks |
| Consumer | 读取端 | Group、offset、再均衡 |
| ZooKeeper/KRaft | 元数据管理 | KRaft为演进方向 |