如果让我给正在学Kafka的Java开发者推荐一个入门项目,我首推的就是基于Java和Kafka的生产者-消费者示例。原因是它虽然只有两个角色,却把Kafka最核心的消息流转链路完整串了起来:生产者把消息发到Topic,Broker负责存储,消费者从Topic里拉取并处理。我见过不少人第一步就卡住——环境搭起来了但本机代码连不上,日志疯狂刷metadata报错,甚至代码写完消费端一条数据都拿不到。这篇文章就从我实际跑通一个可运行的生产者-消费者示例出发,把环境搭建、生产者和消费者的完整代码、每个关键配置背后的理由、以及实测踩过的坑都整理出来,适合正在学Kafka的Java工程师,也适合准备面试时用一个完整示例来串联知识点。
1. 为什么"生产者-消费者"是Kafka最值得先写的Demo
1.1 从一条消息的旅程理解Kafka的核心角色
很多教程一上来就画架构图:Producer、Broker、Topic、Partition、Consumer Group、Offset。图看懂了,动手时还是一头雾水。我建议反过来,先跟一条消息走一遍,再回头看概念就清晰了。
假设你有一个Topic叫demo-topic,分了3个分区(partitions=3)。生产者发送一条消息,实际上是在往某个分区追加一条记录,这条记录被赋予一个递增的offset,在这个分区内严格有序。如果消息带key,Kafka会对key做哈希决定进哪个分区,同一个key总会进同一个分区;如果不带key,就按轮询或粘性分区策略分散到各个分区。Broker的角色更像一个持久化的日志系统,消息写进去之后不会因为消费者读过就删除,而是要等保留策略(retention)到期才清理。这个设计是Kafka能支撑"多个消费组同时读"的关键。
消费者的工作方式也不是常见的"推送",而是主动拉取(poll)。消费者加入某个消费组后,Kafka会把这个Topic下的分区分配给组内的成员,一个分区在同一时刻只会被同一个消费组内的一个消费者持有。消费者poll一批消息,处理完后提交offset,相当于在日志上做"我读到这了"的标记。这个提交位置就是之后消费恢复的起点。
关于消费组在这里特别重要。同一个groupId内的多个消费者实例共同分担分区;不同groupId的消费者互不干扰,各自都能读到全量消息。打个比方:同一个小区里有两家搬家公司,它们看到的都是整个小区所有信件,一家消费掉的消息不会影响另一家。这也是Kafka能同时服务多个下游业务的基础。
1.2 这个Demo能覆盖的面试题与生产场景
既然要写示例,先把它的价值说清楚。这个看似简单的Demo,其实把Kafka的高频面试点都卡进去了:
- 生产者为什么快:顺序写盘、页缓存、批量发送,这些会对应到batch.size、linger.ms这些参数;
- 消息可靠性:acks、retries、幂等生产者,对应"消息会不会丢";
- 消费组与rebalance:分区分配策略、消费者数量超过分区数会空转;
- offset与重复消费:自动提交的窗口、手动提交方式、业务侧幂等。
网上很多人备考Kafka相关面试题,与其死记硬背,不如把这段Demo跑通,再对着参数试一遍,每个概念都有真实场景对照,记得更牢。
生产里这个模型同样无处不在:订单系统把消息发给Kafka,库存服务、积分服务、短信服务各自用不同消费组去订阅;高峰期流量先打到Kafka做削峰,下游按自己的处理能力消费。可以说,理解了Producer和Consumer,整个Kafka生态(SpringBoot Kafka、Canal同步、Flink消费)都是在这个底座上长出来的。后面你去看spring-boot-starter-kafka的封装,也只是把这个原生API包了一层。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备:从JDK到可用的Kafka,少走弯路
2.1 版本选型:Java、Kafka、客户端版本怎么配对
版本选型是第一个容易踩坑的点。我的建议非常明确:本地上Java 8或Java 11都行,Kafka Server用3.x最新稳定版,客户端依赖kafka-clients用和服务端一致的版本。这样可以把协议差异的坑降到最低。很多人喜欢客户端随便引入一个版本,结果服务端3.x、客户端2.x,虽然大部分时候能跑,但一旦遇到新特性和协议差异,排查起来非常痛苦。
我本地用的是Java 11,Kafka 3.6.x,pom里引入org.apache.kafka:kafka-clients:3.6.2。这里说明一下:3.6是带KRaft模式稳定的版本,本地单节点可以不依赖ZooKeeper直接启动,环境搭建会省很多事。如果你的环境比较老,只能上2.8之前的版本,那还需要单独跑ZooKeeper,原理不影响,但操作多一步。
对应关系可以看手头的JDK:
| JDK版本 | 建议Kafka版本 | 说明 |
|---|---|---|
| 8 | 2.8 ~ 3.6 | 都能跑,3.x后用Java 8依然兼容 |
| 11 | 3.x | 推荐,日常开发和本地Demo足够 |
| 17 | 3.5+ | 新项目可以,但注意部分老工具链要升级 |
顺便补一句,Java环境变量(JAVA_HOME、PATH)如果没配好,IDE会报找不到主类,或者构建工具跑不起来。装JDK后把JAVA_HOME指到安装目录,PATH里加上%JAVA_HOME%/bin,终端执行java -version确认即可。这一步很基础,但我见过不少新手连编译都过不了就是卡在这。
2.2 本地开发环境搭建的两种方式
本地起Kafka,我推荐两种方式,任选其一。
方式一,Docker Compose单节点,最省事。创建一个docker-compose.yml:
yaml复制version: '3.8'
services:
kafka:
image: bitnami/kafka:3.6
container_name: kafka-demo
ports:
- "9092:9092"
environment:
- KAFKA_CFG_NODE_ID=0
- KAFKA_CFG_PROCESS_ROLES=controller,broker
- KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://127.0.0.1:9092
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:9093
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=C
