Flink 使用一次性加入密钥加入流

Flink join streams using a disposable one-time join key

我对在 Flink 上加入两个流有疑问。我使用了两个不同的数据流,在某些时候我需要 加入他们。每个数据流都标有一个唯一的 id,作为这些流之间的连接点。 没有 window 的概念所以为了连接这两个数据流我做了 first.connect(second).keyBy(0,0).

这似乎有效,因为我得到了正确的结果,但我的担忧是长期的。我没有明确保留任何 在执行连接的运算符(coFlatMap)上声明但是如果假设一个流(例如第一个)提供唯一的会发生什么 id 而第二个未能提供加入 id(我想对于那些已经加入的人,操作员会丢弃任何类型的内部状态)? memory/state 足迹是不断增长还是存在某种过期机制?

如果是这种情况,我该如何解决这个问题?或者你能建议我另一种方法吗?

有几种方法可以实现此连接。

  1. 使用一个CoProcessFunction。当键的第一条记录到达时,您将其存储在状态中并注册一个计时器,该计时器稍后触发 x minutes/hours/days。当第二条记录到达时,您执行连接并清除状态。如果第二条记录没有到达,定时器触发时将调用 onTimer() 方法。那时,您可以只清除状态和 return(INNER JOIN 语义)或转发第一个填充有 null 值的记录(OUTER JOIN 语义),清除状态,然后 return.计时器充当安全网,能够在某个时候删除状态。等待第二条记录到达的时间取决于您的要求。

  2. Table API 或 SQL 提供了一个时间 windowed 连接(Table API, SQL),其工作方式类似于我在 1 中描述过。不同之处在于 windowed 连接实现将尝试连接在连接间隔期间到达的所有记录(即,来自每个输入流的多个记录),因此会使状态保持更长的时间。但是,一旦时间超过加入间隔,它就会清除状态。

  3. Flink 1.6.0(将于 2018 年 8 月上旬发布)将为 DataStream API 包含一个 interval join,其工作方式类似于 window 连接Table API (逻辑相似,名称不同)。它还将使状态保持比自定义实现更长的时间,自定义实现基于每个键在每一侧只出现一次的假设。

我会选择方法 1。因为它的内存效率更高,而且仍然相当容易实现。