<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>《Java 消息中间件·Kafka 内核与客户端》 · 全书目录与章节索引（50 篇） on PlumePHP</title><link>https://plumephp.com/posts/books/java%E6%B6%88%E6%81%AF%E5%86%85%E6%A0%B8/</link><description>Recent content in 《Java 消息中间件·Kafka 内核与客户端》 · 全书目录与章节索引（50 篇） on PlumePHP</description><generator>Hugo</generator><language>zh-CN</language><lastBuildDate>Thu, 29 Oct 2026 06:49:00 +0800</lastBuildDate><atom:link href="https://plumephp.com/posts/books/java%E6%B6%88%E6%81%AF%E5%86%85%E6%A0%B8/index.xml" rel="self" type="application/rss+xml"/><item><title>《Java 消息中间件·Kafka 内核与客户端》附录 B 集群与客户端模板</title><link>https://plumephp.com/java-mq-core-appendix-b-templates/</link><pubDate>Thu, 29 Oct 2026 06:49:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-appendix-b-templates/</guid><description>把全书用到的可运行件集中成一份模板：单节点 docker run、三节点 compose（每个节点显式写全 listeners，这是本机踩过的坑）、Maven 工程 pom、生产者与消费者最小可运行类、指标打点与优雅关闭。全部按 4.3.0 实跑验证过，复制后改端口即可用。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》附录 A Kafka 命令速查</title><link>https://plumephp.com/java-mq-core-appendix-a-commands/</link><pubDate>Thu, 29 Oct 2026 06:48:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-appendix-a-commands/</guid><description>把全书用到的命令按「集群、主题、消费组、日志、副本、压测」六组整理成一页，每条都标注了它在哪一节被实际用过。另附一节端口与 listener 的实战排查——包括本机遇到的两个坑：宿主机端口被别的进程占用、以及 advertised 端口和映射端口不一致导致客户端连维。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》15.3 libraryd-mq 卷一验收</title><link>https://plumephp.com/java-mq-core-15-3-acceptance/</link><pubDate>Thu, 29 Oct 2026 06:47:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-15-3-acceptance/</guid><description>把前十四章的实验汇总成一份可以照着执行的验收清单：十二个场景，每个给出可量化的判据、本卷对应的实测证据和结论，并配一份可以直接改造成脚本的检查骨架。另外单独列出五项本机做不出来、因而不算通过的检查，说明它们会带来什么风险、下一卷在什么条件下能补上。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》15.2 版本升级与兼容性</title><link>https://plumephp.com/java-mq-core-15-2-upgrade/</link><pubDate>Thu, 29 Oct 2026 06:46:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-15-2-upgrade/</guid><description>升级 Kafka 时要同时管住三个版本号：broker 二进制、metadata.version 和客户端 jar。这一节把这三者的关系拆开，给出四组客户端与服务端的交叉实测（含 2.5.1 这种跨越多个大版本的老客户端），并用 KIP-848 新消费组协议演示什么叫「硬下界」，最后给出 KRaft 下的滚动升级顺序与回滚边界。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》15.1 监控指标与告警</title><link>https://plumephp.com/java-mq-core-15-1-monitoring/</link><pubDate>Thu, 29 Oct 2026 06:45:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-15-1-monitoring/</guid><description>Kafka 的 MBean 有近千个，真正常看的只有十二个。这一节把它们分成 broker、客户端、业务三层，给出本机实测的 JMX 采集步骤——包括镜像里没有 jcmd、JMX_PORT 会被客户端继承、JmxTool 的包名在 4.x 改过这三个坑，并用一次 5 万条的生产与消费演示数字怎么变、阈值怎么定、告警怎么去抖。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》14.3 数据不一致的取证</title><link>https://plumephp.com/java-mq-core-14-3-divergence-forensics/</link><pubDate>Thu, 29 Oct 2026 06:44:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-14-3-divergence-forensics/</guid><description>副本落后与副本分歧是两件事：落后会自己追上，分歧不会。本节实跑 kafka-replica-verification.sh 得到 max lag 0，用 offsetLag 与 dump-log 的 crc 逐层取证，再手动截断 follower 的段文件，观察 LEO 从 682 回退到 651 并重建，并给出反直觉结论：offsetLag=0 时段文件字节数可以不同。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》14.2 积压的分层定位</title><link>https://plumephp.com/java-mq-core-14-2-lag-diagnosis/</link><pubDate>Thu, 29 Oct 2026 06:43:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-14-2-lag-diagnosis/</guid><description>LAG 是一个差值，但成因至少三种：生产变快、消费变慢、分区倾斜。本节用限速消费者制造 0 到 26821 的积压，连续采样 `--describe` 的三列，给出「LEO 是否增长、CURRENT-OFFSET 是否推进、LAG 是否均衡」的三步判定法，并实测 max.poll.interval.ms 超时被踢出组与单条处理慢这两种完全不同的表现。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》14.1 故障图谱</title><link>https://plumephp.com/java-mq-core-14-1-fault-map/</link><pubDate>Thu, 29 Oct 2026 06:42:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-14-1-fault-map/</guid><description>Kafka 的故障不是一张清单，而是一组会互相触发的链条：磁盘满会让 broker 退出，broker 退出会制造 URP，URP 又可能拖垮写入。本节把 URP、离线分区、脑裂、磁盘满、fd 耗尽、ISR 抖动、controller 不可用七类故障做成「现象→指标→命令→根因」对照表，并实跑 URP、fd 耗尽、controller 切换与一次真实的 ENOSPC。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》13.3 副本重建与限流</title><link>https://plumephp.com/java-mq-core-13-3-replica-rebuild/</link><pubDate>Thu, 29 Oct 2026 06:41:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-13-3-replica-rebuild/</guid><description>一个 broker 停机一段时间再上线，是接着拉落后的部分，还是把整段日志丢掉重来？本节实测两种情形：日志未截断时 100 MB 追赶约 5 秒；leader 的 log start 越过 follower 之后，follower 丢掉 311 MB 旧段、从 offset 349995 重建。另附 1 MiB/s 限流实测：稳定在 0.96–1.02 MiB/s。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》13.2 滚动重启与最小可用</title><link>https://plumephp.com/java-mq-core-13-2-rolling-restart/</link><pubDate>Thu, 29 Oct 2026 06:40:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-13-2-rolling-restart/</guid><description>三节点逐个重启，先停 follower 还是先停 leader，差别有多大？本机实测：按 follower→leader 顺序，200 次写入零失败、最长 43ms；按 leader→新 leader 顺序，多了一次选举、一次写入卡了 2.6 秒。而 min.insync.replicas=2 时，再停一台，生产者 26 毫秒内收到 NotEnoughReplicasException。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》13.1 集群拓扑与机架感知</title><link>https://plumephp.com/java-mq-core-13-1-topology-rack/</link><pubDate>Thu, 29 Oct 2026 06:39:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-13-1-topology-rack/</guid><description>三个 broker 配了两个机架，三副本的 topic 会怎么放？本节在三节点 KRaft 上实测：每个分区都是 2 个副本落在同一机架、1 个在另一机架，12 个分区无一例外——只要机架里只有一台 broker，机架感知就无法把 3 个副本分到 3 个故障域。文中还统计了跨机架复制链路的真实占比与 broker.rack 的配置边界。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》12.3 容量规划</title><link>https://plumephp.com/java-mq-core-12-3-capacity-planning/</link><pubDate>Thu, 29 Oct 2026 06:38:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-12-3-capacity-planning/</guid><description>容量规划的输入是业务事件率，不是 Kafka 参数。本节用 libraryd 六个事件主题的假设流量，把一个 Java 程序跑出磁盘、分区、内存、网络四笔账，并实测了 retention.bytes 与 retention.ms 同时设置时谁先触发，以及为什么磁盘占用会超出 retention.bytes 这个「上限」。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》12.2 吞吐、延迟与持久性的三角</title><link>https://plumephp.com/java-mq-core-12-2-throughput-latency-durability/</link><pubDate>Thu, 29 Oct 2026 06:37:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-12-2-throughput-latency-durability/</guid><description>acks、batch.size 与 linger.ms、compression.type 三组参数同时拉扯吞吐、延迟与持久性，任何「三个都要」的方案都只是把成本挪到了别处。本节用四组配置各跑两轮压测，给出对照表，并指出这些数字只能看相对关系，以及单节点为什么测不出 acks 的真实代价。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》12.1 官方压测工具与方法论</title><link>https://plumephp.com/java-mq-core-12-1-perf-testing/</link><pubDate>Thu, 29 Oct 2026 06:36:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-12-1-perf-testing/</guid><description>kafka-producer-perf-test.sh 只输出九列，但每一列都可能被误读。本节逐个拆开 num-records、record-size、throughput 与已弃用的 producer-props，贴出三次同参数运行的完整原文，用 94k 与 203k 的差距说明单次数字为什么不能当基准，并划清客户端数字与 broker 真实能力之间的边界。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》11.3 分区数的非线性成本</title><link>https://plumephp.com/java-mq-core-11-3-partition-count/</link><pubDate>Thu, 29 Oct 2026 06:35:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-11-3-partition-count/</guid><description>分区数不是免费的并行度。本节在 1、10、50、200 个分区的 topic 上实测：每个分区稳定占用 1 个文件描述符和 2 个 mmap 区域，controller 元数据日志约 105 字节/分区，启动加载 261 个空日志要 780 毫秒，并解释为什么上千分区会同时拖慢选举、再平衡与尾延迟。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》11.2 副本同步的吞吐与延迟</title><link>https://plumephp.com/java-mq-core-11-2-replication-throughput/</link><pubDate>Thu, 29 Oct 2026 06:34:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-11-2-replication-throughput/</guid><description>follower 不是被动接收推送，而是主动向 leader 发 fetch。本节用两节点 RF=2 集群实测 acks=1 与 acks=all 的写入速率差，停掉一个 broker 后观察 min.insync.replicas=1 为何仍能写、吞吐为何反而变快，并解释 replica.fetch.* 四个参数各自管什么。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》11.1 网络线程与请求队列</title><link>https://plumephp.com/java-mq-core-11-1-network-threads/</link><pubDate>Thu, 29 Oct 2026 06:33:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-11-1-network-threads/</guid><description>一条 Produce 请求进入 broker 后要经过 acceptor、processor、请求队列和 KafkaRequestHandler 四道关。本节用两节点集群实测线程清单与队列深度：3 个 acceptor、9 个网络线程、16 个处理线程，并解释 mute/unmute 为什么让同一条连接同一时刻只处理一个请求。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》10.3 磁盘与文件描述符规划</title><link>https://plumephp.com/java-mq-core-10-3-disk-planning/</link><pubDate>Thu, 29 Oct 2026 06:32:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-10-3-disk-planning/</guid><description>容量、文件描述符、IO 线程是三笔独立的账。本节用 JDK 25 跑出 libraryd 三档流量的容量估算表，并在容器内实测 fd：12 个新分区只增加 14 个句柄，删除主题后句柄要 60 秒才释放，而不少环境默认的软限制只有 1024，远不够 3000 分区的集群使用。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》10.2 段滚动、索引重建与恢复</title><link>https://plumephp.com/java-mq-core-10-2-segment-roll-recovery/</link><pubDate>Thu, 29 Oct 2026 06:31:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-10-2-segment-roll-recovery/</guid><description>把 segment.bytes 调到 1 MB 后写入 4.5 MB 数据，观察段文件如何按 680 条一批滚出 5 个段；删除一个 .index 再模拟崩溃重启，抓住 Could not find offset index file 与 rebuilding index files 两行日志，验证索引确实是从 .log 重建的。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》10.1 顺序写、页缓存与零拷贝</title><link>https://plumephp.com/java-mq-core-10-1-sequential-io-zerocopy/</link><pubDate>Thu, 29 Oct 2026 06:30:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-10-1-sequential-io-zerocopy/</guid><description>顺序写为什么快、零拷贝到底省掉哪两次拷贝、Kafka 为什么把缓存交给操作系统？本节把约 10 MB 数据写进单分区，用 kafka-dump-log.sh 验证 625 个批次的 position 首尾相接，再对照 /proc/meminfo 的 Dirty 值与内核脏页参数，解释刷盘抖动从哪里来。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》9.3 客户端指标口径</title><link>https://plumephp.com/java-mq-core-09-3-client-metrics/</link><pubDate>Thu, 29 Oct 2026 06:29:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-09-3-client-metrics/</guid><description>metrics() 构造后有 77 项，跑起来变成 110 项，同一个名字在不同 group 下含义不同。本节把 producer-metrics 里与背压、批次、延迟相关的指标拆开口径：实测打满 1 MiB 缓冲时 buffer-available-bytes 归零、waiting-threads 变 1，并对比客户端 lag 为 0 而服务端 LAG 为 200 的同一条消费链路。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》9.2 拦截器链与埋点</title><link>https://plumephp.com/java-mq-core-09-2-interceptors/</link><pubDate>Thu, 29 Oct 2026 06:28:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-09-2-interceptors/</guid><description>onSend 在调用线程、序列化之前执行，onAcknowledgement 在 Sender 线程、用户回调之前执行，这个位置差决定了埋点能不能测到真实耗时。本节实测 100 条消息的 send→ack 分布，验证链上拦截器抛异常后仍继续、ack 回调里的 headers 只读，以及 onSend 里 sleep 会等量拖慢 send()。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》9.1 序列化器与 Schema 边界</title><link>https://plumephp.com/java-mq-core-09-1-serializers/</link><pubDate>Thu, 29 Oct 2026 06:27:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-09-1-serializers/</guid><description>序列化发生在 send() 的调用线程里，而不是 Sender 线程，这决定了异常在哪抛、可变对象何时被读。本节用手写 TLV 格式在同一 topic 混写 v1/v2：严格老读者在第 4 条抛 RecordDeserializationException，宽容老读者能读完却丢掉新字段，复用字段编号则静默读错值。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》8.3 ConsumerCoordinator 与位移提交</title><link>https://plumephp.com/java-mq-core-08-3-consumer-coordinator/</link><pubDate>Thu, 29 Oct 2026 06:26:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-08-3-consumer-coordinator/</guid><description>自动提交不是后台定时器，它只在 poll() 里触发；提交的值是 position，而 position 在 poll 返回记录时就已推进。本节用源码和实测把这个时间差做成丢消息场景：处理 3 条，位移却已提交到 10，close() 时更进一步到 20。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》8.2 Fetcher 与拉取管线</title><link>https://plumephp.com/java-mq-core-08-2-fetcher-pipeline/</link><pubDate>Thu, 29 Oct 2026 06:25:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-08-2-fetcher-pipeline/</guid><description>4.3.0 的 Fetcher 只剩 9,378 字节，因为拉取逻辑被拆进了 AbstractFetch、FetchCollector、CompletedFetch 和 FetchBuffer。本节把 poll 的一次完整路径走一遍，说明请求按 leader 节点合并、分区不按 lag 排序，以及 max.poll.records 与两个字节上限的真实关系。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》8.1 KafkaConsumer 的两套实现</title><link>https://plumephp.com/java-mq-core-08-1-consumer-implementations/</link><pubDate>Thu, 29 Oct 2026 06:24:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-08-1-consumer-implementations/</guid><description>KafkaConsumer 在 4.3.0 里只是一个门面，真正的实现是 ClassicKafkaConsumer 或 AsyncKafkaConsumer，分支点在 ConsumerDelegateCreator 而不是 KafkaConsumer 本身。本节用源码和三次运行把默认值、判定逻辑、以及为什么 getClass() 永远测不出真实实现讲清楚。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》7.3 Sender 与 NetworkClient</title><link>https://plumephp.com/java-mq-core-07-3-sender-network-client/</link><pubDate>Thu, 29 Oct 2026 06:23:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-07-3-sender-network-client/</guid><description>Sender 是一个 while 循环：拉就绪分区、按节点抽批、发请求、poll 响应。本节读 4.3.0 的 runOnce、sendProducerData 与 NetworkClient.poll，并用三组对照实验把 max.in.flight 与重试的乱序关系做实：5 个在途出现 9 处乱序，1 个在途与开启幂等均为 0 处。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》7.2 RecordAccumulator 与批次缓存</title><link>https://plumephp.com/java-mq-core-07-2-record-accumulator/</link><pubDate>Thu, 29 Oct 2026 06:22:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-07-2-record-accumulator/</guid><description>每个分区一条双端队列、每个批次占满 16 KB 缓冲、整块内存由 BufferPool 统一分配。本节读 4.3.0 的 append、ready 与 allocate，实测 32 KB 缓冲池被打满后 send() 阻塞 5 秒，并纠正一个常见说法：异常不是从 send() 抛出的，而是从 Future 里拿到的。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》7.1 KafkaProducer 的线程模型</title><link>https://plumephp.com/java-mq-core-07-1-producer-thread-model/</link><pubDate>Thu, 29 Oct 2026 06:21:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-07-1-producer-thread-model/</guid><description>KafkaProducer 只有两个线程：调用 send() 的应用线程，和跑 Sender 循环的 kafka-producer-network-thread。本节逐行读 4.3.0 的 send() 与 doSend()，实测回调跑在哪个线程、close() 在回调里为什么被降级成零超时，并划出共享状态与线程安全的边界。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》6.3 KIP-848 新一代消费组协议</title><link>https://plumephp.com/java-mq-core-06-3-kip848/</link><pubDate>Thu, 29 Oct 2026 06:20:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-06-3-kip848/</guid><description>group.protocol 一个取值就换掉整套消费组实现：classic 走客户端分配和 JoinGroup/SyncGroup，consumer 走服务端分配和 ConsumerGroupHeartbeat。本节用反射打印真实实现类，核实 4.3.0 源码里的分支，再从 __consumer_offsets 读出 KIP-848 新增的五种记录，并给出迁移时必须先改的配置。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》6.2 经典再平衡协议</title><link>https://plumephp.com/java-mq-core-06-2-classic-rebalance/</link><pubDate>Thu, 29 Oct 2026 06:19:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-06-2-classic-rebalance/</guid><description>两个消费者加进同一个组，分区怎么从 3-0 变成 2-1？本节用实测时间线拆开 JoinGroup、SyncGroup、Heartbeat 三个阶段，说明 leader 成员在哪一步算分配、eager 与 cooperative 各自撤销哪些分区，以及 stop-the-world 卡在 poll() 的哪一行；再让一个消费者停 poll 超时，看它如何被踢出。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》6.1 位移与 __consumer_offsets</title><link>https://plumephp.com/java-mq-core-06-1-offsets-topic/</link><pubDate>Thu, 29 Oct 2026 06:18:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-06-1-offsets-topic/</guid><description>位移不是消息的一部分，它被写进一个叫 __consumer_offsets 的内部 topic。本节从段文件里解出真实的 key/value，说明一个组的位移为什么全落在同一个分区，用实测输出区分「消费位置」与「已提交位移」，并把 --describe 的六列和 offsets.retention.minutes 的边界讲清楚。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》5.3 客户端的元数据刷新</title><link>https://plumephp.com/java-mq-core-05-3-client-metadata/</link><pubDate>Thu, 29 Oct 2026 06:17:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-05-3-client-metadata/</guid><description>客户端的 Metadata 不是一个定时器，而是由「过期」和「显式请求」两个条件驱动的缓存状态机。本篇按 4.3.0 源码逐段读 timeToNextUpdate、requestUpdate、update、failedUpdate 与 NetworkClient 的 maybeUpdate，并用 DEBUG 日志量出 2 秒和 60 秒两种 max.age 下的真实请求次数。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》5.2 集群成员与元数据传播</title><link>https://plumephp.com/java-mq-core-05-2-metadata-propagation/</link><pubDate>Thu, 29 Oct 2026 06:16:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-05-2-metadata-propagation/</guid><description>broker 重启后 brokerEpoch 会变，leader 变更会以一条记录进入 __cluster_metadata，再经 broker 的元数据缓存传到客户端。本篇实测分区扩容在 metadata.max.age.ms=5s 与 600s 下的可见时间差，并说明为什么 broker 掉线时客户端反而恢复得很快。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》5.1 KRaft：控制器与元数据日志</title><link>https://plumephp.com/java-mq-core-05-1-kraft-controller/</link><pubDate>Thu, 29 Oct 2026 06:15:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-05-1-kraft-controller/</guid><description>KRaft 把集群元数据本身写成一条 Raft 日志：topic 创建、broker 注册、leader 变更都是 __cluster_metadata 里的记录。本篇用 kafka-dump-log.sh 解出 4.3.0 单节点的真实记录序列，说明 controller quorum 如何选举、元数据如何提交，以及为什么 4.x 不再需要 ZooKeeper。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》4.3 Leader 选举与不干净选举</title><link>https://plumephp.com/java-mq-core-04-3-leader-election/</link><pubDate>Thu, 29 Oct 2026 06:14:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-04-3-leader-election/</guid><description>停掉 leader 之后，分区多久能用？答案取决于集群能不能「干净」地选出新 leader。本节实测三节点 KRaft：停 leader 后 1.8 秒新 leader 就位、数据零丢失；但停掉两个 broker 会让 controller quorum 失去多数派，整个集群连元数据都查不了——这是 KRaft 和 ZooKeeper 时代最容易被忽略的差别。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》4.2 ISR 收缩与 min.insync.replicas</title><link>https://plumephp.com/java-mq-core-04-2-isr-min-isr/</link><pubDate>Thu, 29 Oct 2026 06:13:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-04-2-isr-min-isr/</guid><description>acks=all 不是「写完就成功」，它真正的含义是「等 ISR 里的副本都写完」。ISR 会收缩，收缩到低于 min.insync.replicas 时写入被拒。本节用三节点集群实测：杀掉一个 broker 仍能写，再杀一个就报 NOT_ENOUGH_REPLICAS，并解释这两个参数为什么要成对出现。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》4.1 副本、LEO 与高水位</title><link>https://plumephp.com/java-mq-core-04-1-replica-leo-hw/</link><pubDate>Thu, 29 Oct 2026 06:12:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-04-1-replica-leo-hw/</guid><description>生产者明明返回了 offset 5 到 9，消费者却一条都读不到——这不是 bug，是 LEO 与高水位分离的正常状态。本节用 docker pause 冻结一个 follower，在同一秒里同时读出「leader 磁盘上有 19 条」和「消费者只能看到 16 条」，并给出 stop、pause、崩溃三种失效下 ISR 收缩的真实时序。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》3.3 分区器与键设计</title><link>https://plumephp.com/java-mq-core-03-3-partitioner/</link><pubDate>Thu, 29 Oct 2026 06:11:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-03-3-partitioner/</guid><description>4.3.0 的默认分区逻辑不在 DefaultPartitioner 里，而在 BuiltInPartitioner：key 存在时用 murmur2 取模，key 为 null 时按字节粘性切换。本篇用 6 个分区的实测序列说明粘性批次、key 基数与热点 key 三种倾斜，并给出自定义 Partitioner 的完整写法和边界。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》3.2 acks、重试与幂等</title><link>https://plumephp.com/java-mq-core-03-2-acks-retry-idempotence/</link><pubDate>Thu, 29 Oct 2026 06:10:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-03-2-acks-retry-idempotence/</guid><description>acks=0 的成功只代表写进 socket，acks=1 的成功只代表 leader 写进本地日志，acks=all 才等到 ISR 确认。本篇用单节点杀 broker 的实验量出三种取值的失败窗口，拆开 retries 与 delivery.timeout.ms 的关系，并用批次头里的 PID 与 sequence 说明幂等生产者能去掉哪一种重复。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》3.1 批次、linger 与压缩</title><link>https://plumephp.com/java-mq-core-03-1-batch-linger-compression/</link><pubDate>Thu, 29 Oct 2026 06:09:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-03-1-batch-linger-compression/</guid><description>batch.size 是批次上限，linger.ms 是等待上限，compression.type 作用在整批数据上。本篇用五组参数和磁盘日志大小把三者的相互作用拆开：为什么批次满了 linger 就不起作用、为什么压缩率取决于批次而不是单条消息，以及 CPU 与带宽如何交换。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》2.3 保留与清理</title><link>https://plumephp.com/java-mq-core-02-3-retention-compaction/</link><pubDate>Thu, 29 Oct 2026 06:08:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-02-3-retention-compaction/</guid><description>日志不会因为被读过就删除，它的生死由 cleanup.policy 决定。本节实测 delete 策略按时间整段回收，以及 compact 策略如何把同 key 的多次写入压成最后一条、墓碑如何先删除旧值、又为什么墓碑自己还要再等一轮清理，并给出两种策略的选择边界。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》2.2 Topic 的物理结构</title><link>https://plumephp.com/java-mq-core-02-2-log-segments/</link><pubDate>Thu, 29 Oct 2026 06:07:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-02-2-log-segments/</guid><description>一个分区在磁盘上不是一个文件，而是一组按 base offset 命名的段。本节用两次真实写入制造时间滚动，拆开 .log、.index、.timeindex、.snapshot 的职责，解释 20 条记录为什么只产生 1 个索引项，并走一遍从 offset 到字节位置的寻址路径。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》2.1 三个节点的最小集群</title><link>https://plumephp.com/java-mq-core-02-1-lab-cluster/</link><pubDate>Thu, 29 Oct 2026 06:06:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-02-1-lab-cluster/</guid><description>单节点能验证命令，三节点才能验证副本。本节先把 listeners、advertised.listeners 与 controller quorum 三组地址的分工讲透，再用真实的单节点启动日志和一个故意写错 advertised 的失败实验，解释为什么客户端连上了却读不到元数据，最后给出可直接使用的三节点 compose。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》1.3 交付语义的真实成本</title><link>https://plumephp.com/java-mq-core-01-3-delivery-semantics/</link><pubDate>Thu, 29 Oct 2026 06:05:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-01-3-delivery-semantics/</guid><description>at-most-once、at-least-once、exactly-once 不是三个开关，而是三组失败窗口的取舍。本节先打出 4.3.0 的真实默认值，再分别复现「提交早于处理」的丢失、「处理完未提交」的重复、事务提交与 abort 的可见性，最后划清 exactly-once 只在 Kafka 读写链路内成立的边界。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》1.2 分区：顺序与并行度的交换</title><link>https://plumephp.com/java-mq-core-01-2-partition-tradeoff/</link><pubDate>Thu, 29 Oct 2026 06:04:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-01-2-partition-tradeoff/</guid><description>5 条按顺序发出的消息，消费者看到的却是另一种顺序。本节用 3 个分区实测落点 1、2、2、0、1，从 murmur2 哈希与粘性分区讲到同 key 同分区，再把分区数的三笔代价——并行上限、文件与内存、故障恢复——逐条算清楚，并给出一个可操作的分区数估算顺序。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》1.1 把消息系统看成日志</title><link>https://plumephp.com/java-mq-core-01-1-topics-as-log/</link><pubDate>Thu, 29 Oct 2026 06:03:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-01-1-topics-as-log/</guid><description>从队列、发布订阅、日志、流四种形态的差别入手，用单节点 Kafka 发 5 条消息、两个消费组读到不同位置、消费后日志段仍完整保留的实验，说明 Kafka 为什么选分区日志，以及「消费不删数据、位移是读者自己的进度」在工程上到底意味着什么。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》目录与学习路径</title><link>https://plumephp.com/java-mq-core-toc/</link><pubDate>Thu, 29 Oct 2026 06:02:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-toc/</guid><description>本卷 15 章 45 节加两个附录，按「先建立直觉、再进服务端、再读客户端源码、最后做运维」的顺序组织。这篇目录给出完整章节索引、三条阅读路径、每章回答的具体问题、读之前需要的前置知识，以及哪些实验可以跳过，方便你按手上的故障或疑问直接跳读。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》前言：实验环境、集群与数据口径</title><link>https://plumephp.com/java-mq-core-preface/</link><pubDate>Thu, 29 Oct 2026 06:01:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-preface/</guid><description>本书所有实验都在同一台机器上完成：Temurin 25.0.5+8、colima 里的 Docker 29.5.2、apache/kafka:4.3.0 的 KRaft 集群。这篇前言给出单节点与三节点两套底座的完整启动命令、客户端工程的最小 pom、源码核实方法，以及「单次运行不作基准」和「未在本机执行」两条数据口径的具体用法。</description></item><item><title>《Java 消息中间件·Kafka 内核与客户端》序：消息系统里没有魔法</title><link>https://plumephp.com/java-mq-core-foreword/</link><pubDate>Thu, 29 Oct 2026 06:00:00 +0800</pubDate><guid>https://plumephp.com/java-mq-core-foreword/</guid><description>消息队列最常见的三类误判，是把「发了」当成「到了」、把「分区有序」当成「全局有序」、把「配了 acks=all」当成「不会丢」。本序用三个可以在本机复现的现象拆掉这三层幻觉，说明本书为什么坚持每个结论都要有命令和原始输出，并交代三卷各自回答什么问题。</description></item></channel></rss>