通过Dataflow将大型gzip JSON文件从Google Cloud Storage读入BigQuery

时间:2017-02-15 10:14:03

标签: google-cloud-dataflow

我正在尝试从Google云端存储(GCS)中读取大约90个gzip压缩文件,每个大约2GB大(未压缩10 GB),解析它们,并通过Google将它们写入到BigQuery(BQ)的日期分区表中云数据流(GCDF)。

每个文件包含7天的数据,整个日期范围约为2年(730天和计数)。我目前的管道如下:

p.apply("Read logfile", TextIO.Read.from(bucket))
 .apply("Repartition", Repartition.of())
 .apply("Parse JSON", ParDo.of(new JacksonDeserializer()))
 .apply("Extract and attach timestamp", ParDo.of(new ExtractTimestamps()))
 .apply("Format output to TableRow", ParDo.of(new TableRowConverter()))
 .apply("Window into partitions", Window.into(new TablePartWindowFun()))
 .apply("Write to BigQuery", BigQueryIO.Write
         .to(new DayPartitionFunc("someproject:somedataset", tableName))
         .withSchema(TableRowConverter.getSchema())
         .withCreateDisposition(BigQueryIO.Write.CreateDisposition.CREATE_IF_NEEDED)
         .withWriteDisposition(BigQueryIO.Write.WriteDisposition.WRITE_APPEND));

重新分区是我在尝试创建管道reshuffle after decompressing时内置的内容,我尝试使用和不使用它来运行管道。解析JSON通过Jackon ObjectMapper和建议的here对应的类工作。 TablePartWindowFun取自here,用于为PCollection中的每个条目分配一个分区。

管道适用于较小的文件而不是太多,但是对于我的实际数据集来说是中断。我选择了足够大的机器类型并尝试设置最大数量的工作人员,以及使用自动调节最多100台n1-highmem-16机器。我已经尝试了流媒体和批处理模式以及每个工作250到1200 GB的disSizeGb值。

目前我能想到的可能解决方案是:

  1. 解压缩GCS上的所有文件,因此无法利用GCS' gzip transcoding
  2. 建设"很多"循环中的并行管道,每个管道只处理90个文件的子集。

    选项2在我看来就像编程"周围"一个框架,还有另一个解决方案吗?

    附录:

    在批处理模式下读取 gzip JSON文件后,最多100个工人(类型为n1-highmem-4),管道运行大约一个小时,有12名工人,并完成阅读以及重新分配的第一阶段。然后它可以扩展到100个工作人员并处理重新分区的PCollection。完成后,图形如下所示:

    Write to BQ Service Graph

    有趣的是,当达到这个阶段时,首先它处理高达150万个元素/秒,然后进度下降到0.图片中GroupByKey步骤的OutputCollection的大小首先上升然后下降从大约3亿到0(总共约有18亿个元素)。就像它丢弃了一些东西。此外,最后ExpandIterableParDo(Streaming Write)运行时间为0.图片显示在运行之前稍微显示#34;向后"。 在工作人员的日志中,我看到来自exception thrown while executing request记录器的一些com.google.api.client.http.HttpTransport消息,但我无法在Stackdriver中找到更多信息。

    读取后没有重新分区管道在完全相同的步骤(n1-highmem-2之后的所有内容)使用内存错误的GroupByKey实例失败 - 使用更大的实例类型导致像

    这样的例外
    java.util.concurrent.ExecutionException: java.io.IOException: 
    CANCELLED: Received RST_STREAM with error code 8 dataflow-...-harness-5l3s 
    talking to frontendpipeline-..-harness-pc98:12346
    

2 个答案:

答案 0 :(得分:1)

感谢Google云数据流团队的Dan和他提供的示例here,我能够解决这个问题。我做的唯一改变是:

  • 在175 =(25周)大块的日子里循环,一个接一个地运行一个管道,以免压倒系统。在循环中,确保重新处理上一次迭代的最后一个文件,并以与基础数据相同的速度向前移动startDate(175天)。使用WriteDisposition.WRITE_TRUNCATE时,以这种方式用正确的完整数据覆盖块末尾的不完整日期。

  • 使用上面提到的重新分区/重新洗牌转换,在阅读gzip压缩文件后,加快进程并允许更顺畅的自动缩放

  • 使用DateTime而不是Instant类型,因为我的数据不是UTC

更新(Apache Beam 2.0):

随着Apache Beam 2.0的发布,解决方案变得更加容易。现在支持Sharding BigQuery输出表out of the box

答案 1 :(得分:0)

通过在运行管道时设置具有更高值的--numWorkers,尝试为管道分配更多资源可能是值得的。这是“在线故障排除管道”document中讨论的“常见错误和行动课程”子章节中讨论的可能解决方案之一。