窗口化之后,Google数据流流传输管道不会将工作负载分配给多个工作人员

时间:2019-02-19 10:31:26

标签: google-cloud-dataflow apache-beam

我正在尝试在python中建立数据流流传输管道。我对批处理管道有相当的经验。我们的基本架构如下所示: enter image description here

第一步是进行一些基本处理,每条消息大约需要2秒钟才能到达窗口。我们正在使用3秒和3秒间隔的滑动窗口(稍后可能会更改,因此我们有重叠的窗口)。作为最后一步,我们需要进行大约15秒钟的SOG预测处理,这显然是我们的瓶颈转换。

因此,我们似乎面临的问题是,在开窗之前,工作负载已完美地分布在我们的工作人员上,但是最重要的转换根本没有分布。所有窗口一次只能处理一个工人,而我们只有50个。

日志显示,sog预测步骤每15秒钟会输出一次,如果要在更多工作人员上处理窗口,则情况并非如此,因此随着时间的推移,这会增加我们不希望的巨大延迟。收到1分钟的消息后,最后一个窗口的等待时间为5分钟。当分发有效时,这应该仅在15秒左右(SOG预测时间)。因此,我们在这一点上一无所知。

enter image description here

有人看到我们的代码是否有问题,或者如何防止/规避此问题? 看来这是Google Cloud Dataflow内部发生的事情。 Java流管道中也会发生这种情况吗?

在批处理模式下,一切正常。在那里,可以尝试进行改组以确保不发生融合等。但这在流式处理窗口化之后是不可能的。

args = parse_arguments(sys.argv if argv is None else argv)
pipeline_options = get_pipeline_options(project=args.project_id,
                                        job_name='XX',
                                        num_workers=args.workers,
                                        max_num_workers=MAX_NUM_WORKERS,
                                        disk_size_gb=DISK_SIZE_GB,
                                        local=args.local,
                                        streaming=args.streaming)

pipeline = beam.Pipeline(options=pipeline_options)

# Build pipeline
# pylint: disable=C0330
if args.streaming:
    frames = (pipeline | 'ReadFromPubsub' >> beam.io.ReadFromPubSub(
        subscription=SUBSCRIPTION_PATH,
        with_attributes=True,
        timestamp_attribute='timestamp'
    ))

    frame_tpl = frames | 'CreateFrameTuples' >> beam.Map(
        create_frame_tuples_fn)

crops = frame_tpl | 'MakeCrops' >> beam.Map(make_crops_fn, NR_CROPS)
bboxs = crops | 'bounding boxes tfserv' >> beam.Map(
    pred_bbox_tfserv_fn, SERVER_URL)

sliding_windows = bboxs | 'Window' >> beam.WindowInto(
                  beam.window.SlidingWindows(
                        FEATURE_WINDOWS['goal']['window_size'],
                        FEATURE_WINDOWS['goal']['window_interval']),
                  trigger=AfterCount(30),
                  accumulation_mode=AccumulationMode.DISCARDING)

# GROUPBYKEY (per match)
group_per_match = sliding_windows | 'Group' >> beam.GroupByKey()
_ = group_per_match | 'LogPerMatch' >> beam.Map(lambda x: logging.info(
    "window per match per timewindow: # %s, %s", str(len(x[1])), x[1][0][
        'timestamp']))

sog = sliding_windows | 'Predict SOG' >> beam.Map(predict_sog_fn,
                                                SERVER_URL_INCEPTION,
                                                SERVER_URL_SOG )

pipeline.run().wait_until_finish()

2 个答案:

答案 0 :(得分:6)

在光束中,并行度的单位是关键-给定密钥的所有窗口都将在同一台机器上生成。但是,如果您有50个以上的密钥,则应该在所有工作线程中分配它们。

您提到无法在流式传输中添加Reshuffle。这应该是可能的;如果您遇到错误,请通过https://issues.apache.org/jira/projects/BEAM/issues提交错误。重新进入GlobalWindows是否可以消除重新组合的问题?

答案 1 :(得分:2)

看起来您不一定需要GroupByKey,因为您总是在同一键上分组。相反,您可以使用CombineGlobally代替GroupByKey(始终使用相同的键)来将窗口内的所有元素附加到窗口中。

combined = values | beam.CombineGlobally(append_fn).without_defaults()
combined | beam.ParDo(PostProcessFn())

我不确定在使用CombineGlobally时负载分配的工作方式,但是由于它不处理键值对,我希望有另一种机制可以进行负载分配。