《Java 消息中间件·Kafka 内核与客户端》目录与学习路径

本卷 15 章 45 节加两个附录,按「先建立直觉、再进服务端、再读客户端源码、最后做运维」的顺序组织。这篇目录给出完整章节索引、三条阅读路径、每章回答的具体问题、读之前需要的前置知识,以及哪些实验可以跳过,方便你按手上的故障或疑问直接跳读。

这本书的骨架

卷一回答一个问题:一条消息从 send() 调用到落进日志文件,中间发生了什么,为什么有时候不按你以为的方式发生。

为了回答这个问题,全书分成五个部分,前三部分是「理解」,后两部分是「使用与维护」:

部分章节主题读完能做什么
第一部分第 1–3 章消息系统的形状、实验底座、生产者说清楚分区、顺序、交付语义的关系
第二部分第 4–6 章副本、选举、KRaft、位移与消费组协议解释 ISR 收缩、leader 切换、再平衡停顿
第三部分第 7–9 章生产者与消费者源码、序列化与指标从源码里找到某个行为的原因
第四部分第 10–12 章存储、网络与复制、压测与容量做容量估算,知道压测数字可信到什么程度
第五部分第 13–15 章运维动作、故障图谱、监控与验收处理集群故障,给出可执行的处理顺序

前两部分是概念密度最高的地方。第三部分是源码,读起来慢但一次性收益最大。第四、五部分可以当手册查。

每一章回答的那个问题

写目录的时候,最没用的是只列标题。所以这里给每章配一个「它到底在回答什么」:

章章节它回答的问题
1第 1 章 消息系统的形状消息系统有几种形态?Kafka 为什么是日志?
2第 2 章 实验底座与物理结构数据到底存在哪几个文件里?
3第 3 章 生产者我调的这几个参数,各自在改什么?
4第 4 章 副本与选举一台机器挂了,我的数据还在不在?
5第 5 章 KRaft没有 ZooKeeper 之后,集群靠什么协调?
6第 6 章 位移与消费组协议消费者重启之后,为什么从奇怪的位置开始读?
7第 7 章 生产者内部send() 之后,消息去了哪个缓冲区?
8第 8 章 消费者内部poll() 一次,背后发了几个请求?
9第 9 章 序列化与扩展点我能在客户端插什么,不能插什么?
10第 10 章 存储为什么 Kafka 号称顺序写很快?边界在哪?
11第 11 章 网络与复制分区数加上去,为什么反而慢了?
12第 12 章 压测与容量我的压测数字能信吗?容量怎么估?
13第 13 章 运维动作重启、扩容、换盘,正确的顺序是什么?
14第 14 章 故障面板上这个指标红了,下一步查什么?
15第 15 章 监控与验收哪些指标必须告警?验收怎么算通过?

如果你手上正有一个具体问题,直接看最后一列,比从头读快。

第一部分:消息系统与实验底座

这一部分建立两件事:消息系统的直觉,以及一套能反复用的实验环境。

节标题一句话
1.1把消息系统看成日志消费不删数据,位移是读者自己的进度
1.2分区:顺序与并行度的交换分区既是并行单位,也是顺序单位
1.3交付语义的真实成本三档语义各要付出什么
2.1三个节点的最小集群listener 与 advertised.listener 为什么要分开
2.2Topic 的物理结构段文件、索引,以及一次读请求的寻址
2.3保留与清理delete 与 compact 的语义差别
3.1批次、linger 与压缩三个参数互相挤压
3.2acks、重试与幂等失败窗口在哪里,幂等挡住了什么
3.3分区器与键设计默认分区器的粘性行为,与热点 key

第 1 章不需要环境,读完就能建立直觉。第 2 章开始需要容器,所以 2.1 同时承担「实验环境搭建」的职责——如果这一步跑不通,后面的实验都做不了。

第 3 章讲生产者,是全书第一次动手写客户端代码。它的前置只有 1.2(分区)和 1.3(语义),不依赖服务端机制。

