bigywater.tech
Kafka 内部原理 · 76

Window、Join 和时间语义

在同一个key跨越5秒窗口边界前后各发一批消息,验证窗口聚合的计数是真实独立的、不会跨窗口累加,理解为什么Join操作也必须依赖时间窗口来限定关联范围。

2,不是4
跨窗口后同一个key真实的独立计数结果
5000ms
两个窗口起始时间戳真实精确相差的时长

验证:同一个key,跨越窗口边界后计数真实重新开始

命令 · python p.produce("streams-input", value="hello kafka hello") # t=0秒 time.sleep(6) # 真实等超过5秒的窗口大小 p.produce("streams-input", value="hello streams hello") # t=6秒,真实进入下一个窗口
真实实测 · 本机执行输出
kafka@[1790563690000-1790563695000) -> 1
hello@[1790563690000-1790563695000) -> 2
streams@[1790563695000-1790563700000) -> 1
hello@[1790563695000-1790563700000) -> 2

真实关键的观察:第二批消息里的"hello",计数真实是2,不是4——它没有跟第一批的hello累加,而是真实在一个全新的窗口[1790563695000-1790563700000)里重新从0开始计数。两个窗口的起始时间戳真实精确相差5000毫秒(1790563695000-1790563690000),跟代码里配置的TimeWindows.ofSizeAndGrace(Duration.ofSeconds(5), ...)完全对上。

结论:窗口真实把无限的流,切成了一段段可以聚合的"有限数据集"

流处理真实面对的是一个永不停止的数据流,"总共出现了多少次hello"这种问题在无限流上真实没有意义——总数会一直增长,永远给不出一个"最终答案"。窗口真实解决的正是这个问题:把无限流按时间切成一段段5秒的有限区间,在每个区间内部做真实完整的聚合,每个区间有自己独立的、真实封闭的计数结果。这也是Join操作真实必须依赖窗口的原因——两个独立的流要做关联,"哪些记录应该被视为同一时刻发生的"这件事,如果不用时间窗口框定一个真实的时间范围,理论上一条来自10年前的记录都可能被拿去跟今天的记录做join,这既不合理也没法真实在有限内存里实现。窗口时间语义还分事件时间(消息真实产生的时间)和处理时间(Streams应用真实处理到这条消息的时间)——本文用的是默认的事件时间语义,窗口边界依据的是消息真实携带的时间戳,不是Streams处理它的那一刻的系统时间。

分步演示:窗口真实是怎么隔离聚合结果的

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

跨越窗口边界,同一个key的计数真实重新开始
这一步新验证的窗口

    参考与说明

    • 数据来自本机3节点Kafka 4.3.1集群,前两篇同一个wordcount-windowed-app应用(TimeWindows.ofSizeAndGrace(5秒, 1秒宽限期))。
    • 和《Kafka Streams:一条消息如何变成状态存储》一起看:那篇验证了单个窗口内的聚合结果,这篇验证跨窗口时计数真实是独立的。
    • 没有验证:真实的Join操作(本文只测了单流窗口聚合,没有做两个流的关联);乱序数据(消息真实到达顺序跟事件时间顺序不一致)在宽限期(grace period)内真实的处理行为。
    京ICP备2026067502号-1京公网安备11010502063487号