简单的Apache Beam操作非常慢

时间:2017-06-24 12:33:22

标签: java maven apache-beam apache-beam-io

我是Apache Beam的新手,我的Java技能很低,但我想了解为什么我的简单条目操作在Apache Beam中工作得太慢。

我正在尝试执行的操作如下:我有一个包含以下方案的100万条记录(Alexa前100万个网站)的CSV文件:NUMBER,DOMAIN(例如1,google.com),我想“剥离”第一个(数字)字段并仅获取域部分。我对此管道的代码如下:

package misc.examples;

import org.apache.beam.sdk.Pipeline;
import org.apache.beam.sdk.io.TextIO;
import org.apache.beam.sdk.metrics.Counter;
import org.apache.beam.sdk.metrics.Metrics;
import org.apache.beam.sdk.transforms.DoFn;
import org.apache.beam.sdk.transforms.ParDo;

public class Example {

  static class ExtractDomainsFn extends DoFn<String, String> {
    private final Counter domains = Metrics.counter(ExtractDomainsFn.class, "domains");

    @ProcessElement
    public void processElement(ProcessContext c) {
      if (c.element().contains(",")) {
        domains.inc();

        String domain = c.element().split(",")[1];
        c.output(domain);
      }
    }
  }

  public static void main(String[] args) {
    Pipeline p = Pipeline.create();

    p.apply("ReadLines", TextIO.read().from("./top-1m.csv"))
     .apply("ExtractDomains", ParDo.of(new ExtractDomainsFn()))
     .apply("WriteDomains", TextIO.write().to("domains"));

    p.run().waitUntilFinish();
  }
}

当我使用Maven执行此代码时,我的笔记本电脑上的成功时间超过四分钟:

$ mvn compile exec:java -Dexec.mainClass=misc.examples.Example
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building my-example 1.0.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ my-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /…/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.5.1:compile (default-compile) @ my-example ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- exec-maven-plugin:1.4.0:java (default-cli) @ my-example ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 04:36 min
[INFO] Finished at: 2017-06-24T15:20:33+03:00
[INFO] Final Memory: 31M/1685M
[INFO] ------------------------------------------------------------------------

虽然简单的cut(1)在你甚至可以眨眼之前有效:

$time cut -d, -f2 top-1m.csv > domains

real    0m0.171s
user    0m0.140s
sys     0m0.028s

那么,这种Apache Beam行为是否被认为是可以接受的(可能它在大量数据上的效果相当好)或者我的代码是否效率低下?

01-07-2014更新:

正如Kenn Knowles suggested,我试图在DirectRunner上的DataflowRunner以外的其他跑步者上运行管道。因此更新后的代码如下所示:

package misc.examples;

import org.apache.beam.runners.dataflow.DataflowRunner;
import org.apache.beam.runners.dataflow.options.DataflowPipelineOptions;
import org.apache.beam.sdk.Pipeline;
import org.apache.beam.sdk.io.TextIO;
import org.apache.beam.sdk.options.PipelineOptions;
import org.apache.beam.sdk.options.PipelineOptionsFactory;
import org.apache.beam.sdk.transforms.DoFn;
import org.apache.beam.sdk.transforms.ParDo;

public class Example {

  static class ExtractDomainsFn extends DoFn<String, String> {
    @ProcessElement
    public void processElement(ProcessContext c) {
      if (c.element().contains(",")) {
        String domain = c.element().split(",")[1];
        c.output(domain);
      }
    }
  }

  public static void main(String[] args) {
    PipelineOptions options = PipelineOptionsFactory.create();
    DataflowPipelineOptions dataflowOptions = options.as(DataflowPipelineOptions.class);
    dataflowOptions.setRunner(DataflowRunner.class);
    dataflowOptions.setProject("my-gcp-project-id");
    Pipeline p = Pipeline.create(options);
    p.apply("ReadLines", TextIO.read().from("gs://my-gcs-bucket/top-1m.csv"))
     .apply("ExtractDomains", ParDo.of(new ExtractDomainsFn()))
     .apply("WriteDomains", TextIO.write().to("gs://my-gcs-bucket/output/"));

    p.run().waitUntilFinish();
  }
}

与直接跑步者相比,在Google数据流上运行的时间较短但仍然足够慢 - 稍微多于 3分钟

Google Dataflow Job

Google Dataflow Job Logs

1 个答案:

答案 0 :(得分:3)

Apache Beam在大规模数据处理引擎(如Apache Flink,Apache Spark,Apache Apex和Google Cloud Dataflow)上提供正确的事件时间处理和可移植性。

在这里,您似乎在默认的DirectRunner中运行管道,这是一种在小规模上测试管道正确性的方法(其中“小”表示不使用多台机器的任何东西)。为了测试正确性,运行器还执行额外的任务以帮助确保正确性,例如检查序列化(Coder)并按随机顺序放置元素以确保管道不依赖于顺序。

DirectRunner必须立即将所有值都带入内存,但是有一个流式执行模型,因此它也适用于无界数据集和触发。与简单的循环相比,这也增加了开销。

那就是说,四分钟很慢,我提交了BEAM-2516来跟进。

您也可以尝试在其他后端运行它,特别是SparkRunnerFlinkRunnerApexRunner支持在您的笔记本电脑上执行嵌入式执行。

对2017-07-01更新的回复:

虽然您在Cloud Dataflow上遇到的总运行时间约为3分钟,但处理数据所需的实际时间约为1分钟。您可以在日志中看到这一点。剩下的就是旋转并关闭工作虚拟机。我们一直在努力减少这种开销。为什么需要约1分钟?你需要剖析才能找到答案(我很想听听结果!)但是Dataflow确实比cut做了很多:从GCS读取和写入,提供耐久性和容错性,以及TextIO写入步骤,它正在执行网络数据混乱,以便并行写入分片文件。如果Dataflow注意到你的计算没有并行性并且足够小而不需要它,那么显然有些事情可以被优化掉。

但请记住,Beam和Cloud Dataflow可以帮助您对无法在一台计算机上及时处理的数据量使用并行处理。因此,处理没有并行性的微小示例不是目标。

较小的顺序计算通常确实作为大型管道的一小部分发生,但在实际物理计划的上下文中,小的辅助计算通常不会影响端到端时间。 VM管理的开销也是一次性成本,因此在几十到几百台计算机上进行数分钟到几小时的计算就更有可能进行测量。