我们目前正在实施一个流程(使用Kafka Processor API),我们需要将来自两个相关事件(消息)的信息组合在一个主题上,然后转发这些组合信息。事件源自IoT设备,并且由于我们希望将它们保持有序,因此源主题使用设备标识符作为密钥。事件还包含相关ID:
关键
{ deviceId: "..." }
消息
{ deviceId: "...", correlationId: "...", data: ...}
我们的第一种方法是创建一个具有连接状态存储的处理器,该存储使用相关ID作为密钥存储每个传入消息。这使我们能够在商店中查询传入消息的相关ID,如果商店中已经存在具有相同ID的消息,我们可以组合信息,转发新事件并从商店中删除条目。因此,对于每个相关ID,会发生以下情况:在某些时候,使用并存储具有该ID的第一条消息,并且在该时间的某个其他时间点,具有该ID的第二条消息导致存储条目被移除。
状态键
{ correlationId: "..." }
州价值
{ event: { deviceId: "...", correlationId: "...", data: ... }}
但现在我们想知道Kafka Streams如何处理不同的密钥。我们正在使用微服务方法,并且将运行该服务的多个实例。商店由内部主题自动支持。考虑重新调整服务实例,s.t。重新平衡源主题和状态主题的分区。是否可能将特定相关ID的分区分配给除相应设备ID的分区之外的其他服务?我们能否最终处于这样一种情况:服务实例将使用相同ID的第二个事件,而该服务实例无法访问已存储的第一个事件?
提前致谢!
答案 0 :(得分:4)
如果我理解你的设置正确,那么是的,方法是正确的,并且(重新)缩放将起作用。
TL; DR:如果流任务从机器A移动到机器B,那么它的所有状态也将被移动,无论该状态是如何键入的(在你的情况下它恰好被{{1键入) }})。
更详细:
correlationId
键控)以确定的方式将输入分区映射到流任务来实现的。这确保了即使在跨机器/ VM /容器移动流任务时,他们也总是看到"他们的"输入分区=他们的输入数据。deviceId
键入的一个州商店。对你的问题来说重要的是,关键是如何锁定国家。输入分区的键控方式非常重要,因为它确定了哪些数据从输入主题流向特定的流任务(请参阅上一个要点)。当流任务跨机器/ VM /容器移动时,它的所有状态也将被移动,以便它始终具有自己的"国家可用。商店由内部主题自动支持。
正如您已经建议的那样,商店具有内部主题(用于容错和弹性扩展,因为内部主题用于在其流任务从A移动到B时重建状态存储)这一事实是一个实现细节。作为使用Kafka Streams API的开发人员,可以自动,透明地完成状态存储恢复的处理。
当移动流任务及其状态存储时,Kafka Streams知道如何在流任务的新位置重建状态存储。你不必担心这一点。
是否可能将特定相关ID的分区分配给除相应设备ID的分区之外的其他服务?
不(这很好)。流任务将始终知道如何重建其状态(1+状态存储),无论该状态本身是如何键入的。
我们最终是否会遇到一个具有相同关联ID的第二个事件将被服务实例消耗,该服务实例无法访问已存储的第一个事件?
不(这很好)。