第二部分:服务端机制

这一部分进入 broker 内部。它不需要写太多客户端代码,但需要三类实验:单节点、三节点、以及「杀掉一个节点」的破坏性操作。

节标题一句话
4.1副本、LEO 与高水位消费者只能读到 HW 之前
4.2ISR 收缩与 min.insync.replicas两个参数联合决定能不能写
4.3Leader 选举与不干净选举优先副本、受控关闭、ELR
5.1KRaft:控制器与元数据日志元数据本身也是一条日志
5.2集群成员与元数据传播变更多久能被客户端看见
5.3客户端的元数据刷新Metadata 状态机与过期抖动
6.1位移与 __consumer_offsets位移存在哪,和消费位置差在哪
6.2经典再平衡协议JoinGroup/SyncGroup 与停顿
6.3KIP-848 新一代协议服务端主导分配,迁移要注意什么

第 4 章是三节点实验的核心。4.1 建立 LEO/HW 的关系,4.2 用「杀一个 broker 还能写、杀两个就不能写」把这个关系变成可观测的事实,4.3 讲选举策略。

第 5 章讲 KRaft。这里有一个版本陷阱:4.x 已经彻底移除 ZooKeeper,所有命令用 --bootstrap-server,--zookeeper 参数不存在。如果你在别处看到「用 --zookeeper 连集群」,那是 3.x 的写法。

第 6 章讲消费者协调。6.2 和 6.3 是同一件事的两代实现,读的时候要分清「classic 协议的行为」和「新协议的行为」,两者在再平衡停顿上的表现不同。

第三部分:客户端源码

这一部分最慢,也最值。它要求读者愿意打开 sources jar,跟着方法调用读下去。

节标题一句话
7.1KafkaProducer 的线程模型调用线程 + 一个 Sender 线程
7.2RecordAccumulator 与批次缓存每个分区一个队列,共享一个内存池
7.3Sender 与 NetworkClient请求怎么拆分,in-flight 怎么限制
8.1KafkaConsumer 的两套实现门面背后是 Classic 还是 Async
8.2Fetcher 与拉取管线4.x 重构之后,Fetcher 变小了
8.3ConsumerCoordinator 与位移提交自动提交的确切时机
9.1序列化器与 Schema 边界消息里不要放可变对象
9.2拦截器链与埋点能改什么,不能改什么
9.3客户端指标口径77 项指标里哪几个有用

这一部分有一个反复出现的提醒:不要凭 3.x 的印象写 4.x 的源码。消费者的实现、Fetcher 的职责、group.protocol 的分支,在 4.x 都变了。每一节都会给出 grep 命令和类文件大小,读者可以自己复核。

第四部分:存储与性能

这一部分回答「为什么快」和「快到哪里为止」。

节标题一句话
10.1顺序写、页缓存与零拷贝快的是顺序追加和页缓存,不是魔法
10.2段滚动、索引重建与恢复崩溃之后索引怎么回来
10.3磁盘与文件描述符规划容量、fd、IO 线程三笔账
11.1网络线程与请求队列network 与 io 线程的分工
11.2副本同步的吞吐与延迟follower 追赶的代价
11.3分区数的非线性成本上千分区为什么是坏主意
12.1官方压测工具与方法论两个 perf-test 脚本,以及它们的局限
12.2吞吐、延迟与持久性的三角三个指标不能同时最好
12.3容量规划从 QPS 推分区数与保留期

第 12 章会明确写:本机的压测数字只能做相对比较,不能做容量结论。这不是谦虚,是这台机器 load 常年在十几到二十几之间波动决定的。

第五部分:运维与故障

这一部分最接近日常工作。它的组织方式不是「知识点」,是「动作」。

