CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Kafka 消息队列入门/课时/核心概念
RawBlame
课时目录12 节

Kafka 消息队列入门

  1. 01消息队列是什么
  2. 02核心概念
  3. 03Docker 运行 Kafka
  4. 04生产者
  5. 05消费者组
  6. 06Spring Kafka
  7. 07消息格式
  8. 08投递语义
  9. 09Kafka Streams 入门
  10. 10监控与 lag
  11. 11Kafka vs RabbitMQ
  12. 12综合练习

核心概念

Broker、Topic、Partition、Offset、Consumer Group。

35 分钟

核心概念

这一课你将能做到

  1. 用自己的话解释 Broker、Topic、Partition、Offset、Consumer Group、副本(ISR),并指出「顺序保证」落在哪一层
  2. 画出「3 分区 Topic + 两组消费者」的 ASCII 图,标出谁在分摊、谁在完整重读
  3. 写出带 orderId 作 key 的 ProducerRecord,说明为什么同一订单的事件能保持分区内有序

为什么要学

后面写 Producer / Consumer / Spring Kafka 时,配置项全是这些名词。若把 Topic 当成「一个大队列」、把 Offset 当成「全局游标」,就会在 rebalance、重复消费、乱序上反复踩坑。

这些概念同时也是 Kafka 面试的地基题:面试官问「分区内有序怎么实现」「消费者数和分区数的关系」「offset 存在哪」,本质上都在验证你有没有把这张图画进脑子。本课先建立 追加日志 + 分区并行 + 组内位点 的图像;安装与代码课都建立在这张图上。

人话:Kafka = 很多本按页编号的日记本(分区),写的人按页追加,每本书可以复印多份(副本),读者用书签(offset)记下读到哪一页。

先建立图像

Cluster
  └── Broker(Kafka 进程,可多台)
        └── Topic: order-events          ← 逻辑频道名
              ├── Partition 0: [m0][m1][m2]...  offset 0,1,2...
              ├── Partition 1: [m0][m1]...
              └── Partition 2: [m0]...
        (每个分区在多 Broker 上有副本:1 Leader + N Follower)

Consumer Group "notify-svc"(负载均衡)
  实例 A ← 读 P0, P1(组内互斥)
  实例 B ← 读 P2

Consumer Group "audit-svc"(独立订阅)
  实例 C ← 再读 P0+P1+P2 全部分区(自己独立的 offset)
概念人话记住一句
Broker存分区数据的 Kafka 节点进程/机器,不是 Topic 本身
Topic逻辑频道,如 order-events名字空间,下面才分分区
PartitionTopic 的物理分片分区内有序;跨分区无全局序
Offset分区内消息序号每个「组 × 分区」一份进度
Consumer Group同 group.id 的消费者集合组内分摊;组间互不影响
副本/ISR同一分区在多 Broker 的拷贝Leader 写,Follower 追;跟得上的叫 ISR
Key生产者附带的键同 key 进同一分区 → 保序
与本站其他组件的分工:
  MySQL  → 业务真相(订单行)
  Redis  → 热缓存 / 轻通知
  Kafka  → 「发生了什么」的可重放事件流

跟着做

步骤 1:把五个词写成「人话卡片」

在笔记上为 Broker / Topic / Partition / Offset / Consumer Group 各写一句人话(禁止只抄英文)。自检标准:能否不看表格,口头向同事解释「offset 是分区局部的,不是整个 Topic 一个号」。

步骤 2:在纸上复刻分区图

照上面 ASCII 自己手画一遍,并标注:

  • notify 组两个实例各管哪些分区
  • audit 组为什么还能再读同一 Topic

应看到:消息不会被「第一个组」删掉;第二组有自己的书签。

步骤 3:推演 key 与顺序

假设同一订单连续发三条:Created → Paid → Shipped,key 都是 orderId=1001。在笔记写:它们会进几个分区?消费时能否保证 Created 先于 Shipped?

答案方向:同 key → 哈希到同一分区 → 分区内追加有序;换 key 或无 key 则不保证订单级顺序。

步骤 4:算「几个消费者能真正干活」

题目:Topic 有 4 个分区,Consumer Group 启动 6 个实例。问:同时有几个实例分到分区?多出来的在干什么?

应看到:最多 4 个干活,多出的空闲等 rebalance;消费者数 > 分区数没有额外并行。反过来,4 分区只起 1 个实例,则一人扛四分区。

步骤 5:对照官方术语页

打开 Kafka Introduction — Concepts,核对 Topics / Partitions / Consumers 三段与你的人话卡片是否一致。补一句官方强调点:「日志按分区追加,消费者各自维护偏移。」

步骤 6:写一条带 key 的概念发送

import org.apache.kafka.clients.producer.ProducerRecord;

String topic = "coderoadmap.order-events";
String orderId = "1001"; // key → 分区路由
String json = "{\"event\":\"OrderCreated\",\"orderId\":\"1001\"}";

ProducerRecord<String, String> record =
        new ProducerRecord<>(topic, orderId, json);
// 无 key 写法:new ProducerRecord<>(topic, json)
// → 消息轮询打散到各分区,丢订单级顺序

应看到:API 形状简单,但 key 的选择是业务顺序策略,不是装饰字段。

