跳到主要内容

Kafka 核心原理

问题

Kafka 的架构是什么样的?为什么 Kafka 吞吐量这么高?Producer 和 Consumer 的工作流程是怎样的?

答案

Kafka 架构总览

核心概念

概念说明
BrokerKafka 服务器节点,负责存储和转发消息
Topic消息的逻辑分类,类似数据库的表
PartitionTopic 的物理分片,实现并行读写
Replica分区副本,Leader 负责读写,Follower 同步数据
Producer消息生产者,将消息发送到 Topic
Consumer消息消费者,从 Topic 拉取消息
Consumer Group消费者组,组内消费者分摊 Partition
Offset消息在 Partition 中的唯一位置标识
ISRIn-Sync Replicas,与 Leader 保持同步的副本集合
ZooKeeper/KRaft元数据管理(Kafka 3.x+ 推荐 KRaft 模式去 ZK)

Partition 与消息存储

每个 Partition 是一个有序的、不可变的消息序列,消息追加到末尾(append-only)。

Kafka 的磁盘存储结构:

topic-partition/
├── 00000000000000000000.log # 消息日志文件(Segment)
├── 00000000000000000000.index # 稀疏偏移量索引
├── 00000000000000000000.timeindex # 时间戳索引
├── 00000000000005367851.log # 新的 Segment
├── 00000000000005367851.index
└── 00000000000005367851.timeindex

为什么 Kafka 吞吐量高

技术说明
顺序写磁盘追加写入,避免随机 I/O,磁盘顺序写速度接近内存
Page Cache利用 OS 页缓存,减少用户态与内核态之间的拷贝
零拷贝sendfile() 系统调用,数据从磁盘直接到网卡,不经过用户空间
分区并行多 Partition 多 Consumer 并行消费
批量发送Producer 端攒批发送,减少网络请求次数
压缩支持 gzip/snappy/lz4/zstd 消息压缩
零拷贝原理

传统方式:磁盘 → 内核缓冲区 → 用户缓冲区 → Socket 缓冲区 → 网卡(4 次拷贝)

零拷贝(sendfile):磁盘 → 内核缓冲区 → 网卡(2 次拷贝,DMA 直传)

Kafka Consumer 读取消息时就是通过零拷贝实现高效传输。

Producer 发送流程

关键参数

参数说明建议值
acks确认模式:0/1/-1(all)高可靠用 all
retries失败重试次数3 或更多
batch.size批次大小16384(16KB)
linger.ms等待攒批时间5-100ms
buffer.memory缓冲区总大小33554432(32MB)
max.in.flight.requests.per.connection未确认请求数保证顺序设为 1

Consumer 消费流程

Consumer 消费示例
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "order-group");
props.put("enable.auto.commit", "false"); // 手动提交 offset
props.put("key.deserializer", StringDeserializer.class);
props.put("value.deserializer", StringDeserializer.class);

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList("order-topic"));

while (true) {
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
for (ConsumerRecord<String, String> record : records) {
// 处理消息
processOrder(record.value());
}
// 手动提交 offset,确保消息真正处理完再提交
consumer.commitSync();
}

Consumer Group 与 Rebalance

  • 一个 Partition 只能被同一 Consumer Group 内的一个 Consumer 消费
  • Consumer 数量 > Partition 数量时,多余的 Consumer 空闲
  • Consumer 加入/离开会触发 Rebalance(重新分配 Partition)

Rebalance 的三种分配策略:

策略说明
Range按 Topic 的 Partition 范围分配(默认)
RoundRobin轮询分配所有 Partition
Sticky尽量保持原有分配不变,减少迁移

ISR 机制与副本同步

  • ISR(In-Sync Replicas):与 Leader 保持同步的副本列表
  • Follower 落后超过 replica.lag.time.max.ms(默认 30s)会被踢出 ISR
  • Leader 选举只从 ISR 中选取(unclean.leader.election.enable=false

常见面试问题

Q1: Kafka 为什么不用内存队列而用磁盘?

答案

  1. 顺序写磁盘性能极高:顺序写磁盘速度可达 600MB/s,接近内存的随机写速度
  2. 利用 Page Cache:OS 自动将磁盘数据缓存到内存,读写效率接近纯内存
  3. 持久化保障:消息写入磁盘后不怕进程崩溃丢失数据
  4. 支持消息回溯:消费者可以通过 offset 重新消费历史消息
  5. 海量堆积能力:磁盘容量远大于内存,可以堆积数十 TB 消息

Q2: Kafka 如何保证消息不丢失?

答案

需要 Producer、Broker、Consumer 三端配合:

配置说明
Produceracks=allISR 全部写入才确认
Producerretries > 0发送失败重试
Brokermin.insync.replicas=2ISR 最少副本数
Brokerunclean.leader.election.enable=false禁止非 ISR 副本当选 Leader
Consumer手动提交 offset处理完再提交,避免自动提交丢消息

Q3: Kafka 的 acks=0、1、-1 有什么区别?

答案

  • acks=0:Producer 不等待任何确认就返回。最快但可能丢消息
  • acks=1:Leader 写入本地 log 就返回确认。Leader 宕机可能丢数据
  • acks=-1(all):等待 ISR 中所有副本都写入才返回。最可靠但最慢

生产环境高可靠场景用 acks=all + min.insync.replicas=2

Q4: Consumer Group 的 Rebalance 是什么?有什么问题?

答案

Rebalance 是 Consumer Group 内重新分配 Partition 的过程,触发条件:

  • Consumer 加入或离开组
  • Consumer 心跳超时
  • Topic 的 Partition 数变化

问题:Rebalance 期间所有 Consumer 暂停消费(Stop The World),在大量 Partition 时耗时较长。

优化

  • 增大 session.timeout.msheartbeat.interval.ms,减少误判
  • 使用 Sticky 分配策略,减少不必要的 Partition 迁移
  • Kafka 2.4+ 支持 增量 Rebalance(CooperativeStickyAssignor),不再全部暂停

Q5: Kafka 和传统消息队列(RabbitMQ)的本质区别是什么?

答案

维度KafkaRabbitMQ
定位分布式流平台传统消息中间件
存储磁盘持久化,可回溯消费后删除
消费模式Pull(拉取)Push(推送)+ Pull
吞吐量百万级 TPS万级 TPS
消息路由Topic + PartitionExchange + Queue(灵活路由)
消息顺序Partition 内有序Queue 内有序
适用场景日志、大数据、事件流业务消息、任务队列

相关链接