Assume that I have a topic with numerous partitions. Im writing K/V data in there and want to aggregate said data in Tumbling Windows by keys.
Assume that I've launched as many worker instances as I have partitions and each worker instance is running on a separate machine.
How would I go about insuring that the resultant aggregations include all values for each key? IE I don't want each worker instance to have some subset of the values.
Is this something that a StateStore would be used for? Does Kafka manage this on its own or do I need to come up with a method?
答案 0 :(得分:8)
我如何确保结果聚合包含每个键的所有值? IE我不希望每个工作者实例都有一些值的子集。
通常,Kafka Streams确保同一个键的所有值都将由同一个(并且只有一个)流任务处理,这也意味着只有一个应用程序实例(您所描述的"工作者实例&#34 ;)将处理该键的值。请注意,应用程序实例可能会运行1个以上的流任务,但这些任务是隔离的。
此行为是通过数据的分区实现的,而Kafka Streams确保分区始终由相同且仅一个流任务处理。键/值的逻辑链接是,在Kafka和Kafka Streams中,键总是被发送到同一个分区(这里有一个问题,但是我不确定是否有意义进入这个问题的范围),因此一个特定的分区 - 在可能的许多分区中 - 包含相同密钥的所有值。
在某些情况下,例如加入两个流A
和B
时,您必须确保聚合将在同一个密钥上运行,以确保来自两个流的数据共存于相同的流任务 - 同样是关于确保相关输入流分区并因此匹配密钥(分别来自A
和B
)在同一流任务中可用。您在此处使用的典型方法是selectKey()
。完成后,Kafka Streams确保,为了加入两个流A和B以及创建连接的输出流,同一个键的所有值将由同一个流任务处理,因此也是相同的应用程序实例。 / p>
示例:
A
的密钥userId
的值为{ georegion }
。B
的密钥georegion
的值为{ continent, description }
。当两个流使用相同的密钥时,仅加入两个流(从Kafka 0.10.0开始)。在此示例中,这意味着您必须重新键入(并因此重新分区)流A
,以便将生成的密钥从userId
更改为georegion
。否则,从Kafka 0.10开始,您无法加入A
和B
,因为数据不会共同位于负责实际执行加入的流任务中。
在此示例中,您可以通过以下方式重新键入/重新分区流A
// Kafka 0.10.0.x (latest stable release as of Sep 2016)
A.map((userId, georegion) -> KeyValue.pair(georegion, userId)).through("rekeyed-topic")
// Upcoming versions of Kafka (not released yet)
A.map((userId, georegion) -> KeyValue.pair(georegion, userId))
仅在Kafka 0.10.0中需要through()
调用以实际触发重新分区,而后续版本的Kafka将自动为您执行这些操作(即将推出的功能已在Kafka中完成并可用{{1 }})。
这是StateStore会用于什么的东西吗? Kafka是自己管理这个还是我需要提出一种方法?
一般来说,没有。上述行为是通过分区实现的,而不是通过状态存储实现的。
由于您为流定义的操作,有时会涉及状态存储,这可能解释了您提出此问题的原因。例如,窗口操作将需要管理状态,因此将在幕后创建状态存储。但是你的实际问题 - "确保最终的聚合包括每个键的所有值" - 与州商店无关,它与分区行为无关。
答案 1 :(得分:1)
对于worker实例,我假设您的意思是Kafka Streams应用程序实例,对吧? (因为Kafka Streams中没有主/工模式 - 它是一个库而不是一个框架 - 我们不使用术语" worker&#34 ;.)
如果要为每个键共同定位数据,则需要按键对数据进行分区。因此,当数据从头开始写入主题时,您的数据将由外部生产者按键分区。或者您在Kafka Streams应用程序中明确设置了一个新密钥(例如使用selectKey()
或map()
),并通过调用through()
重新分发。
(在将来的版本中不需要显式调用through()
,即0.10.1
和Kafka Streams会在必要时自动重新分发记录。)
如果要对消息/记录进行分区,则密钥不能为null
。您还可以通过生产者配置partitioner.class
更改分区架构(请参阅https://kafka.apache.org/documentation.html#producerconfigs)。
分区完全独立于StateStores,即使StateStores通常在分区数据之上使用。