防止在Apache Beam / Dataflow流(python)管道中融合以消除管道瓶颈

时间:2019-02-20 10:30:56

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

我们目前正在使用DataflowRunner在Apache Beam上开发流传输管道。我们正在从Pub / Sub中读取消息并对其进行一些处理,然后在滑动窗口中对其进行窗口化(当前窗口大小为3秒,间隔也为3秒)。触发窗口后,我们会对窗口内的元素进行一些后处理。此后处理步骤明显大于窗口大小,大约需要15秒。

管道的Apache梁代码:

input = ( pipeline | beam.io.ReadFromPubSub(subscription=<subscription_path>)
                   | beam.Map(process_fn))
windows = input | beam.WindowInto(beam.window.SlidingWindows(3, 3),
                                  trigger=AfterCount(30), 
                                  accumulation_mode = AccumulationModel.DISCARDING)
group = windows | beam.GroupByKey()
group | beam.Map(post_processing_fn)

您知道,Dataflow会尝试对管道步骤进行一些优化。在我们的案例中,它从窗口开始将所有内容融合在一起(集群操作:1 /处理2 /窗口+后处理),这导致仅1个工作人员对所有窗口进行缓慢的顺序后处理。我们每15秒就会看到日志记录管道正在处理下一个窗口。但是,我们希望有多个工作人员选择单独的窗口,而不是将工作负载转移给单个工作人员。

因此,我们正在寻找防止这种融合发生的方法,因此Dataflow会将窗口与窗口的后处理分开。这样,我们希望Dataflow能够再次将多个工作程序分配给激发窗口的后处理。

到目前为止我们已经尝试过:

  • 将工人人数增加到20、30甚至40,但没有效果。仅将窗口化之前的步骤分配给多个工作人员
  • 将管道运行5或10分钟,但我们注意到没有窗口重新分配工作人员来帮助进行此较大的后处理步骤
  • 窗口化之后,将它们放回全局窗口中
  • 使用伪密钥(如https://cloud.google.com/dataflow/docs/guides/deploying-a-pipeline#preventing-fusion中所述)模拟另一个GroupByKey,但没有成功。

最后两个动作确实创建了第三个集群操作(1 /处理2 /窗口3 / 后处理),但是我们注意到,在窗口操作之后,仍然是同一工作人员执行所有操作。

>

有没有可以解决此问题的解决方案?

我们现在正在考虑的当前解决方法是建立另一个接收窗口的流传输管道,以便这些工作人员可以并行处理窗口,但是很麻烦。

1 个答案:

答案 0 :(得分:2)

您做对了,打破了元素之间的融合。我怀疑这可能会给您带来麻烦。

对于流式传输,单个键总是在同一工作线程中处理。您是否将所有或大部分记录分配给一个键?如果是这样,您的处理将由单个工作人员完成。

您可以采取的措施是使窗口成为键的一部分,以便即使具有相同的键,也可以在不同的工作程序中处理多个窗口的元素:

class KeyIntoKeyPlusWindow(core.DoFn):
  def process(self, element, window=core.DoFn.WindowParam):
    key, values = element
    yield ((key, window), element)

group = windows | beam.ParDo(KeyIntoKeyPlusWindow() | beam.GroupByKey()

完成此操作后,即可进行后期处理:

group | beam.Map(post_processing_fn)