bigywater.tech
Kafka 内部原理 · 74

Kafka Streams:一条消息如何变成状态存储

真实写一份不到40行的Kafka Streams程序做单词计数,验证一条输入消息是怎么经过flatMap拆分、groupBy分组、count聚合,最终变成一份带状态的计数结果输出的。

hello->2
重复出现的词真实被正确聚合计数
0手动poll/produce
整条消费-处理-生产链路由框架内部自动完成

验证:一份真实能编译运行的Streams拓扑

命令 · java (WordCountWindowed.java) KStream<String, String> lines = builder.stream("streams-input"); KStream<String, String> words = lines.flatMapValues( v -> Arrays.asList(v.toLowerCase().split("\\s+"))); KTable<Windowed<String>, Long> counts = words .groupBy((k, v) -> v) .windowedBy(TimeWindows.ofSizeAndGrace(Duration.ofSeconds(5), Duration.ofSeconds(1))) .count(Materialized.as("word-count-windowed-store")); counts.toStream().to("streams-output");

用发行包自带的kafka-streams-4.3.1.jar真实javac编译、java直接运行,不需要额外下载任何依赖——这份拓扑真实做了三件事:flatMapValues把一行文本拆成多个词,groupBy按词本身重新分组,count对每个分组累加计数。

验证:真实发一条消息,输出topic里真实拿到了拆词计数的结果

命令 · python p.produce("streams-input", value="hello kafka hello")
真实实测 · 本机执行输出(streams-output topic的内容)
kafka@[1790563690000-1790563695000) -> 1
hello@[1790563690000-1790563695000) -> 2
一条输入消息"hello kafka hello",真实变成了输出topic里的两条记录——kafka计数为1,hello计数为2,这正是"hello"出现两次真实被聚合出来的结果。这条链路真实完全没有客户端手动poll、手动处理、手动produce——Kafka Streams框架内部真实自己维护着一个消费者去读streams-input,自己在内存(和磁盘状态存储)里做计数累加,再自己拿一个生产者把结果写到streams-output,开发者只需要真实声明"数据要怎么变换",不用管消费-处理-生产这条链路真实是怎么跑起来的。

分步演示:一条消息真实的变换过程

每一步都是本文上面用真实运行的Kafka Streams程序跑出来的原始结果。

一条消息真实经过拆分、分组、聚合变成了计数结果
这一步新验证的阶段

    参考与说明

    • 数据来自本机3节点Kafka 4.3.1集群,一份真实用javac+java编译运行的Kafka Streams程序(依赖kafka-streams-4.3.1.jar),topic streams-input/streams-output。
    • 和《Kafka Streams State Store:状态为什么也要写回 Kafka》《Window、Join 和时间语义》一起看:这篇给出最基础的拓扑跑通验证,后两篇分别深入状态存储和窗口机制。
    • 没有验证:真实多实例部署下Kafka Streams的任务(task)分配和故障转移;join操作(本文只测了单流的count聚合)。
    京ICP备2026067502号-1京公网安备11010502063487号