Kafka KTable - 跨机器共享聚合

eth*_*nny 4 java apache-kafka apache-kafka-streams

假设我有一个包含大量分区的主题.我在那里写K/V数据,并希望通过键在Tumbling Windows中聚合所述数据.

假设我启动了尽可能多的工作实例,因为我有分区,每个工作器实例都在一台单独的机器上运行.

我如何确保结果聚合包含每个键的所有值?IE我不希望每个工作者实例都有一些值的子集.

这是StateStore会用于什么的东西吗?Kafka是自己管理这个还是我需要提出一种方法?

Mic*_*oll 8

我如何确保结果聚合包含每个键的所有值?IE我不希望每个工作者实例都有一些值的子集.

通常,Kafka Streams确保同一个键的所有值都将由同一个(并且只有一个)流任务处理,这也意味着只有一个应用程序实例(您描述为"工作者实例")将处理该值的值键.请注意,应用程序实例可能会运行1个以上的流任务,但这些任务是隔离的.

此行为是通过对数据进行分区来实现的,而Kafka Streams确保分区始终由相同且仅一个流任务处理.键/值的逻辑链接是,在Kafka和Kafka Streams中,键总是被发送到同一个分区(这里有一个问题,但我不确定是否有必要详细讨论范围这个问题),因此一个特定的分区 - 在可能的许多分区中 - 包含相同密钥的所有值.

在某些情况下,这种连接两个流时为AB,你必须确保虽然对于聚合将同一个按键上操作,以确保这两个流共存于同一个流任务的数据-这又是怎么一回事确保相关的输入流分区并因此匹配密钥(分别来自AB分别)在同一流任务中可用.您在这里使用的典型方法是selectKey().完成后,Kafka Streams确保,为了加入两个流A和B以及创建连接的输出流,同一个键的所有值将由同一个流任务处理,因此也是同一个应用程序实例.

例:

  • 流有价值的A关键.userId{ georegion }
  • 流有价值的B关键.georegion{ continent, description }

当两个流使用相同的密钥时,仅连接两个流(从Kafka 0.10.0开始).在此示例中,这意味着您必须重新键入(并因此重新分区)流,A以便将生成的密钥从更改userIdgeoregion.否则,从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))
Run Code Online (Sandbox Code Playgroud)

through()调用仅在Kafka 0.10.0中需要实际触发重新分区,而后续版本的Kafka将自动为您执行这些操作(即将推出的功能已在Kafka中完成并可用trunk).

这是StateStore会用于什么的东西吗?Kafka是自己管理这个还是我需要提出一种方法?

一般来说,没有.上述行为是通过分区而不是通过状态存储来实现的.

有时因为您为流定义的操作而涉及状态存储,这可能解释了您提出此问题的原因.例如,窗口操作将需要管理状态,因此将在幕后创建状态存储.但是你的实际问题 - "确保结果聚合包括每个键的所有值" - 与状态存储无关,而是与分区行为无关.