📋 概览
📋 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()));
执行逻辑:
- 从
quickstart-events主题读取文本行; - 将每行拆分成单词(小写化);
- 按单词分组并计数;
- 将结果写入
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: 清理环境 🧹
-
停止生产者和消费者 :在对应终端按
Ctrl-C。 -
停止 Kafka Broker :在 Kafka 服务终端按
Ctrl-C。 -
删除数据目录 (可选):
bash$ rm -rf /tmp/kafka-logs /tmp/kraft-combined-logs⚠️ 这会删除所有事件数据,仅用于清理本地环境。
💬 小贴士:Kafka 的学习曲线虽然平缓,但要真正驾驭它,还需要亲手搭建项目、调试配置、观察行为。大胆尝试,错误是最好的老师!🚀