【Kafka学习3】Apache Kafka 本地部署环境快速入门指南

📋 概览

📋 Kafka

步骤 名称 核心操作 / 说明
Step 1 下载 Kafka 下载并解压 Kafka 发行包(tar -xzf
Step 2 启动环境 生成集群 UUID,格式化日志目录,启动 Broker(本地脚本或 Docker)
Step 3 创建主题 使用 kafka-topics.sh 创建主题(如 quickstart-events
Step 4 写入事件 使用控制台生产者向主题写入测试事件
Step 5 读取事件 使用控制台消费者从主题读取事件
Step 6 Kafka Connect 导入/导出 运行 Source 和 Sink 连接器,在文件与 Kafka 间同步数据
Step 7 Kafka Streams 流处理 编写流处理应用(如 WordCount),对事件进行实时转换
Step 8 清理环境 停止服务,删除本地数据目录(rm -rf /tmp/kafka-logs

Step 1: 获取 Kafka 📦

首先,下载最新版本的 Kafka 并解压https://www.apache.org/dyn/closer.cgi?path=/kafka/4.3.1/kafka_2.13-4.3.1.tgz

bash 复制代码
# 下载(请替换为最新版本号)
$ tar -xzf kafka_2.13-4.3.1.tgz
$ cd kafka_2.13-4.3.1

📌 说明kafka_2.13-4.3.1.tgz 中,2.13 是 Scala 版本,4.3.1 是 Kafka 版本。解压后进入目录,所有后续命令都在此目录下执行。


Step 2: 启动 Kafka 环境 🔧

前置条件

  • Java 17+ 必须已安装。可以用 java -version 检查。

Kafka 支持两种启动方式:本地脚本Docker 容器。我们分别介绍。


方式一:使用下载的文件(本地脚本)

① 生成集群 UUID

Kafka 4.0+ 使用 KRaft 模式(内置共识协议,不再依赖 ZooKeeper)。每个集群需要一个唯一 ID。

bash 复制代码
$ KAFKA_CLUSTER_ID="$(bin/kafka-storage.sh random-uuid)"
② 格式化日志目录

这会在磁盘上初始化 Kafka 的存储结构。

bash 复制代码
$ bin/kafka-storage.sh format --standalone -t $KAFKA_CLUSTER_ID -c config/server.properties

💡 补充--standalone 表示单节点模式,适合本地测试。-t 指定集群 ID,-c 指定配置文件。

③ 启动 Kafka 服务
bash 复制代码
$ bin/kafka-server-start.sh config/server.properties

看到日志输出 [KafkaServer id=0] started 之类的信息,说明启动成功!🎉


方式二:使用 Docker(JVM 版)

bash 复制代码
# 拉取镜像
$ docker pull apache/kafka:4.3.1

# 启动容器(映射 9092 端口)
$ docker run -p 9092:9092 apache/kafka:4.3.1

方式三:使用 Docker(GraalVM 原生版)

原生镜像启动更快、内存占用更小,适合资源敏感的环境。

bash 复制代码
# 拉取原生镜像
$ docker pull apache/kafka-native:4.3.1

# 启动容器
$ docker run -p 9092:9092 apache/kafka-native:4.3.1

📊 三种启动方式对比

方式 优点 适用场景
本地脚本 可控性强,便于调试 开发、学习、自定义配置
Docker JVM 环境隔离,快速启动 测试、演示、CI/CD
Docker GraalVM 极速启动,内存占用小 云原生、微服务部署

Step 3: 创建主题(Topic)📂

Kafka 中的主题 是事件的逻辑容器,类似于文件系统中的文件夹,而事件就是文件夹里的文件。

📌 在写入任何事件之前,必须先创建主题

打开一个新的终端窗口(保持 Kafka 服务在后台运行),执行:

bash 复制代码
$ bin/kafka-topics.sh --create --topic quickstart-events --bootstrap-server localhost:9092

查看主题详情

bash 复制代码
$ bin/kafka-topics.sh --describe --topic quickstart-events --bootstrap-server localhost:9092

输出示例:

复制代码
Topic: quickstart-events   TopicId: NPmZHyhbR9y00wMglMH2sg   PartitionCount: 1   ReplicationFactor: 1
Topic: quickstart-events   Partition: 0   Leader: 0   Replicas: 0   Isr: 0

💡 解读PartitionCount: 1 表示该主题只有 1 个分区(默认);ReplicationFactor: 1 表示没有副本(单机模式)。


Step 4: 写入事件 ✍️

Kafka 客户端通过网络与 Broker 通信来写入或读取事件。Broker 收到事件后会持久化存储(保留时长由你配置,甚至永久保留)。

使用控制台生产者写入几条事件:

bash 复制代码
$ bin/kafka-console-producer.sh --topic quickstart-events --bootstrap-server localhost:9092
>This is my first event
>This is my second event

每输入一行就发送一条事件。完成后可以用 Ctrl-C 退出生产者。

💡 原理:生产者将事件追加到主题的某个分区。在单分区主题中,所有事件都写入同一个分区,顺序与发送顺序一致。


写入过程示意图

#mermaid-svg-52dinnw50vA0nZPg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-52dinnw50vA0nZPg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-52dinnw50vA0nZPg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-52dinnw50vA0nZPg .error-icon{fill:#552222;}#mermaid-svg-52dinnw50vA0nZPg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-52dinnw50vA0nZPg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-52dinnw50vA0nZPg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-52dinnw50vA0nZPg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-52dinnw50vA0nZPg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-52dinnw50vA0nZPg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-52dinnw50vA0nZPg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-52dinnw50vA0nZPg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-52dinnw50vA0nZPg .marker.cross{stroke:#333333;}#mermaid-svg-52dinnw50vA0nZPg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-52dinnw50vA0nZPg p{margin:0;}#mermaid-svg-52dinnw50vA0nZPg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-52dinnw50vA0nZPg .cluster-label text{fill:#333;}#mermaid-svg-52dinnw50vA0nZPg .cluster-label span{color:#333;}#mermaid-svg-52dinnw50vA0nZPg .cluster-label span p{background-color:transparent;}#mermaid-svg-52dinnw50vA0nZPg .label text,#mermaid-svg-52dinnw50vA0nZPg span{fill:#333;color:#333;}#mermaid-svg-52dinnw50vA0nZPg .node rect,#mermaid-svg-52dinnw50vA0nZPg .node circle,#mermaid-svg-52dinnw50vA0nZPg .node ellipse,#mermaid-svg-52dinnw50vA0nZPg .node polygon,#mermaid-svg-52dinnw50vA0nZPg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-52dinnw50vA0nZPg .rough-node .label text,#mermaid-svg-52dinnw50vA0nZPg .node .label text,#mermaid-svg-52dinnw50vA0nZPg .image-shape .label,#mermaid-svg-52dinnw50vA0nZPg .icon-shape .label{text-anchor:middle;}#mermaid-svg-52dinnw50vA0nZPg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-52dinnw50vA0nZPg .rough-node .label,#mermaid-svg-52dinnw50vA0nZPg .node .label,#mermaid-svg-52dinnw50vA0nZPg .image-shape .label,#mermaid-svg-52dinnw50vA0nZPg .icon-shape .label{text-align:center;}#mermaid-svg-52dinnw50vA0nZPg .node.clickable{cursor:pointer;}#mermaid-svg-52dinnw50vA0nZPg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-52dinnw50vA0nZPg .arrowheadPath{fill:#333333;}#mermaid-svg-52dinnw50vA0nZPg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-52dinnw50vA0nZPg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-52dinnw50vA0nZPg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-52dinnw50vA0nZPg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-52dinnw50vA0nZPg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-52dinnw50vA0nZPg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-52dinnw50vA0nZPg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-52dinnw50vA0nZPg .cluster text{fill:#333;}#mermaid-svg-52dinnw50vA0nZPg .cluster span{color:#333;}#mermaid-svg-52dinnw50vA0nZPg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-52dinnw50vA0nZPg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-52dinnw50vA0nZPg rect.text{fill:none;stroke-width:0;}#mermaid-svg-52dinnw50vA0nZPg .icon-shape,#mermaid-svg-52dinnw50vA0nZPg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-52dinnw50vA0nZPg .icon-shape p,#mermaid-svg-52dinnw50vA0nZPg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-52dinnw50vA0nZPg .icon-shape .label rect,#mermaid-svg-52dinnw50vA0nZPg .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-52dinnw50vA0nZPg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-52dinnw50vA0nZPg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-52dinnw50vA0nZPg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 输入文本
写入事件
分区 P0

控制台生产者
主题: quickstart-events
Kafka 存储


Step 5: 读取事件 📖

打开第三个终端,运行控制台消费者来读取刚刚写入的事件:

bash 复制代码
$ bin/kafka-console-consumer.sh --topic quickstart-events --from-beginning --bootstrap-server localhost:9092

输出:

复制代码
This is my first event
This is my second event

💡 参数说明

  • --from-beginning:从主题的最早消息开始读取(否则只读取启动后的新消息)。
  • 你可以同时打开多个消费者终端,它们都能读到相同的事件------因为 Kafka 的事件消费后不会删除

读写全流程

#mermaid-svg-r7ndrfwZQJFKMpxe{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-r7ndrfwZQJFKMpxe .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-r7ndrfwZQJFKMpxe .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-r7ndrfwZQJFKMpxe .error-icon{fill:#552222;}#mermaid-svg-r7ndrfwZQJFKMpxe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-r7ndrfwZQJFKMpxe .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-r7ndrfwZQJFKMpxe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-r7ndrfwZQJFKMpxe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-r7ndrfwZQJFKMpxe .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-r7ndrfwZQJFKMpxe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-r7ndrfwZQJFKMpxe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-r7ndrfwZQJFKMpxe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-r7ndrfwZQJFKMpxe .marker.cross{stroke:#333333;}#mermaid-svg-r7ndrfwZQJFKMpxe svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-r7ndrfwZQJFKMpxe p{margin:0;}#mermaid-svg-r7ndrfwZQJFKMpxe .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-r7ndrfwZQJFKMpxe .cluster-label text{fill:#333;}#mermaid-svg-r7ndrfwZQJFKMpxe .cluster-label span{color:#333;}#mermaid-svg-r7ndrfwZQJFKMpxe .cluster-label span p{background-color:transparent;}#mermaid-svg-r7ndrfwZQJFKMpxe .label text,#mermaid-svg-r7ndrfwZQJFKMpxe span{fill:#333;color:#333;}#mermaid-svg-r7ndrfwZQJFKMpxe .node rect,#mermaid-svg-r7ndrfwZQJFKMpxe .node circle,#mermaid-svg-r7ndrfwZQJFKMpxe .node ellipse,#mermaid-svg-r7ndrfwZQJFKMpxe .node polygon,#mermaid-svg-r7ndrfwZQJFKMpxe .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-r7ndrfwZQJFKMpxe .rough-node .label text,#mermaid-svg-r7ndrfwZQJFKMpxe .node .label text,#mermaid-svg-r7ndrfwZQJFKMpxe .image-shape .label,#mermaid-svg-r7ndrfwZQJFKMpxe .icon-shape .label{text-anchor:middle;}#mermaid-svg-r7ndrfwZQJFKMpxe .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-r7ndrfwZQJFKMpxe .rough-node .label,#mermaid-svg-r7ndrfwZQJFKMpxe .node .label,#mermaid-svg-r7ndrfwZQJFKMpxe .image-shape .label,#mermaid-svg-r7ndrfwZQJFKMpxe .icon-shape .label{text-align:center;}#mermaid-svg-r7ndrfwZQJFKMpxe .node.clickable{cursor:pointer;}#mermaid-svg-r7ndrfwZQJFKMpxe .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-r7ndrfwZQJFKMpxe .arrowheadPath{fill:#333333;}#mermaid-svg-r7ndrfwZQJFKMpxe .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-r7ndrfwZQJFKMpxe .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-r7ndrfwZQJFKMpxe .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-r7ndrfwZQJFKMpxe .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-r7ndrfwZQJFKMpxe .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-r7ndrfwZQJFKMpxe .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-r7ndrfwZQJFKMpxe .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-r7ndrfwZQJFKMpxe .cluster text{fill:#333;}#mermaid-svg-r7ndrfwZQJFKMpxe .cluster span{color:#333;}#mermaid-svg-r7ndrfwZQJFKMpxe div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-r7ndrfwZQJFKMpxe .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-r7ndrfwZQJFKMpxe rect.text{fill:none;stroke-width:0;}#mermaid-svg-r7ndrfwZQJFKMpxe .icon-shape,#mermaid-svg-r7ndrfwZQJFKMpxe .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-r7ndrfwZQJFKMpxe .icon-shape p,#mermaid-svg-r7ndrfwZQJFKMpxe .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-r7ndrfwZQJFKMpxe .icon-shape .label rect,#mermaid-svg-r7ndrfwZQJFKMpxe .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-r7ndrfwZQJFKMpxe .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-r7ndrfwZQJFKMpxe .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-r7ndrfwZQJFKMpxe :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 写入
持久化存储
读取
读取
生产者
主题
磁盘
消费者1
消费者2


Step 6: 使用 Kafka Connect 导入/导出数据 🔄

你的现有系统(数据库、文件、消息队列)中可能已经有大量数据。Kafka Connect 就是用来持续导入/导出数据的工具,它通过连接器(Connector) 与外部系统交互。

在本教程中,我们用 File Source Connector 从文件读数据到 Kafka,再用 File Sink Connector 从 Kafka 写数据到文件。


① 配置插件路径

编辑 config/connect-standalone.properties,加入:

bash 复制代码
$ echo "plugin.path=libs/connect-file-4.3.1.jar" >> config/connect-standalone.properties

💡 这告诉 Kafka Connect 去哪里找连接器插件。


② 准备种子数据

创建一个包含两行文本的测试文件:

bash 复制代码
$ echo -e "foo\nbar" > test.txt

③ 启动 Kafka Connect(Standalone 模式)

bash 复制代码
$ bin/connect-standalone.sh config/connect-standalone.properties config/connect-file-source.properties config/connect-file-sink.properties

启动后,你会看到日志中出现连接器实例化的信息。

  • Source Connector :读取 test.txt 的每一行,作为事件写入主题 connect-test
  • Sink Connector :从主题 connect-test 读取事件,逐行写入 test.sink.txt

④ 验证结果

bash 复制代码
$ more test.sink.txt
foo
bar

也可以用控制台消费者查看主题中的数据:

bash 复制代码
$ bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic connect-test --from-beginning

输出(JSON 格式,包含 schema 和 payload):

json 复制代码
{"schema":{"type":"string","optional":false},"payload":"foo"}
{"schema":{"type":"string","optional":false},"payload":"bar"}

⑤ 动态追加数据

test.txt 中追加一行:

bash 复制代码
$ echo "Another line" >> test.txt

你会发现消费者终端和 test.sink.txt 中立即出现了新数据------这就是实时数据流的魅力!


Kafka Connect 工作流程图

#mermaid-svg-9QaJ2q92gEXD2qGZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9QaJ2q92gEXD2qGZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9QaJ2q92gEXD2qGZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9QaJ2q92gEXD2qGZ .error-icon{fill:#552222;}#mermaid-svg-9QaJ2q92gEXD2qGZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9QaJ2q92gEXD2qGZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9QaJ2q92gEXD2qGZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9QaJ2q92gEXD2qGZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9QaJ2q92gEXD2qGZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9QaJ2q92gEXD2qGZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9QaJ2q92gEXD2qGZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9QaJ2q92gEXD2qGZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9QaJ2q92gEXD2qGZ .marker.cross{stroke:#333333;}#mermaid-svg-9QaJ2q92gEXD2qGZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9QaJ2q92gEXD2qGZ p{margin:0;}#mermaid-svg-9QaJ2q92gEXD2qGZ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9QaJ2q92gEXD2qGZ .cluster-label text{fill:#333;}#mermaid-svg-9QaJ2q92gEXD2qGZ .cluster-label span{color:#333;}#mermaid-svg-9QaJ2q92gEXD2qGZ .cluster-label span p{background-color:transparent;}#mermaid-svg-9QaJ2q92gEXD2qGZ .label text,#mermaid-svg-9QaJ2q92gEXD2qGZ span{fill:#333;color:#333;}#mermaid-svg-9QaJ2q92gEXD2qGZ .node rect,#mermaid-svg-9QaJ2q92gEXD2qGZ .node circle,#mermaid-svg-9QaJ2q92gEXD2qGZ .node ellipse,#mermaid-svg-9QaJ2q92gEXD2qGZ .node polygon,#mermaid-svg-9QaJ2q92gEXD2qGZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9QaJ2q92gEXD2qGZ .rough-node .label text,#mermaid-svg-9QaJ2q92gEXD2qGZ .node .label text,#mermaid-svg-9QaJ2q92gEXD2qGZ .image-shape .label,#mermaid-svg-9QaJ2q92gEXD2qGZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-9QaJ2q92gEXD2qGZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-9QaJ2q92gEXD2qGZ .rough-node .label,#mermaid-svg-9QaJ2q92gEXD2qGZ .node .label,#mermaid-svg-9QaJ2q92gEXD2qGZ .image-shape .label,#mermaid-svg-9QaJ2q92gEXD2qGZ .icon-shape .label{text-align:center;}#mermaid-svg-9QaJ2q92gEXD2qGZ .node.clickable{cursor:pointer;}#mermaid-svg-9QaJ2q92gEXD2qGZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-9QaJ2q92gEXD2qGZ .arrowheadPath{fill:#333333;}#mermaid-svg-9QaJ2q92gEXD2qGZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9QaJ2q92gEXD2qGZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9QaJ2q92gEXD2qGZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9QaJ2q92gEXD2qGZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-9QaJ2q92gEXD2qGZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9QaJ2q92gEXD2qGZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-9QaJ2q92gEXD2qGZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9QaJ2q92gEXD2qGZ .cluster text{fill:#333;}#mermaid-svg-9QaJ2q92gEXD2qGZ .cluster span{color:#333;}#mermaid-svg-9QaJ2q92gEXD2qGZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9QaJ2q92gEXD2qGZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9QaJ2q92gEXD2qGZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-9QaJ2q92gEXD2qGZ .icon-shape,#mermaid-svg-9QaJ2q92gEXD2qGZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9QaJ2q92gEXD2qGZ .icon-shape p,#mermaid-svg-9QaJ2q92gEXD2qGZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-9QaJ2q92gEXD2qGZ .icon-shape .label rect,#mermaid-svg-9QaJ2q92gEXD2qGZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9QaJ2q92gEXD2qGZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9QaJ2q92gEXD2qGZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9QaJ2q92gEXD2qGZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Source Connector
Sink Connector
可选
test.txt
主题: connect-test
test.sink.txt
控制台消费者

组件 角色 数据流向
File Source 源连接器 文件 → Kafka 主题
File Sink 目标连接器 Kafka 主题 → 文件
Console Consumer 独立消费者 Kafka 主题 → 控制台

Step 7: 用 Kafka Streams 处理事件 ⚙️

Kafka Streams 是一个轻量级的 Java/Scala 客户端库,让你可以构建实时流处理应用。它支持:

  • 状态操作与聚合
  • 窗口计算(时间窗口、会话窗口)
  • 多流 Join
  • 事件时间(Event-time)处理
  • 精确一次(Exactly-once) 语义

WordCount 示例(代码片段)

下面这段代码实现了经典的单词计数算法:

java 复制代码
KStream<String, String> textLines = builder.stream("quickstart-events");

KTable<String, Long> wordCounts = textLines
    .flatMapValues(line -> Arrays.asList(line.toLowerCase().split(" ")))
    .groupBy((keyIgnored, word) -> word)
    .count();

wordCounts.toStream().to("output-topic", Produced.with(Serdes.String(), Serdes.Long()));

执行逻辑

  1. quickstart-events 主题读取文本行;
  2. 将每行拆分成单词(小写化);
  3. 按单词分组并计数;
  4. 将结果写入 output-topic 主题。

💡 你可以把这段代码嵌入一个完整的 Java 应用中运行。Kafka Streams 应用可以水平扩展,多个实例共同处理数据,自动负载均衡。


流处理管道图

#mermaid-svg-4nHSJeCSqfhPJ8VK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4nHSJeCSqfhPJ8VK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4nHSJeCSqfhPJ8VK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4nHSJeCSqfhPJ8VK .error-icon{fill:#552222;}#mermaid-svg-4nHSJeCSqfhPJ8VK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4nHSJeCSqfhPJ8VK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4nHSJeCSqfhPJ8VK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4nHSJeCSqfhPJ8VK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4nHSJeCSqfhPJ8VK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4nHSJeCSqfhPJ8VK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4nHSJeCSqfhPJ8VK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4nHSJeCSqfhPJ8VK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4nHSJeCSqfhPJ8VK .marker.cross{stroke:#333333;}#mermaid-svg-4nHSJeCSqfhPJ8VK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4nHSJeCSqfhPJ8VK p{margin:0;}#mermaid-svg-4nHSJeCSqfhPJ8VK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4nHSJeCSqfhPJ8VK .cluster-label text{fill:#333;}#mermaid-svg-4nHSJeCSqfhPJ8VK .cluster-label span{color:#333;}#mermaid-svg-4nHSJeCSqfhPJ8VK .cluster-label span p{background-color:transparent;}#mermaid-svg-4nHSJeCSqfhPJ8VK .label text,#mermaid-svg-4nHSJeCSqfhPJ8VK span{fill:#333;color:#333;}#mermaid-svg-4nHSJeCSqfhPJ8VK .node rect,#mermaid-svg-4nHSJeCSqfhPJ8VK .node circle,#mermaid-svg-4nHSJeCSqfhPJ8VK .node ellipse,#mermaid-svg-4nHSJeCSqfhPJ8VK .node polygon,#mermaid-svg-4nHSJeCSqfhPJ8VK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4nHSJeCSqfhPJ8VK .rough-node .label text,#mermaid-svg-4nHSJeCSqfhPJ8VK .node .label text,#mermaid-svg-4nHSJeCSqfhPJ8VK .image-shape .label,#mermaid-svg-4nHSJeCSqfhPJ8VK .icon-shape .label{text-anchor:middle;}#mermaid-svg-4nHSJeCSqfhPJ8VK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-4nHSJeCSqfhPJ8VK .rough-node .label,#mermaid-svg-4nHSJeCSqfhPJ8VK .node .label,#mermaid-svg-4nHSJeCSqfhPJ8VK .image-shape .label,#mermaid-svg-4nHSJeCSqfhPJ8VK .icon-shape .label{text-align:center;}#mermaid-svg-4nHSJeCSqfhPJ8VK .node.clickable{cursor:pointer;}#mermaid-svg-4nHSJeCSqfhPJ8VK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-4nHSJeCSqfhPJ8VK .arrowheadPath{fill:#333333;}#mermaid-svg-4nHSJeCSqfhPJ8VK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4nHSJeCSqfhPJ8VK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4nHSJeCSqfhPJ8VK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4nHSJeCSqfhPJ8VK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4nHSJeCSqfhPJ8VK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4nHSJeCSqfhPJ8VK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-4nHSJeCSqfhPJ8VK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4nHSJeCSqfhPJ8VK .cluster text{fill:#333;}#mermaid-svg-4nHSJeCSqfhPJ8VK .cluster span{color:#333;}#mermaid-svg-4nHSJeCSqfhPJ8VK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4nHSJeCSqfhPJ8VK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4nHSJeCSqfhPJ8VK rect.text{fill:none;stroke-width:0;}#mermaid-svg-4nHSJeCSqfhPJ8VK .icon-shape,#mermaid-svg-4nHSJeCSqfhPJ8VK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4nHSJeCSqfhPJ8VK .icon-shape p,#mermaid-svg-4nHSJeCSqfhPJ8VK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-4nHSJeCSqfhPJ8VK .icon-shape .label rect,#mermaid-svg-4nHSJeCSqfhPJ8VK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4nHSJeCSqfhPJ8VK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-4nHSJeCSqfhPJ8VK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-4nHSJeCSqfhPJ8VK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 读取
拆分/分组/计数
写入
主题: quickstart-events
Kafka Streams 应用
KTable 状态表
主题: output-topic


Step 8: 清理环境 🧹

  1. 停止生产者和消费者 :在对应终端按 Ctrl-C

  2. 停止 Kafka Broker :在 Kafka 服务终端按 Ctrl-C

  3. 删除数据目录 (可选):

    bash 复制代码
    $ rm -rf /tmp/kafka-logs /tmp/kraft-combined-logs

    ⚠️ 这会删除所有事件数据,仅用于清理本地环境。


💬 小贴士:Kafka 的学习曲线虽然平缓,但要真正驾驭它,还需要亲手搭建项目、调试配置、观察行为。大胆尝试,错误是最好的老师!🚀


相关推荐
世人万千丶1 小时前
HarmonyOS 股票 K 线图完整源码与金融图表模板
学习·华为·金融·harmonyos·鸿蒙
210Brian2 小时前
STM32学习笔记(七)TIM定时中断(上)
笔记·stm32·学习
渣渣盟3 小时前
Flink + Kafka 数据写入实战:从API调用到端到端一致性精讲
flink·kafka·linq
海兰3 小时前
【Kafka学习2】Apache Kafka 典型应用场景
学习·kafka·apache
边境悍匪3 小时前
蜗牛学苑 Java 学习 Day23|SpringBoot 思维导图复盘
学习
heimeiyingwang3 小时前
【架构实战】消息队列选型与异步架构设计:从Kafka到RabbitMQ,一次聊透
架构·kafka·rabbitmq
xx~t3 小时前
嵌入式学习22
数据结构·学习·算法·排序算法
Linux-lucky12 小时前
21-Linux学习之旅之HTTPS和安全加固
linux·运维·学习·ubuntu·https
学运维的Kysan14 小时前
暑假运维学习打卡第二十六天8.17
学习