Skip to content

Kafka 面试题

Kafka 基础

Q1: Kafka 的核心概念?

┌─────────────────────────────────────────────────────────────────┐
│                      Kafka 核心架构                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   Producer ──▶ Topic ──▶ Partition ──▶ Consumer Group            │
│                              │                                  │
│                              ├── Partition 0                    │
│                              ├── Partition 1                    │
│                              └── Partition 2                    │
│                                                                  │
│   每个 Partition 有多个副本,分布在不同 Broker                     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
概念说明
Producer消息生产者,负责发送消息
Consumer消息消费者,负责接收消息
Consumer Group消费者组,同一组内消息只被消费一次
Topic消息主题,用于分类消息
Partition分区,实现水平扩展
BrokerKafka 服务节点
Replica副本,保证高可用
Offset消息偏移量,记录消费位置

Q2: Kafka 的工作流程?

┌─────────────────────────────────────────────────────────────────┐
│                      Kafka 消息流程                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   Producer                    Broker                    Consumer  │
│                                                                  │
│   ┌─────────┐               ┌─────────┐              ┌─────────┐│
│   │ 发送消息 │──▶ 写入 ──▶│ Leader  │──▶ 同步 ──▶│ 消费消息 ││
│   │ 到 Topic │               │ Partition│              │          ││
│   └─────────┘               └─────────┘              └─────────┘│
│                                 │                                  │
│                                 ▼                                  │
│                           ┌─────────┐                           │
│                           │ Follower│                           │
│                           │ Partition│                           │
│                           └─────────┘                           │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

写入流程

  1. Producer 发送消息到 Topic
  2. 根据分区策略发送到对应 Partition
  3. Leader Partition 接收消息
  4. Follower Partition 同步消息
  5. Consumer 订阅 Topic 并消费

Q3: Kafka 的分区策略?

1. 指定 partition

java
producer.send(new ProducerRecord<>("topic", partition, key, value));

2. 按 key 哈希

java
producer.send(new ProducerRecord<>("topic", key, value));
// key 相同 → 相同 partition(保证顺序)

3. 轮询(无 key)

java
producer.send(new ProducerRecord<>("topic", value));
// 依次写入各个 partition

消息可靠性

Q4: 如何保证消息不丢失?

┌─────────────────────────────────────────────────────────────────┐
│                      消息可靠性等级                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   acks=0  ⭐☆☆☆☆  最快,可能丢失                             │
│   acks=1  ⭐⭐⭐☆☆  平衡,默认选择                             │
│   acks=all ⭐⭐⭐⭐⭐ 最安全,性能最低                          │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

1. Producer 端

java
// 配置
props.put("acks", "all");  // 所有副本确认
props.put("retries", 3);   // 重试次数
props.put("enable.idempotence", true);  // 开启幂等性

2. Broker 端

properties
# 分区副本数 >= 2
min.insync.replicas=2
replication.factor=3

3. Consumer 端

java
// 手动提交 offset
consumer.commitSync();

Q5: Kafka 的 ACK 机制?

bash
# acks=0
# 不等待 Leader 确认
# 最快,可能丢失消息
# 适用于日志收集等可容忍丢失的场景

# acks=1
# Leader 确认收到即可
# 平衡选项
# Leader 宕机可能丢失消息

# acks=all (或 -1)
# 所有 ISR 副本确认
# 最安全
# 性能最差

ISR(In-Sync Replicas)

┌─────────────────────────────────────────────────────────────────┐
│                         ISR 概念                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   ISR = 与 Leader 保持同步的副本集合                             │
│                                                                  │
│   min.insync.replicas = 2  # ISR 最小数量                      │
│                                                                  │
│   如果 ISR 数量 < min.insync.replicas:                        │
│   - Broker 拒绝写入                                            │
│   - 抛出 NotEnoughReplicasException                            │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

消息顺序性

Q6: Kafka 如何保证消息顺序?

单 Partition 顺序保证

java
// 按 key 发送到同一分区,保证同一 key 消息顺序
producer.send(new ProducerRecord<>("order-topic", orderId, message));

// 消费者按偏移量顺序消费
while (true) {
    ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
    for (ConsumerRecord<String, String> record : records) {
        // 按顺序处理
    }
}

顺序性场景

