我正在尝试在python中建立数据流流传输管道。我对批处理管道有相当的经验。我们的基本架构如下所示:
第一步是进行一些基本处理,每条消息大约需要2秒钟才能到达窗口。我们正在使用3秒和3秒间隔的滑动窗口(稍后可能会更改,因此我们有重叠的窗口)。作为最后一步,我们需要进行大约15秒钟的SOG预测处理,这显然是我们的瓶颈转换。
因此,我们似乎面临的问题是,在开窗之前,工作负载已完美地分布在我们的工作人员上,但是最重要的转换根本没有分布。所有窗口一次只能处理一个工人,而我们只有50个。
日志显示,sog预测步骤每15秒钟会输出一次,如果要在更多工作人员上处理窗口,则情况并非如此,因此随着时间的推移,这会增加我们不希望的巨大延迟。收到1分钟的消息后,最后一个窗口的等待时间为5分钟。当分发有效时,这应该仅在15秒左右(SOG预测时间)。因此,我们在这一点上一无所知。
有人看到我们的代码是否有问题,或者如何防止/规避此问题? 看来这是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()
答案 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时负载分配的工作方式,但是由于它不处理键值对,我希望有另一种机制可以进行负载分配。