讲清楚要点

  1. 因为消息追加写在分区日志里,所以Kafka 的心智是「可回溯的日志」,不是「取走即删的队列」——这直接决定了多订阅者与重放能力。
  2. 因为顺序只在分区内保证,所以需要订单级顺序时必须稳定路由到同一分区(通常靠 key),跨分区无法承诺先后。
  3. 因为offset 按「消费者组 × 分区」记录(存在内部 Topic __consumer_offsets),所以两组可独立重放;组内重启则从已提交位点继续,书签不存应用内存里。
  4. 因为组内一个分区同时只分配给一个消费者,所以水平扩展上限 ≈ 分区数;想加消费者先想分区数够不够。
  5. 因为副本解决的是「Broker 宕机数据不丢」,分区解决的是「并行与顺序」,所以两者是正交概念:分区是横向切,副本是纵向拷。
  6. 因为Broker 只持久化字节与元数据,所以schema 校验、业务幂等、字段演进都在应用层(后续消息格式/投递课展开)。

你可能会懵的地方

  1. 「Offset 是不是全局自增 id?」 不是。offset 每个分区从 0 起;比较消费进度必须带上 (topic, partition, offset) 三元组。说「我消费到 offset=100」而不说分区,等于没说。

  2. 「多加消费者一定更快?」 超过分区数后多余实例空转(只能等别人挂了顶上)。要提速先加分区(并评估 key 热点是否倾斜),再加实例。

  3. 「两个服务共用同一个 group.id 图省事?」 会变成竞争消费,审计可能收不全。规则一句话:一个职责一个 group.id。

  4. 「无 key 是不是更均匀、更好?」 均匀 ≠ 正确。需要实体有序时必须带稳定 key;如果担心大客户热点,可以业务上组合 key(如 shopId + orderId),而不是简单丢掉 key。

  5. 「副本和分区是一回事吗?」 分区是并行与顺序的边界;副本是同一分区数据在多 Broker 上的冗余。单节点实验 replication-factor=1,生产至少 2(常见 3)才扛得住宕机。

  6. 「Leader 是干嘛的?」 每个分区有一个 Leader 副本负责全部读写,Follower 只同步。ISR(In-Sync Replicas)是「跟得上 Leader」的副本集合,后面生产者课的 acks=all 等的就是 ISR 确认。

错法对照

错法问题正解
以为 Topic 内全局有序顺序只承诺在分区内,跨分区并行无全局序只承诺分区内有序;按 key 路由保实体序
所有事件 key=null 却要求同订单顺序消费无 key 消息轮询散落多分区key=orderId(业务实体 id)固定分区
通知与审计共用一个 group.id组内互斥,一方收不全两个 group.id,各自完整消费
用 Kafka 替代 MySQL 存订单最终状态消息是事件流不是权威库MySQL 事务为准;Kafka 存可重放事件
6 个消费者配 3 个分区还指望 2 倍提速超出分区数的消费者闲置分区数 ≥ 期望并行消费者数

卡点急救

  1. 概念多到记不住:只抓三个动词——写进哪(Topic/Partition)、读到哪(Offset)、谁在读(Consumer Group),其余概念都能从这三个动词推出来。
  2. 画图分不清「谁在抢谁在读全量」:判断口诀——同 group.id 抢分区,不同 group.id 各读全量;画图前先给每个消费者标组名。
  3. 搞不清顺序该在哪层保证:需要「同一实体的操作有序」→ key 路由 + 分区内有序;需要「全局所有消息有序」→ Kafka 不擅长,只能单分区(牺牲吞吐)或应用层排序。

面试常问

  • Kafka 为什么吞吐量高? 背四点:①顺序写磁盘(追加日志,顺序 IO 接近内存速度);②页缓存(PageCache,读写都走 OS 缓存,不依赖 JVM 堆);③零拷贝(sendfile,数据不经过用户态);④批量发送 + 压缩(Producer 攒 batch,网络与存储都省)。

  • 分区内有序是怎么保证的?如何让同一订单的消息有序? 分区日志只追加不修改,offset 单调递增,消费按 offset 顺序读——所以分区内天然有序。同一订单有序:Producer 用 orderId 作 key,默认分区器对 key 哈希固定路由到同一分区;注意消费端多线程乱处理仍可能乱序,需按 key 分发到单线程或内存队列。

  • 分区数怎么定?越多越好吗? 起点公式:max(期望吞吐/单分区吞吐, 期望消费者并行数)。不是越多越好:每个分区对应更多文件句柄、更多副本同步、更大 rebalance 与控制器开销;未消费数据也可能摊薄 PageCache。先按当前需求留余量,后续可以增加(减少不行)。

自测三问

  1. Topic 4 分区、Group 2 实例:最多几个实例同时干活?升到 6 实例呢?为什么?
  2. Offset 与 MySQL 自增 id:相似点与不同点各写一条。
  3. 两个服务都要消费同一 Topic:应设几个 group.id?若误设成一个会怎样?

小结一句话

Kafka = 可分区的持久化日志 + 消费者组各自的位点进度;顺序在分区内,扩展上限看分区数,副本负责扛宕机。

延伸

  • Kafka 官方文档 — Topics and Logs
  • 下一课「Docker 运行 Kafka」:把这张概念图变成你机器上真跑起来的 Broker。
加载本节练习…
← 上一课消息队列是什么下一课 →Docker 运行 Kafka