┌─────────────────────────────────────────────────────────────────┐
│                      消息顺序场景                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   订单流程(必须有序):                                          │
│   1. 创建订单 → 2. 支付 → 3. 发货 → 4. 签收                   │
│                                                                  │
│   解决方式:                                                     │
│   - 相同订单 ID 发到同一 Partition                               │
│   - 单 Partition 单 Consumer                                    │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

多 Partition 只能保证单 Partition 内有序


消费者组

Q7: 消费者组机制?

┌─────────────────────────────────────────────────────────────────┐
│                    消费者组分区分配                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   Topic: my-topic (3 partitions)                                │
│                                                                  │
│   Consumer Group A:                                              │
│   ┌─────────┐  ┌─────────┐  ┌─────────┐                        │
│   │C1 (P0) │  │C2 (P1) │  │C3 (P2) │                        │
│   └─────────┘  └─────────┘  └─────────┘                        │
│   每个 Consumer 消费一个 Partition                               │
│                                                                  │
│   Consumer Group B:                                              │
│   ┌─────────┐  ┌─────────┐  ┌─────────┐                        │
│   │C4 (P0,1)│  │C5 (P1) │  │C4 (P2) │                        │
│   └─────────┘  └─────────┘  └─────────┘                        │
│   2个 Consumer 消费3个 Partition                                │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

特点

  • 同一组内 Consumer 不能消费同一 Partition
  • 不同组可以重复消费同一消息
  • Partition 数量决定最大并行度

Q8: 消费者 offset 管理?

自动提交(默认)

java
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "5000");

手动提交

java
props.put("enable.auto.commit", "false");

while (true) {
    ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));

    for (ConsumerRecord<String, String> record : records) {
        process(record);
    }

    // 手动提交
    consumer.commitSync();
}

精确一次语义

┌─────────────────────────────────────────────────────────────────┐
│                      消息传递语义                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   at most once(最多一次)                                      │
│   - 异步提交,可能丢失消息                                       │
│   - Consumer 先提交 offset,再处理消息                           │
│                                                                  │
│   at least once(至少一次)                                     │
│   - 同步提交,可能重复消费                                       │
│   - Consumer 先处理消息,再提交 offset                           │
│                                                                  │
│   exactly once(精确一次)                                      │
│   - 事务机制                                                   │
│   - Producer + Consumer 事务                                    │
│   - 用于支付等关键场景                                          │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

分区副本

Q9: 分区副本机制?

┌─────────────────────────────────────────────────────────────────┐
│                      Partition 副本分布                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   Partition 0:                                                   │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │  Leader: Broker-1   ISR: [Broker-1, Broker-2]          │  │
│   │  Follower: Broker-2 (同步中)                            │  │
│   └─────────────────────────────────────────────────────────┘  │
│                                                                  │
│   Partition 1:                                                   │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │  Leader: Broker-2   ISR: [Broker-2, Broker-3]          │  │
│   │  Follower: Broker-3 (同步中)                            │  │
│   └─────────────────────────────────────────────────────────┘  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

LEO 和 HW

┌─────────────────────────────────────────────────────────────────┐
│                      LEO 和 HW                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   LEO (Log End Offset):                                        │
│   - 当前分区写入消息的最大 offset                               │
│                                                                  │
│   HW (High Watermark):                                         │
│   - 已同步到所有副本的消息最大 offset                          │
│   - Consumer 只能看到 HW 之前的消息                            │
│   - 保证消息一致性                                             │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Kafka 实战

Q10: 如何实现延迟队列?

方式1:使用延时插件

java
// kafka-delayed-message 插件
producer.send(new ProducerRecord<>("delayed-topic", message), delay);

方式2:外部延迟系统 + 定时任务

java
// 发送消息时记录到 Redis ZSet
redisTemplate.opsForZSet().add("delay:queue",
    messageId,
    System.currentTimeMillis() + delayMs);

// 定时任务扫描 ZSet
Set<String> readyMessages = redisTemplate.opsForZSet()
    .rangeByScore("delay:queue", 0, System.currentTimeMillis());

方式3:RabbitMQ 的延迟插件


Q11: 如何实现消息幂等?

Producer 端幂等

java
props.put("enable.idempotence", true);
// 开启后,Producer 自动实现幂等发送
// 每个消息有一个 PID(Producer ID)+ Sequence Number
// 相同 PID + Sequence Number 的消息会被去重

