Google cloud dataflow 侧输入会破坏数据流性能

Google cloud dataflow 侧输入会破坏数据流性能,google-cloud-dataflow,Google Cloud Dataflow,我使用数据流生成大量数据 我已经测试了我的管道的两个版本:一个带有侧面输入(大小不同),另一个没有 当我运行管道而不使用侧输入时,我的工作将在大约7分钟内完成。当我使用侧面输入运行我的作业时,我的作业永远不会完成 下面是我的DoFn的样子: 公共类MyDoFn扩展了DoFn{ 最终PCollectionView PCollectionView; 最终清单材料; 专用聚合器dofnCounter= createAggregator(“DoFn计数器”,new Sum.SumIntegerFn())

我使用数据流生成大量数据

我已经测试了我的管道的两个版本:一个带有侧面输入(大小不同),另一个没有

当我运行管道而不使用侧输入时,我的工作将在大约7分钟内完成。当我使用侧面输入运行我的作业时,我的作业永远不会完成

下面是我的DoFn的样子:

公共类MyDoFn扩展了DoFn{
最终PCollectionView PCollectionView;
最终清单材料;
专用聚合器dofnCounter=
createAggregator(“DoFn计数器”,new Sum.SumIntegerFn());
公共MyDoFn(PCCollectionView pcv,列表m){
this.pCollectionView=pcv;
this.stuff=m;
}
@凌驾
public void processElement(ProcessContext ProcessContext)引发异常{
Map pdata=processContext.sideInput(pCollectionView);
output(另一个类.generateData(stuff,pdata));
dofnCounter.addValue(1);
}
}
我的管道是这样的:

final Pipeline p=Pipeline.create(PipelineOptionsFactory.fromArgs(args).withValidation().create());
p收集数据;
data=p.apply(TextIO.Read.from(“gs://where\u the\u files\u are/*”)。命名为(“读取数据”))
.apply(ParDo.named(“解析数据”)。of(new DoFn(){
@凌驾
public void processElement(ProcessContext ProcessContext)引发异常{
//解析一些数据
processContext.output(键、值的千伏);
}
}));
最终PCollection视图pcv=
data.apply(GroupByKey.create())
.apply(View.asMap());
DoFn DoFn=新的MyDoFn(pcv,localList);
p、 应用(TextIO.Read.from(“gs://some_text.txt”)。命名为(“大小”)
.apply(ParDo.named(“生成数据”).with sideinputs(pvc).of(dofn))
.apply(TextIO.Write.named(“Write_out”).to(outputFile));
p、 run();
我们已经花了大约两天的时间尝试各种方法来实现这一点。我们将其缩小到包含侧输入。如果processContext被修改为不使用side输入,那么只要包含它,它仍然会非常慢。如果我们不调用.withSideInput()它又会非常快

为了澄清这一点,我们已经在20mb-1.5gb的sideinput大小上进行了测试

非常感谢您的洞察力

编辑 包括一些工作ID:


2016-01-20_14_31_12-1354600113427960103

2016-01-21_08_04_33-1642110636871153093(最新版本)

如果不小心使用,数据流SDK中的速度确实会变慢。最常见的情况是,当每个工作者必须重新读取每个主输入元素的整个侧输入时,就会发生这种情况

您似乎正在使用通过
asMap
创建的
PCollectionView
。在这种情况下,整个侧面输入
PCollection
必须放入每个辅助进程的内存中。当需要时,Dataflow SDK将在每个worker上复制此数据以创建这样的映射

也就是说,每个工人的地图可能只创建一次或多次,这取决于几个因素。如果映射的大小足够小(通常小于100MB),则很可能每个工作者只读取一次映射,并跨元素和包重用。但是,如果它的大小不能放入我们的缓存中(或者其他东西将它从缓存中逐出),则可能会在每个工作进程上一次又一次地重新读取整个映射。这通常是缓慢的根本原因

缓存大小可以通过
PipelineOptions
进行控制,如下所示,但由于几个重要的错误修复,应该仅在1.3.0版和更高版本中使用

DataflowWorkerHarnessOptions opts = PipelineOptionsFactory.fromArgs(args).withValidation().create().cloneAs(DataflowWorkerHarnessOptions.class);
opts.setWorkerCacheMb(500);
Pipeline p = Pipeline.create(opts);
目前,解决办法是改变管道结构,以避免过度重读。我不能给你一个具体的建议,因为你没有分享足够的关于你的用例的信息。(如有需要,请单独提问。)


我们正在积极开发一个相关的功能,我们称之为分布式端输入。这将允许查找侧面输入
PCollection
,而无需在worker上构建整个映射。这将大大有助于在这种情况下以及相关情况下的绩效。我们预计很快就会发布这个



我看不出你提到的两份工作有什么特别可疑的地方。它们已被相对快速地取消。

我正在以以下方式创建管道时手动设置缓存大小:

DataflowWorkerHarnessOptions opts = PipelineOptionsFactory.fromArgs(args).withValidation().create().cloneAs(DataflowWorkerHarnessOptions.class);
opts.setWorkerCacheMb(500);
Pipeline p = Pipeline.create(opts);
对于~25mb的侧输入,这大大加快了执行时间(作业id 2016-01-25_08_42_52-657610385797048159),而不是以以下方式创建管道(作业id 2016-01-25_07_56_35-14864561652521586982)


但是,当侧面输入增加到~400mb时,缓存大小的增加不会提高性能。理论上,GCE机器类型指示的所有内存是否可供工人使用?什么会使工作缓存中的某些内容无效或被逐出,从而强制重新读取?

请试用Dataflow SDK 1.5.0+,它们应该已经解决了您的问题中的已知性能问题

在Dataflow SDK 1.5.0+中,在运行批处理管道时使用新的分布式格式。请注意,如果视图不能完全缓存在内存中,则流式管道和使用旧版本Dataflow SDK的管道仍然需要重新读取侧输入


对于新格式,我们使用索引来提供基于块的查找和缓存策略。因此,当按索引查看列表或按键查看映射时,仅加载包含所述索引或键的块。缓存大小大于工作集大小将有助于提高性能,因为频繁访问的索引/键不需要重新读取它们所包含的块。

您能否给出一个作业ID示例,以便我们可以调试出错的地方?2016-01-20_14_31_12-1354600113427960103感谢这一建议。我成立了公司
  PipelineOptions options = PipelineOptionsFactory.fromArgs(args).withValidation().create();