GCP数据流 - 处理JSON需要太长时间

时间:2016-05-23 11:40:02

标签: json google-cloud-platform google-cloud-dataflow

我正在尝试处理存储桶中的json文件并将结果写入存储桶:

    DataflowPipelineOptions options = PipelineOptionsFactory.create()
            .as(DataflowPipelineOptions.class);
    options.setRunner(BlockingDataflowPipelineRunner.class);
    options.setProject("the-project");
    options.setStagingLocation("gs://some-bucket/temp/");

    Pipeline p = Pipeline.create(options);

    p.apply(TextIO.Read.from("gs://some-bucket/2016/04/28/*/*.json"))
    .apply(ParDo.named("SanitizeJson").of(new DoFn<String, String>() {
        @Override
        public void processElement(ProcessContext c) {
            try {
                JsonFactory factory = JacksonFactory.getDefaultInstance();
                String json = c.element();
                SomeClass e = factory.fromString(json, SomeClass.class);
                // manipulate the object a bit...
                c.output(factory.toString(e));
            } catch (Exception err) {
                LOG.error("Failed to process element: " + c.element(), err);
            }
        }
    }))
    .apply(TextIO.Write.to("gs://some-bucket/output/"));
    p.run();

我在路径gs:// some-bucket / 2016/04/28 /(在子目录中)下有大约50,000个文件。 我的问题是:这需要一个多小时才能完成吗?在亚马逊的Spark群集上做类似的事情需要大约15-20分钟。我怀疑我可能效率低下。

编辑:

在我的Spark作业中,我将所有结果聚合在一个DataFrame中,然后一次性写入输出。我注意到我的管道在这里分别写了每个文件,我想这就是为什么它需要更长的时间。有没有办法改变这种行为?

1 个答案:

答案 0 :(得分:0)

您的作业在Dataflow中遇到了几个性能问题,这是因为它更适合以更大的增量执行工作,而您的工作是处理大量非常小的文件。结果,作业执行的某些方面最终由每个文件开销占主导地位。这是一些细节和建议。

  • 通过写入输出而不是通过读取输入来限制作业(尽管读取输入也是一个重要部分)。您可以通过在withNumShards上指定TextIO.Write来显着降低开销,具体取决于您在输出中需要多少文件。例如。 100可能是合理的价值。默认情况下,你得到一个未指定数量的文件,在这种情况下,给定Dataflow优化器的当前行为,匹配输入文件的数量:通常这是一个好主意,因为它允许我们不实现中间数据,但在此这不是一个好主意,因为输入文件太小,每个文件的开销更重要。
  • 我建议将maxNumWorkers设置为例如maxNumWorkers之类的值12 - 目前第二项工作是自动扩展到过多的工人。这是由于Dataflow的自动调节当前面向以更大增量处理数据的作业 - 它目前没有考虑到每个文件的开销,并且在您的情况下表现不佳。
  • 第二个工作也遇到了一个错误,因为它无法最终确定书面输出。我们正在调查,但设置maxNumWorkers=12也应该使其成功完成。

不久之后:

  • 设置TextIO.Write.to("...").withNumShards(100)
  • 设置bin

它应该运行得更好。