节标题一句话
13.1集群拓扑与机架感知broker.rack 与跨 AZ 流量
13.2滚动重启与最小可用重启顺序决定可用性
13.3副本重建与限流追赶太猛会把正常流量挤掉
14.1故障图谱URP、离线分区、磁盘满、fd 耗尽
14.2积压的分层定位从 lag 一路查到根因
14.3数据不一致的取证副本之间怎么比对
15.1监控指标与告警12 个必看指标与阈值
15.2版本升级与兼容性升级顺序与协议兼容
15.3libraryd-mq 卷一验收全卷实验的汇总与判据

附录

篇标题什么时候翻
AKafka 命令速查正在敲命令,想确认参数
B集群与客户端模板要从零搭一套环境

附录 A 里的端口、参数都是本机实际用过的,可以直接复制。附录 B 的 compose 文件就是本书实验用的那一份。

三条阅读路径

路径一:顺序通读(约 30 小时)

1.1 → 1.2 → 1.3 → 2.1 → …… → 15.3。适合想建立完整机制理解的人。第 1–3 章大约 6 小时,第 4–6 章 8 小时,第 7–9 章源码 8 小时,第 10–15 章 8 小时。

路径二:机制跳读(约 12 小时)

只读第 1、4、6、7、8 章。这五章覆盖三个最高频的疑问:为什么消费者会重复、为什么再平衡会停顿、为什么分区数不能乱加。读完可以跳过第 2、3、5 章的细节,需要时再回查。

路径三:值班查表(按需)

附录 A 的命令 + 第 14 章的故障图谱 + 15.1 的指标阈值。这条路径不追求理解,只追求「现在该敲什么命令」。

每节末尾的「判据」是什么

本书每一节结尾附近都会有一个小段落,标题通常是「本节判据」或「怎么判断」。它回答的不是「讲完了吗」,而是「什么现象出现,说明你真的理解了」。

举三个例子:

  • 1.2 节的判据是:你能否解释「为什么 5 条消息按顺序发出,消费者看到的却是 book-3 在前」。
  • 4.2 节的判据是:看完 NOT_ENOUGH_REPLICAS 之后,你是否能说出「此时再减一个副本会怎样」。
  • 8.3 节的判据是:你能否指出自动提交在哪个时间点可能丢掉一批已处理的记录。

这个设计来自一个观察:技术书读完之后最常说的一句话是「好像懂了」。判据的作用是把它变成一个可以自己回答的问题。答不出来,说明这一节需要重读或重跑实验。

和其它书的关系

这本卷属于《Java 消息中间件》三卷本的第一卷。三卷的关系是:

卷什么时候读
卷一(本书)想理解机制,或者在排查「为什么行为和我以为的不一样」
卷二《可靠消息与消费治理》要设计不丢不重的链路,或者正在处理积压与重复
卷三《事件驱动架构》要决定「这个业务该不该用事件」,或者设计 CQRS 与流处理

此外,下面几本书和本卷有交叉,但角度不同:

  • 《Java 并发编程·性能诊断与事故》 :讲线程、锁、GC 与容器配额。本卷讲的是跨进程的消息链路,那本讲的是单进程内的并发。读第 11、12 章时如果对 CPU 与内存的观测手段不熟,可以对照那本的诊断工具章节。
  • 《Java 网络编程基础》 :讲 Socket、NIO、HTTP/2 与 TLS。Kafka 的协议建立在 TCP 之上,第 11.1 节讲网络线程时会假设你了解基本的 TCP 语义。
  • 《Java 虚拟机原理与性能调优》 :讲 GC 与内存布局。Kafka 客户端大量使用堆外内存与页缓存,第 10 章会引用那本的概念。

读之前需要的前置知识

这本书不假设你已经是 Kafka 专家,但假设你具备三样东西:

前置为什么需要不熟怎么办
Java 语言基础第三部分要读源码,看懂泛型、lambda、CompletableFuture先读《Java 编程入门》的泛型与并发章节
基本的命令行能力几乎所有实验都用 docker exec 进容器敲脚本附录 A 给了完整的命令形式,照抄即可
容量单位与简单估算第 12 章要做分区数与磁盘的乘法这一节会把每一步算式写出来

