Kafka Streams-通过地址聚合和加入用户

时间:2018-12-03 09:37:23

标签: apache-kafka apache-kafka-streams

我有两个紧凑的主题。一个包含有关我的用户的所有信息( USERID ),另一个保存他们的地址( USERID ADRESSID )。括号中是键。我想要的是仅将一个主题用户数据及其地址列表保存在其中。我的方法是这样:

KTable<GenericRecord, ArrayList<GenericRecord>> aggregatedAddresses = adressStream
.selectKey(...) //Selecting USERID as key - this generates KStream
.groupByKey(...) //Grouping by USERID as key - this generates KGroupedStream
.aggregate(...) //Aggregating by USERID as key - this generates KTable
.to("aggregated_addresses"); //KTable with USERID as key 
最后,我在USERID上对user和aggregated_addresses进行leftJoin并将结果保存到名为“ user_addresses”的压缩主题中。

我想实现将所有数据及其地址保留在user_addresses中。这意味着我不想在一段时间后丢失任何地址。仅当数据库中的地址被删除时。我的问题是我的方法是否可以实现这一目标。我的原型正在运行,并且正在向每个用户保存地址列表,但是我问自己KGroupedStream是否会在一段时间后删除一些流。

也许有人可以向我详细解释该管道的工作方式。如果有新的流(地址)进入整个流水线(selectKey,groupByKey,aggregate),并最终到达主题aggregated_addresses,将其另存为地址列表?步骤汇总正在使用以下语句:

(user, address, queue) -> {...}

Kafka流是否使用aggregated_addresses填充上述语句的队列?我是的,如果有新的流到达。aggregate,卡夫卡会在aggregated_addresses中搜索其对应的聚合列表并用此数据填充队列吗?还是使用.groupByKey的分组流,并且每当有新流进入时,整个分组流就被发送以进行汇总?如果第二个为真,例如会在一周后KGroupedStream删除某些流吗?如果是,队列中会缺少一些地址?

KGroupedStream和KGroupedTable在内部有什么区别?

有趣的是,联接后的结果(在一个紧凑的主题中称为user_addresses)具有比用户表项更多的表项。我更深入地看,发现具有相同键的用户多次出现(多个偏移量)。在最小偏移量处,该用户没有地址,然后在较高偏移量处,该用户列表中有一个地址,而最大偏移量时,该用户列表中有两个地址。我再次问自己,当我使用压缩主题时,为什么旧​​的偏移量不会自动删除。 Kafka的压缩是否像垃圾收集器那样工作,之后将数据删除?如果我正在寻找钥匙,那我会得到偏移量最大的钥匙吗?

对于这么多问题我感到很抱歉,但是随着我对流的使用越来越多,一些事情对我来说还不清楚。

预先感谢您的帮助! :)

1 个答案:

答案 0 :(得分:1)

  

我问自己KGroupedStream是否会在一段时间后删除某些流。

它不会删除任何内容。

如果我理解您的其余问题,则您正在询问aggregate()运算符的工作方式。它使用本地状态存储(使用RocksDB实现)存储<userId, X>,其中X是聚合UDF((user, address, queue) -> { })返回的值,即应为X == queue。因此,每个输入记录都会在RocksDB中进行本地查找,以获取当前的queue,对其进行更新,将其写回到RocksDB,并将其向下游发送到to()运算符中,并将其也写入结果主题。

也请阅读文档以获取更多详细信息:https://kafka.apache.org/21/documentation/streams/关于Kafka Streams及其在互联网上的工作方式,还有很多其他材料(博客文章,谈话记录,幻灯片...)

  

有趣的是,联接后的结果(在一个紧凑的主题中称为user_addresses)具有比用户表项更多的表项。我更深入地看,发现具有相同键的用户多次出现(多个偏移量)。在最小偏移量处,该用户没有地址,然后在较高偏移量处,该用户列表中有一个地址,而最大偏移量时,该用户列表中有两个地址。我再次问自己,当我使用压缩主题时,为什么旧​​的偏移量不会自动删除。 Kafka的压缩是否像垃圾收集器那样工作,之后将数据删除?如果我正在寻找钥匙,那我会得到偏移量最大的钥匙吗?

压缩在后台异步完成,但不是立即完成。还要注意,主题(或更准确地说是)分区被划分为“段”,并且活动段从未压缩(默认段大小为1GB)。您可以配置段大小以及如何触发压缩(有关更多详细信息,请阅读文档:https://kafka.apache.org/documentation/#compaction)。

  

如果我正在寻找钥匙,那我会得到偏移量最大的钥匙吗?

不确定您的意思。 Kafka仅允许顺序读取,但不允许键查找。因此,您需要从头到尾阅读该主题以找到密钥的最新版本。如果您引用Kafka Streams的“交互式查询”功能,它将查询本地RocksDB,从而包含每个密钥的最新条目。

  

我的问题是我的方法是否是实现这一目标的好方法。

是的,其中一个重要细节与

有关
  

KGroupedStream和KGroupedTable在内部有什么区别?

由于您输入的主题是使用键(userId,addressId)的紧凑主题,因此应将其读为table()(而不是stream()):

KTable<GenericRecord, ArrayList<GenericRecord>> aggregatedAddresses =
    builder.table("address-topic")
      .selectKey(...) //Selecting USERID as key - this generates KStream
      .groupBy(...) //Select USERID as and group by USERID
      .aggregate(...) //Aggregating by USERID as key - this generates KTable
      .to("aggregated_addresses"); //KTable with USERID as key 

区别在于,如果您阅读主题KStreams,则会被解释为“事实”,因此没有删除语义。但是,您输入的主题包含“更新”记录,因此,它应该是消费者。 KGroupedStreamKGroupedTable只是API中的中间对象,还暗示着“事实”与“更新”的语义。再次,在Internet上查看文档和更多材料以获取更多详细信息。