2、Kafka核心概念:Topic、Partition、Offset、Broker、Producer、Consumer
Kafka 这六个核心概念,说白了就是它的骨架。你把这六个东西搞明白了,整个消息管道怎么跑的就清楚了。我刚开始接触 Kafka 的时候,也是被这些名词绕得头晕,后来在项目里踩了几次坑,才真正理解它们之间的关系。
一句话总结:Producer 往 Topic 里写消息,Topic 分成多个 Partition,每条消息在 Partition 内有唯一的 Offset,Broker 负责存储这些 Partition,Consumer 从 Partition 里按 Offset 拉取消息。
2.1 Topic —— 消息的逻辑分类
Topic 是 Kafka 里最上层的概念。你可以把它理解成一个消息的「分类标签」或者「主题」。比如在实时数仓里,我们通常会给每个业务线建一个 Topic:订单消息放 order_topic,用户行为放 user_behavior_topic,日志放 app_log_topic。
我个人习惯把 Topic 类比成数据库里的「表」。Producer 往 Topic 里写数据,Consumer 从 Topic 里读数据,大家各司其职。Topic 本身不存数据,它只是一个逻辑命名空间。
命名规范建议:我在项目中一般用 <业务线>_<数据源>_<数据类型> 的格式,比如 ods_order_mysql_binlog。这样一看名字就知道数据从哪来、干什么用。
2.2 Partition —— 并行与扩展的基石
Topic 下面真正干活的是 Partition。每个 Topic 可以分成多个 Partition,每个 Partition 是一个有序的、不可变的消息序列。说白了,Partition 才是真正存数据的地方。
为什么要分 Partition?两个原因:并行和扩展。
- 并行:多个 Consumer 可以同时消费不同 Partition,互不干扰。你想想看,如果只有一个 Partition,那 Consumer 再多也只能串行处理,吞吐量上不去。
- 扩展:Partition 可以分布在不同的 Broker 上。集群加机器,Partition 就能分散出去,存储和计算能力线性扩展。
我记得有一次做实时大屏项目,订单 Topic 只设了 3 个 Partition,结果双十一流量一上来,Consumer 根本来不及消费。后来我把 Partition 扩到 12 个,Consumer 也加到 6 台机器,吞吐量直接翻了 4 倍。嗯,这里要注意:Partition 数不是越多越好,太多会导致文件句柄和选举开销变大。
| Partition 数量 | 优点 | 缺点 |
|---|---|---|
| 少(1-3) | 管理简单,元数据小 | 并行度低,吞吐量受限 |
| 适中(4-16) | 吞吐量与资源平衡 | 需要合理规划 Consumer 数量 |
| 多(32+) | 极高并行度 | 文件句柄多,Leader 选举慢 |
我曾经踩过的坑:Partition 数一旦设定,虽然可以增加,但不能减少。减少 Partition 会导致数据重新分配,Kafka 不支持这个操作。所以建 Topic 时,我建议根据未来 6-12 个月的流量预估来设置 Partition 数,留点余量。
2.3 Offset —— 消息的唯一身份证
每个 Partition 内部,消息都有一个唯一的、递增的整数编号,这就是 Offset。你可以把它理解成消息在 Partition 里的「行号」。第一条消息 Offset 是 0,第二条是 1,以此类推。
Offset 的作用非常关键:它决定了 Consumer 从哪开始读。Consumer 消费完一条消息后,会提交当前 Offset,下次重启就从提交的位置继续消费。这就是 Kafka 能保证「至少一次」语义的基础。
核心要点:Offset 只在 Partition 内唯一,不同 Partition 的 Offset 是独立的。所以 Consumer 消费时,每个 Partition 都有自己的 Offset 记录。
我见过不少新手问:「为什么我重启 Consumer 后,消息重复消费了?」原因多半是 Offset 提交失败。Consumer 处理完消息但还没来得及提交 Offset 就挂了,重启后只能从上一次提交的位置重新拉取。这就是「至少一次」语义的代价。
2.4 Broker —— Kafka 的服务器节点
Broker 就是运行 Kafka 服务的机器。一个 Kafka 集群由多个 Broker 组成,每个 Broker 负责存储一部分 Partition 的数据。
Broker 之间通过 Zookeeper(或 KRaft)协调。比如某个 Broker 挂了,它上面的 Partition Leader 会被重新选举到其他 Broker 上。这个过程对 Producer 和 Consumer 是透明的——它们只跟 Topic 和 Partition 打交道,不关心数据具体存在哪台机器上。
我个人习惯把 Broker 想象成「仓库管理员」。你只管把货(消息)交给仓库(Topic),管理员会帮你把货分到不同的货架(Partition)上,还会在某个管理员请假时安排其他人顶班。
| Broker 角色 | 说明 |
|---|---|
| Controller | 集群中的「老大」,负责 Partition Leader 选举和元数据管理 |
| Partition Leader | 每个 Partition 的主副本,负责读写请求 |
| Partition Follower | 从 Leader 同步数据,Leader 挂了就顶上 |
2.5 Producer —— 消息的生产者
Producer 负责把消息发送到指定的 Topic。它有几个关键决策要做:
- 发到哪个 Partition?可以指定 Key,Kafka 根据 Key 的哈希值决定 Partition;也可以不指定,轮询分配。
- 要不要确认?
acks参数控制:acks=0发完不管,acks=1Leader 确认就行,acks=all所有副本都确认才算成功。 - 重试策略?网络抖动时自动重试,但要设置重试次数和间隔。
我的经验:实时数仓场景下,我一般用 acks=all 配合 enable.idempotence=true,保证数据不丢不重。虽然延迟会高一点点,但数据一致性更重要。
2.6 Consumer —— 消息的消费者
Consumer 从 Topic 的 Partition 里拉取消息。注意是「拉取」不是「推送」——Consumer 主动去 Broker 拿数据,这样 Consumer 可以根据自己的处理能力控制消费速度。
Consumer 通常以「组」的形式出现(Consumer Group)。组内每个 Consumer 负责消费不同的 Partition,实现负载均衡。如果某个 Consumer 挂了,组内其他 Consumer 会接管它的 Partition——这就是 Rebalance。
我曾经在项目中遇到过一个问题:Consumer 处理逻辑里有远程 RPC 调用,耗时不稳定,导致 Rebalance 频繁触发。后来我把 max.poll.interval.ms 调大,并且把 RPC 调用改成异步,才稳定下来。
避坑指南:Consumer 的 poll() 循环里不要做耗时操作。默认 max.poll.interval.ms 是 5 分钟,如果你处理一条消息花了 6 分钟,Kafka 会认为这个 Consumer 死了,触发 Rebalance。我建议把耗时操作异步化,或者调大超时时间。
2.7 六个概念如何协同工作?
我们用一个实时数仓的典型场景串一下:
- 业务系统产生一条订单数据,通过 Producer 发送到
order_topic。 order_topic有 6 个 Partition,分布在 3 台 Broker 上。Producer 根据订单 ID 的哈希值,把消息发到 Partition-3。- Partition-3 的 Broker 收到消息,给它分配 Offset = 1024,并写入磁盘。
- 实时计算任务的 Consumer 从 Partition-3 拉取消息,读到 Offset=1024 的订单数据,进行处理。
- 处理完成后,Consumer 提交 Offset=1025,表示这条消息已经消费过了。
你看,六个概念各司其职,配合得严丝合缝。理解了这个流程,Kafka 的消息管道原理你就掌握了七八成。