我想充分理解kafka-streams处理器在划分处理器输入及其状态时必须遵循的规则。具体来说,我想了解:
我一直在对此进行一些研究,发现的答案似乎不是很清楚,有时甚至是矛盾的: this one似乎暗示商店是完全独立的,并且您可以使用任何键,而this one则说您不应使用与输入主题中的钥匙不同的商店。
感谢您的澄清。
答案 0 :(得分:3)
您必须区分输入分区,并存储分片/更改日志主题分区以获取完整图片。另外,这取决于您使用DSL还是Processor API,因为DSL会进行一些自动重新分区,但Processor API不会。因为DSL可以编译为Processor API,所以我将从这里开始。
如果您有一个带有4个分区的主题,并且创建了一个使用此主题的有状态处理器,那么您将获得4个任务,每个任务运行一个处理器实例,该实例维护一个存储区。请注意,整体状态分为4个分片,每个分片基本上与其他分片隔离。
从Processor API运行时的角度来看,输入主题分区和状态存储碎片(包括其对应的changelog主题分区)是并行度的单位。因此,将使用4个分区创建商店的changelog主题,并将changelog-topic-partition-X映射到input-topic-partition-X。请注意,Kafka Streams在写入更改日志主题时不会不使用基于哈希的分区,但是会明确提供分区号,以确保“处理器实例X”能够处理input-topic-partition- X,仅从changelog-topic-partition-X中读取/写入。
因此,如果需要,运行时与密钥无关。
如果输入主题不是按键划分的,则具有相同键的消息将由不同的任务处理。根据程序的不同,可能没有问题(例如过滤),也可能没有问题(例如每个键计数)。
类似于状态:您可以将任何密钥放入状态存储,但是此密钥对于相应的分片是“本地的”。其他任务,将永远不会看到此键。因此,如果您在商店中使用相同的密钥执行不同的任务,则它们将彼此完全独立(就像它们将是两个密钥一样)。
使用Processor API,您有责任根据所需的运算符语义正确划分输入数据并正确使用存储。
在DSL级别,Kafka Streams将确保正确划分数据以确保正确的操作员语义。首先,假设输入主题按键划分。如果例如通过selectKey()
修改了键,并且下游运算符是一个聚合,那么Kafka Streams会首先对数据进行重新分区,以确保具有相同键的记录位于同一主题分区中。这样可以确保每个密钥将在单个存储碎片中使用。因此,DSL将始终对数据进行分区,以使一个密钥永远不会在不同的分片上进行处理。