Kafka Streams 处理器 - 状态存储和输入主题分区
Kafka Streams processors - state store and input topic partitioning
我想完全理解 kafka-streams 处理器必须遵守的关于处理器输入及其状态分区的规则。具体我想了解一下:
- 状态存储使用与输入主题的密钥不同的密钥是否可能以及潜在的后果是什么
- 状态存储密钥是否跨分区共享,即如果我在处理属于两个不同分区的记录时尝试访问处理器中的相同密钥,我是否会得到相同的值
我一直在对此进行一些研究,但我发现的答案似乎不是很清楚,有时甚至是矛盾的:例如 seems to suggest that the stores are totally independent and you can use any key while this one 说你永远不应该使用与输入主题中的密钥不同的商店。
感谢您的澄清。
您必须区分输入分区并存储 shards/changelog 个主题分区以获得完整的图片。此外,这取决于您使用的是 DSL 还是处理器 API,因为 DSL 会进行一些自动重新分区,但处理器 API 不会。因为 DSL 编译为处理器 API,我将从这里开始。
如果您有一个主题,假设有 4 个分区,并且您创建了一个使用该主题的有状态处理器,您将获得 4 个任务,每个任务 运行 一个维护存储的一个分片的处理器实例。请注意,整体状态分为 4 个分片,每个分片基本上与其他分片隔离。
从处理器 API 运行时的角度来看,输入主题分区和状态存储分片(包括它们对应的更新日志主题分区)是一个并行单元。因此,存储的变更日志主题是用 4 个分区创建的,变更日志主题分区 X 映射到输入主题分区 X。请注意,Kafka Streams 在写入更新日志主题时 不 使用基于散列的分区,但明确提供分区号,以确保 "processor instance X" 处理输入主题-partition-X,仅 reads/write from/into changelog-topic-partition-X.
因此,如果您愿意,运行时与密钥无关。
如果您输入的主题没有按键分区,具有相同键的消息将由不同的任务处理。根据程序的不同,这可能是正确的(例如过滤),也可能不是(例如,按键计数)。
类似于state:你可以将任何key放入state store,但是这个key是"local"对应的分片。其他任务,永远不会看到这个键。因此,如果您在商店中的不同任务上使用相同的密钥,它们将彼此完全独立(就好像它们是两个密钥一样)。
使用处理器 API,您有责任正确划分输入数据并正确使用存储,具体取决于您需要的运算符语义。
在 DSL 级别,Kafka Streams 将确保数据被正确分区以确保正确的运算符语义。首先,假设输入主题是按键划分的。如果键被修改,例如通过 selectKey()
并且下游运算符是一个聚合,Kafka Streams 会首先重新分区数据,以确保具有相同键的记录在同一个主题分区中。这确保了每个键都将在单个存储分片中使用。因此,DSL 将始终对数据进行分区,这样一个键永远不会在不同的分片上处理。
我想完全理解 kafka-streams 处理器必须遵守的关于处理器输入及其状态分区的规则。具体我想了解一下:
- 状态存储使用与输入主题的密钥不同的密钥是否可能以及潜在的后果是什么
- 状态存储密钥是否跨分区共享,即如果我在处理属于两个不同分区的记录时尝试访问处理器中的相同密钥,我是否会得到相同的值
我一直在对此进行一些研究,但我发现的答案似乎不是很清楚,有时甚至是矛盾的:例如
感谢您的澄清。
您必须区分输入分区并存储 shards/changelog 个主题分区以获得完整的图片。此外,这取决于您使用的是 DSL 还是处理器 API,因为 DSL 会进行一些自动重新分区,但处理器 API 不会。因为 DSL 编译为处理器 API,我将从这里开始。
如果您有一个主题,假设有 4 个分区,并且您创建了一个使用该主题的有状态处理器,您将获得 4 个任务,每个任务 运行 一个维护存储的一个分片的处理器实例。请注意,整体状态分为 4 个分片,每个分片基本上与其他分片隔离。
从处理器 API 运行时的角度来看,输入主题分区和状态存储分片(包括它们对应的更新日志主题分区)是一个并行单元。因此,存储的变更日志主题是用 4 个分区创建的,变更日志主题分区 X 映射到输入主题分区 X。请注意,Kafka Streams 在写入更新日志主题时 不 使用基于散列的分区,但明确提供分区号,以确保 "processor instance X" 处理输入主题-partition-X,仅 reads/write from/into changelog-topic-partition-X.
因此,如果您愿意,运行时与密钥无关。
如果您输入的主题没有按键分区,具有相同键的消息将由不同的任务处理。根据程序的不同,这可能是正确的(例如过滤),也可能不是(例如,按键计数)。
类似于state:你可以将任何key放入state store,但是这个key是"local"对应的分片。其他任务,永远不会看到这个键。因此,如果您在商店中的不同任务上使用相同的密钥,它们将彼此完全独立(就好像它们是两个密钥一样)。
使用处理器 API,您有责任正确划分输入数据并正确使用存储,具体取决于您需要的运算符语义。
在 DSL 级别,Kafka Streams 将确保数据被正确分区以确保正确的运算符语义。首先,假设输入主题是按键划分的。如果键被修改,例如通过 selectKey()
并且下游运算符是一个聚合,Kafka Streams 会首先重新分区数据,以确保具有相同键的记录在同一个主题分区中。这确保了每个键都将在单个存储分片中使用。因此,DSL 将始终对数据进行分区,这样一个键永远不会在不同的分片上处理。