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

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

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

学习

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

更多

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

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Kafka 消息队列入门/课时/Docker 运行 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综合练习

Docker 运行 Kafka

KRaft 单节点、kafka-topics 验证。

30 分钟

Docker 运行 Kafka

这一课你将能做到

  1. 用 Docker Compose 拉起单节点 KRaft 模式 Broker(无 ZooKeeper),并用 localhost:9092 作为 bootstrap
  2. 创建 3 分区 Topic,用 kafka-topics --describe 核对分区数与副本因子
  3. 用 kafka-console-producer/consumer 完成「先发后收 / 从头消费」闭环,并写出 Spring 的连接配置

为什么要学

概念图再熟,没有 Broker 就无法验证分区、offset 与消费组行为。本地用 KRaft 单节点 最省事:新版 Kafka 已用内置 Raft 元数据管理替代 ZooKeeper,一个容器搞定,和你跑 Redis 的 Compose 体验一致。

本课目标是 能起、能建、能收发:搭好后,后面 Java 客户端、Spring Kafka、Streams 全部连这个 localhost:9092。生产要多 Broker、副本 ≥ 2、监听器安全(SASL/SSL),那些是上线话题,不阻碍今天动手。

人话:先在自己机器上开一扇 9092 的门,后面所有代码都敲这扇门。

先建立图像

你的电脑
  docker compose
    └── kafka 容器(KRaft:broker + controller 同进程)
          监听 9092  ←──  宿主机 localhost:9092
          监听 9093  ←──  controller 内部用
          分区日志存容器内(实验数据可丢)

终端 A: kafka-console-consumer  (订阅 Topic)
终端 B: kafka-console-producer  (追加记录)
Spring: spring.kafka.bootstrap-servers=localhost:9092
项实验取值生产直觉
模式KRaft 单节点多 controller quorum / 多 broker
replication-factor1≥ 2(常见 3)
分区数3(方便看分摊)按吞吐与消费者数规划
数据可随时 down -v 清空挂卷、有备份与监控

跟着做

步骤 1:准备 Compose 文件

在实验目录新建 docker-compose.yml(KRaft 单节点,无 ZooKeeper):

services:
  kafka:
    image: apache/kafka:3.9.0
    container_name: kafka-lab
    ports:
      - "9092:9092"
    environment:
      # 单节点同时扮演 broker 与 controller(KRaft)
      KAFKA_NODE_ID: 1
      KAFKA_PROCESS_ROLES: broker,controller
      KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093
      # 广播给客户端的地址必须是宿主机能访问到的
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@localhost:9093
      # 单节点必须把内部 topic 副本降为 1,否则启动/建 topic 会失败
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0

启动并确认:

docker compose up -d
docker compose ps
docker logs kafka-lab --tail 20

应看到:容器 Up,日志里出现 Kafka Server started。PowerShell 下命令单行执行即可;9092 被占用时先停占用进程或改端口映射。

步骤 2:确认脚本可用

docker exec kafka-lab ls /opt/kafka/bin

应看到 kafka-topics.sh、kafka-console-producer.sh、kafka-console-consumer.sh、kafka-consumer-groups.sh 等。后续所有命令都走 docker exec kafka-lab ...。

步骤 3:创建 Topic 并 describe

docker exec kafka-lab /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic coderoadmap.order-events --partitions 3 --replication-factor 1

核对:

docker exec kafka-lab /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic coderoadmap.order-events

应看到 PartitionCount: 3、ReplicationFactor: 1,三个分区 Leader 都在本节点。再建一个练习用 Topic:coderoadmap.audit-log,--partitions 2。

步骤 4:终端 A 启动消费者(从头读)

docker exec -it kafka-lab /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic coderoadmap.order-events --from-beginning

--from-beginning:这个新消费者组从最早消息读起(实验习惯)。窗口保持开着。

步骤 5:终端 B 生产消息

新开终端:

docker exec -it kafka-lab /opt/kafka/bin/kafka-console-producer.sh --bootstrap-server localhost:9092 --topic coderoadmap.order-events

逐行输入后回车:

{"event":"OrderCreated","orderId":"1001"}
{"event":"OrderCreated","orderId":"1002"}

应看到终端 A 立即出现相同内容。Ctrl+C 可退出任一终端。

步骤 6:验证「先发后启」与 Spring 连接串

  1. 停掉消费者,用 producer 再发 2 条,然后用同样的 --from-beginning 命令重新拉起——应能看到全部历史消息(日志还在,这就是 Kafka 与 Pub/Sub 的区别)。
  2. 写下 Spring 侧配置,后面课程直接沿用:
# application-dev.yml
spring:
  kafka:
    bootstrap-servers: localhost:9092

