Kafka 核心原理回顾:Topic 与 Partition 机制、Producer/Consumer 模型、Broker 与 Controller、ISR 与 ACK 机制

说实话,很多做实时数据采集的同学,对 Kafka 的理解停留在「发消息、收消息」的层面。一旦 Topic 数量上去、分区数调大、数据出现积压,就开始抓瞎了。

我个人习惯是,不管项目多急,先把 Kafka 这几个核心机制吃透。你想想看,元数据采集的本质就是跟 Topic、Partition、Broker 打交道,如果底层原理不清楚,后面配参数、调优、排错根本无从下手。

这一章,咱们就把 Kafka 的骨架拆开来看。不扯虚的,全是实战中天天要面对的东西。

2.1 Topic 与 Partition 机制

Topic 是 Kafka 里最基础的数据组织单元。你可以把它理解成数据库里的一张表,或者文件系统里的一个文件夹。但 Kafka 跟传统消息队列最大的区别在于——Topic 可以被拆成多个 Partition。

核心观点:Partition 是 Kafka 并行度的基本单位。一个 Topic 的 Partition 数越多,理论上吞吐量就越高。但凡事有代价——Partition 太多,元数据管理、Leader 选举、文件句柄的开销都会暴涨。

我在项目中遇到过这么个坑:有个业务方把 Topic 的分区数设成了 1000,结果集群 Broker 只有 3 台。每台 Broker 要管理 300 多个分区,Leader 频繁重选举,整个集群的 ISR 抖动得厉害。后来我强制要求:分区数不要超过 Broker 总数的 10 倍,除非你有充分的理由。

Partition 内部的数据是有序的,通过偏移量(Offset)来标识每条消息的位置。但跨 Partition 就不保证顺序了。这一点很多新手会搞混。

概念 说明 实战注意点
Topic 逻辑上的消息分类 命名规范要统一,建议用「业务线.数据域.表名」
Partition 物理上的存储分片 分区数 = max(消费者线程数, 预期吞吐量 / 单分区吞吐量)
Offset 分区内消息的唯一序号 Offset 不会全局唯一,只在分区内递增
Segment Partition 的物理文件片段 默认 1GB 滚动一次,频繁滚动会影响 IO

我的习惯:创建 Topic 时,先把分区数设成 Broker 数的 3 倍。比如 5 台 Broker,分区数先给 15。后面根据实际流量再调整。Kafka 2.4+ 支持在线扩分区,但缩分区不行,所以起步别贪多。

2.2 Producer 模型

Producer 负责把数据发到 Kafka。看起来简单,但里面的门道不少。

Producer 的核心流程是这样的:

  1. 应用调用 send() 方法
  2. 序列化器把对象转成字节数组
  3. 分区器决定数据发到哪个 Partition
  4. 数据进入缓冲区(默认 32MB)
  5. Sender 线程批量发送到 Broker

这里有个关键点——send() 方法是异步的。很多人以为调用 send() 就发出去了,其实数据还在缓冲区里。如果缓冲区满了,send() 会阻塞,或者抛异常。

我曾经遇到过一个线上事故:有个采集任务突然积压了几百万条数据,查了半天发现是 Producer 的 buffer.memory 设得太小,加上 max.block.ms 设成了 60 秒,导致应用线程全堵在 send() 上。后来我把缓冲区调到 128MB,问题就解决了。

Producer 还有一个重要的参数——acks。这个咱们放到后面跟 ISR 一起讲。

避坑指南:千万不要在 Producer 的回调函数里做耗时操作。我曾经见过有人在回调里写数据库,结果回调线程池被打满,整个 Producer 都卡死了。回调里只做轻量级的统计和日志,重操作另起线程。

2.3 Consumer 模型

Consumer 是消费端。Kafka 的 Consumer 跟传统消息队列最大的不同是——Consumer 主动拉数据,而不是 Broker 推数据。

这样做的好处很明显:Consumer 可以自己控制消费速度,不会把消费者压垮。但坏处是,如果 Consumer 拉得太慢,数据就会积压。

Consumer 的核心机制是「消费者组」(Consumer Group)。同一个组内的消费者共同消费一个 Topic,每个 Partition 只能被组内的一个消费者消费。

举个例子:Topic 有 6 个 Partition,消费者组里有 3 个 Consumer。理想情况下,每个 Consumer 分到 2 个 Partition。但如果 Consumer 数超过 Partition 数,多出来的 Consumer 就闲着。

场景 Partition 分配情况 说明
Consumer = Partition 1:1 分配 最理想的情况
Consumer < Partition 部分 Consumer 消费多个 Partition 吞吐量够用,但负载不均
Consumer > Partition 部分 Consumer 空闲 浪费资源,需要调整