Consumer 端幂等

java
// 业务去重
@RedisCache(expire = 3600)
public Result processMessage(Message msg) {
    // 消息 ID 去重
    if (processedMessageIds.contains(msg.getId())) {
        return Result.success();  // 已处理,直接返回
    }
    // 处理业务逻辑
    processedMessageIds.add(msg.getId());
    return Result.success();
}

Q12: Kafka 高并发优化?

Producer 端优化

java
// 1. 批量发送
props.put("batch.size", 16384);      // 批量大小
props.put("linger.ms", 10);           // 等待时间

// 2. 压缩
props.put("compression.type", "snappy");  // LZ4 / Snappy / GZIP

// 3. 并发发送
List<Future<RecordMetadata>> futures = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
    futures.add(producer.send(new ProducerRecord<>("topic", value)));
}

Consumer 端优化

java
// 1. 提高并行度
consumer.subscribe(Arrays.asList("topic"));
// 分区数 = 最大 Consumer 并行度

// 2. 批量消费
while (true) {
    ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));

    List<Message> batch = new ArrayList<>();
    for (ConsumerRecord<String, String> record : records) {
        batch.add(parse(record));
    }
    processBatch(batch);  // 批量处理
}

Kafka vs RabbitMQ

Q13: Kafka 和 RabbitMQ 的区别?

对比KafkaRabbitMQ
吞吐量极高(10万+/s)中等(万级/s)
延迟
消息顺序单 Partition 有序队列内有序
消息回溯支持不支持
消息持久化支持支持
消息路由基础丰富
消息确认ACK 机制多种确认模式
死信队列支持支持
延迟队列需插件原生支持
适用场景日志、大数据业务消息

选择建议

  • 日志收集、大数据:Kafka
  • 业务消息、复杂路由:RabbitMQ
  • 高并发、事件驱动:Kafka
  • 事务消息:RocketMQ

Q14: 为什么 Kafka 吞吐量高?

┌─────────────────────────────────────────────────────────────────┐
│                      Kafka 高吞吐原因                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   1. 顺序写入                                                    │
│      - 消息追加到文件末尾                                        │
│      - 磁盘顺序 IO,顺序读写速度接近内存                         │
│                                                                  │
│   2. 零拷贝技术                                                  │
│      - sendfile() 系统调用                                      │
│      - 数据直接在内核空间传输,不经过用户空间                     │
│                                                                  │
│   3. 批量处理                                                    │
│      - 消息批量发送                                              │
│      - 消息批量压缩                                              │
│                                                                  │
│   4. 分区并行                                                    │
│      - 多 Partition 并行处理                                     │
│                                                                  │
│   5. 高效序列化                                                  │
│      - Protobuf / Avro 序列化                                   │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

常见问题

Q15: 如何处理消息积压?

原因

  • Consumer 消费能力不足
  • Producer 发送速度过快
  • Consumer 故障

解决方案

java
// 1. 增加 Consumer 并行度
// 提高 Consumer 实例数,但不能超过 Partition 数

// 2. 提高消费并发度
@KafkaListener(topics = "topic", concurrency = "3")
public void consume(String message) {
    // 多线程处理
    executor.execute(() -> process(message));
}

// 3. 批量消费
consumer.poll(Duration.ofMillis(100));
// 一次处理多条消息

// 4. 临时扩容
// 增加 Consumer 实例数

Q16: 如何保证不丢消息不重复消费?

不丢消息

  1. Producer:acks=all + 重试
  2. Broker:replication.factor >= 3
  3. Consumer:手动提交 offset

不重复消费

  1. 业务去重表(基于消息 ID)
  2. 幂等操作(Redis Set)
  3. 分布式事务

总结

Kafka 高频面试知识点

知识点面试频率
核心概念(Topic/Partition/Consumer Group)⭐⭐⭐⭐⭐
消息可靠性(ACK 机制)⭐⭐⭐⭐⭐
消费者组机制⭐⭐⭐⭐
分区副本机制⭐⭐⭐⭐
消息顺序性⭐⭐⭐⭐
Offset 管理⭐⭐⭐⭐
高吞吐原因⭐⭐⭐⭐
消息积压处理⭐⭐⭐