使用实时窗口聚合更新数据库

时间:2019-05-30 02:34:19

标签: google-cloud-platform google-cloud-dataflow apache-beam

我有一个流管道,该流管道消耗了流源(Kafka),并将写入CloudSQL数据库。目标是使用过去一小时内收到的记录的键/值总和来实时更新CloudSQL数据库。

例如在最近一小时内,收到3个记录为KV <001,3><001,4><001,2>的记录,数据库应包含记录001, 9。超过一个小时的记录不包括在内。

我当前的解决方法是在KafkaIO.read之后将SlidingWindow转换为GroupByKey:

                    .apply(Window.into(SlidingWindows
                                .of(Duration.standardSeconds(3600))
                                  .every(Duration.standardSeconds(20)))
                    ).apply(GroupByKey.create())

后跟一个对每个键求和的ParDo,然后更新SQL数据库。

结果是我的CloudSQL数据库每20秒更新一次最新一小时的每个键的汇总,从而满足功能要求。问题在于这会导致CloudSQL大量更新:大多数KV输出与先前的窗口相同,因此每20s的每个窗口都会触发一个小时的交易(约500k)。

仅当消耗具有该键的记录时才触发每个KV输出,或者避免输出自上一个窗口以来未更改的KV,才有意义。或者,在CloudSQL插入之前进行某种过滤,以吸收所有内容,并且仅输出已更改的KV。这可能还是有其他解决方案?

1 个答案:

答案 0 :(得分:0)

一种可能的探索方法是在滑动窗口聚合的下游使用State API。

然而,流入此元素的元素是无序的,因此您不能仅存储元素并将其与传入值进行比较。

  • 您需要将DoFn中的每个元素添加到BagState(带时间戳的值)。
  • 设置一个计时器,然后在OnTimer()函数期间读取bagstate中的所有元素,并对它们排序并输出所需的值。您还需要将max(timestamp)值存储在ValueState对象中,以便下次调用OnTimer时可以使用它。

用于State API DoFn的窗口的大小将是任意的,它越大,不需要的upsert越多。缺点是,窗口越大,您将在ValueState中保留的键越多,可能不再需要这些键。避免使用全局窗口,因为这将需要您构建GC函数,因为该窗口永不过期,并且密钥空间将永远增长。