我建议你在设计消费者组时,Consumer 数不要超过 Partition 数。多出来的 Consumer 不仅没用,还会增加 Rebalance 的开销。

说到 Rebalance,这是 Consumer 最让人头疼的地方。一旦有 Consumer 加入或退出,整个组都要重新分配 Partition。这个过程会暂停消费,如果 Topic 分区数多,Rebalance 可能持续几十秒。

我的经验:用静态消费组(Static Group Membership)可以避免不必要的 Rebalance。把 group.instance.id 设成固定值,Consumer 重启时就不会触发 Rebalance。这个功能在 Kafka 2.3+ 开始支持。

2.4 Broker 与 Controller

Broker 就是 Kafka 的服务器节点。一个集群通常有 3 台以上的 Broker。

Broker 之间不是完全对等的。有一个特殊的角色叫 Controller,它负责管理整个集群的元数据。

Controller 的职责包括:

  • 管理 Partition 的 Leader 选举
  • 处理 Broker 的上下线
  • 维护集群的元数据信息
  • 通知其他 Broker 更新元数据

Controller 是通过 Zookeeper 选举出来的。第一个在 Zookeeper 上创建临时节点的 Broker 就是 Controller。如果 Controller 挂了,其他 Broker 会重新选举。

我遇到过一个问题:集群里有个 Broker 网络不稳定,频繁上下线。每次上下线,Controller 都要触发 Leader 重选举,导致整个集群的写入延迟飙升。后来我们给 Broker 加了心跳超时检测,把 zookeeper.session.timeout.ms 从 6 秒调到了 18 秒,情况才稳定下来。

注意:Controller 是单点的。虽然挂了可以重新选举,但在选举期间,集群的元数据操作(比如创建 Topic、扩分区)会不可用。所以 Controller 所在的 Broker 要选硬件最好、网络最稳定的那台。

2.5 ISR 与 ACK 机制

这两个概念是 Kafka 可靠性的基石。说白了,就是「数据到底安不安全」的问题。

ISR(In-Sync Replicas),就是跟 Leader 保持同步的副本集合。只有 ISR 里的副本,才有资格在 Leader 挂了之后接替它。

Kafka 判断一个副本是否在 ISR 里,标准很简单:副本跟 Leader 的差距不能超过 replica.lag.time.max.ms(默认 10 秒)。如果副本落后太多,就会被踢出 ISR。

ACK 机制是 Producer 端的配置,用来控制数据写入的可靠性级别。

ACK 值 行为 可靠性 性能
acks=0 Producer 发完就不管了 最低,可能丢数据 最高
acks=1 Leader 写入成功就返回 中等,Leader 挂了可能丢 较高
acks=all 所有 ISR 副本都写入成功才返回 最高,不会丢数据 较低

我在做实时元数据采集时,一律用 acks=all。为什么?因为元数据丢了,后面所有数据治理、血缘分析全得完蛋。性能损失可以通过调整 batch.size 和 linger.ms 来弥补。

但要注意,acks=all 不代表 100% 不丢数据。如果 ISR 里只剩一个 Leader 副本,那跟 acks=1 其实没区别。所以还要配合 min.insync.replicas 参数,强制要求 ISR 里至少有几个副本。

推荐配置:

  • Topic 副本数:3
  • min.insync.replicas:2
  • Producer acks:all

这样即使一台 Broker 挂了,数据也不会丢。

2.6 核心知识体系总览

说了这么多,咱们用一张图把 Kafka 的核心机制串起来。这张图我每次培训都会用,你把它记在脑子里,后面学元数据采集会轻松很多。

Kafka 核心机制总览 Producer 异步发送 · 批量 · 压缩 Topic 逻辑分类 · 可拆分为多个 Partition Partition 0 Partition 1 Partition 2 Broker 集群 Broker 1 Leader: P0, P2 Follower: P1 Broker 2 Leader: P1 Follower: P0, P2 Broker 3 Follower: P0, P1, P2 Controller Consumer Group 主动拉取 · 组内负载均衡 ISR(同步副本集) Leader + 紧跟 Leader 的 Follower 落后太多会被踢出 ISR 只有 ISR 成员能成为新 Leader ACK 机制 acks=0:发完即忘 acks=1:Leader 确认 acks=all:ISR 全部确认 配合 min.insync.replicas 使用

这张图把 Kafka 的核心流程串起来了:Producer 发数据到 Topic 的 Partition,Partition 分布在多个 Broker 上,每个 Partition 有 Leader 和 Follower,ISR 保证数据一致性,Consumer 从 Leader 拉数据。Controller 负责协调整个集群。

嗯,这一章的内容就到这里。Kafka 的核心机制是后面所有元数据采集方案的基础。你把这些搞清楚了,后面讲 Kafka Connect、Schema Registry、元数据变更捕获的时候,就不会觉得吃力了。