讲清楚要点

  1. 因为实验只需验证协议与工具,所以单节点 KRaft + replication-factor=1 足够;把生产副本策略照搬到笔记本只会平白报错。
  2. 因为客户端靠 bootstrap-servers 找到集群再获取完整元数据,所以本机所有角色统一写 localhost:9092;容器内脚本连的是容器自己的 localhost:9092。
  3. 因为advertised.listeners 告诉客户端「回头该连谁」,所以宿主机访问必须广播成 localhost:9092,否则 Java 客户端会拿到不可达地址一直超时。
  4. 因为KRaft 用 controller quorum 管理元数据,所以 Compose 里没有 ZooKeeper 服务;看到老教程里的 ZK 配置直接按 KRaft 改写。
  5. 因为日志默认按时间/大小保留,所以--from-beginning 能读到历史;要跨 compose down 保留数据,需要挂 volume。
  6. 因为__consumer_offsets 等内部 Topic 也受副本因子约束,所以单节点必须设 KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 等,否则自动创建失败、消费组提交位点报错。

你可能会懵的地方

  1. 「还要不要 ZooKeeper?」 KRaft(Kafka Raft)自 2.8 引入、3.3 起生产可用,新版镜像不再需要 ZK。读文档认准 KRaft 配置段;面试被问「ZK 在 Kafka 里干什么」也能答出历史职责(Broker 注册、控制器选举)再补一句「已被 KRaft 取代」。

  2. 「容器内 localhost 和宿主机 localhost 是一回事吗?」 不是同一网络命名空间。docker exec 进容器时 localhost:9092 指容器内 Kafka;宿主机上的 Java 也用映射后的 localhost:9092;但另一个容器里连 Kafka 要写服务名(如 kafka:9092),不能写 localhost。

  3. 「create 报 replication 不足 / 内部 topic 建不出来」 单节点默认副本需求没降下来。显式 --replication-factor 1 建业务 Topic,并确认三个 *_REPLICATION_FACTOR / MIN_ISR 环境变量都在。

  4. 「consumer 什么都收不到」 新消费组默认可能从 latest 开始读,或 Topic 名打错。实验加 --from-beginning;用 kafka-topics.sh --list 核对名字。

错法对照

错法问题正解
--replication-factor 3 建在单节点上副本数大于 broker 数必败实验显式 --replication-factor 1
ADVERTISED_LISTENERS 写容器内部地址宿主机客户端拿到不可达地址广播成 PLAINTEXT://localhost:9092
Topic 名每次手滑不一致生产者/消费者连了两个 Topic固定 coderoadmap.order-events 贯穿全 track
以为 compose down 后还能 --from-beginning 读旧消息未挂卷,容器删除数据即丢实验重灌即可;要持久化挂 volume
Compose 里加 ZooKeeper 服务旧写法,镜像不支持联动用 KRaft 环境变量,删 ZK 服务

卡点急救

  1. 容器起不来、日志报 Cluster ID mismatch:旧数据卷与新配置冲突,docker compose down -v 清掉重来(实验数据可丢)。
  2. Java 客户端报 Connection to node 1 could not be established:九成是 advertised listeners 问题。先 telnet localhost 9092 通不通,再核对广播地址是不是 localhost:9092。
  3. 控制台命令「找不到或无法加载主类」:镜像版本差异导致脚本路径不同,先 docker exec kafka-lab ls /opt/kafka/bin 确认真实路径再执行。

面试常问

  • KRaft 和 ZooKeeper 模式有什么区别? 老模式用 ZK 存 Broker 注册信息、做 Controller 选举;KRaft 把元数据放进 Kafka 自己的 Raft quorum(内部 Topic),Controller 与 Broker 合并可单进程运行。好处:少一个重型组件、元数据管理更简单、扩展性与恢复更快。新集群直接上 KRaft。

  • bootstrap-servers 和 advertised.listeners 的关系? bootstrap 只负责第一次连接找入口;连接成功后 Broker 返回集群元数据,其中含每个 Broker 的 advertised 地址,后续读写按广告地址走。所以「能 ping 通 bootstrap 但客户端超时」几乎都是 advertised.listeners 配错。

自测三问

  1. 为什么单节点必须把 KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR 设为 1?不设会看到什么现象?
  2. 先发 3 条再启动 console consumer,加 --from-beginning 能否全收到?不加呢?
  3. Spring 应用与 docker exec 脚本的 bootstrap-servers 各写什么?Java 报连不上时优先查哪两个配置?

小结一句话

会起 KRaft Broker、会建多分区 Topic、会用控制台收发与回放,安装即过关;Spring 只记 localhost:9092。

延伸

  • Apache Kafka Quickstart
  • 下一课「生产者」:用 Java 客户端往这个 Topic 写带 key 的订单事件,把 acks 与回调讲透。
加载本节练习…
← 上一课核心概念下一课 →生产者