不需要的前置:不需要用过 ZooKeeper(4.x 已经没有它),不需要装过 Kafka(第 2.1 节从零开始),不需要懂 Scala(本书只读 clients 模块,纯 Java)。

有一个前置不建议带进来:其它版本 Kafka 的既有印象。3.x 到 4.x 的变化足够大,尤其是消费者实现和 KRaft 的默认化。带着旧印象读,容易在「我记得应该是……」的地方卡住。每节遇到这类变化时会明确标出「4.x 与 3.x 的差异」。

4.x 与旧教材的七处不同

如果你读过 2.x 或 3.x 时代的 Kafka 材料,下面这几处会让你在实验里直接卡住。本书在对应章节会逐条展开,这里先给一张速查表:

旧印象4.x 的实际本书位置
Kafka 需要 ZooKeeper4.0 起只支持 KRaft,ZooKeeper 已移除5.1
--zookeeper 是合法参数所有命令都用 --bootstrap-server附录 A
broker.id 是必填项改用 node.id,broker 角色由 process.roles 决定2.1
消费者就是 Fetcher 那一套新增 AsyncKafkaConsumer(KIP-848),两套实现并存8.1
再平衡一定「停世界」cooperative-sticky 与 KIP-848 都能减少停顿6.2 / 6.3
--producer-property 是标准用法已废弃,改用 --command-property,实测会打 deprecation warning3.1
--describe 输出只有 Leader/Replicas/Isr4.x 多了 Elr 与 LastKnownElr 两列4.3

这张表不是让你背,是让你在遇到「命令报错」时先来这里对一眼。本书所有实验都是在 4.3.0 上跑的,凡是涉及行为变化的地方都会显式标注。

哪些实验可以跳过

不是每一节都需要动手。下面这张表说明每个实验的性质,方便你按时间预算取舍:

实验类型涉及章节需要的环境可以只看结论吗
纯命令验证1.1、2.2、2.3、6.1、附录 A单节点可以
客户端代码3.1–3.3、7–9、12单节点 + Maven建议跑一遍,代码是理解的关键
破坏性操作4.2、4.3、13.2、14.1三节点不可以,破坏性实验的结论依赖你亲眼看到状态变化
性能与压测10.1、11.2、12.1三节点可以只看相对关系,绝对值本就不可信
运维流程13.1、13.3、15.2三节点可以只看流程,但要知道每一步的判据

「破坏性操作」那一行的措辞是刻意的。读别人写的「杀掉 leader 之后 ISR 从 3 变成 2」,和自己在终端里看着 --describe 的输出从 Isr: 2,3,1 变成 Isr: 3,1,理解深度完全不同。这一类实验,本书建议一定自己跑。

一个使用建议

这本书的每一节都按同一个结构写:先给一个具体问题,再给机制,再给实验,最后给判据。

如果你时间有限,只读每节开头的「问题」和结尾的「判据」,中间跳过实验,也能得到一个可用的结论。但如果你要拿这个结论去做生产决策,请至少把实验跑一遍——这本书里没有一个数字是编的,其中不少也和「常识」相反。

另一个建议是:遇到与自己经验冲突的段落,先别急着判它错。本书有若干结论初看反直觉,比如「send() 成功不代表消费者能读到」「acks=all 仍然可能丢」「分区数加到某个点之后整体吞吐反而下降」。这些都不是笔误,而是机制决定的。每一处都给了可复现的命令,请先跑,再下结论。

如果跑出来的结果和书里不一样,那也可能不是书错了,而是你的版本、参数或机器状态不同。把这三种差异记录下来,本身就是一次很好的学习。

从第 1.1 节 开始。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「books」更多文章

  1. 《Java 消息中间件·事件驱动架构》附录 B 架构决策记录模板
  2. 《Java 消息中间件·事件驱动架构》附录 A 术语表
  3. 《Java 消息中间件·事件驱动架构》15.3 全书验收