【问题标题】:Avoid recomputing size of all Cloud Storage files in Beam Python SDK避免在 Beam Python SDK 中重新计算所有 Cloud Storage 文件的大小
【发布时间】:2020-03-26 19:40:23
【问题描述】:

我正在开发一个从 Google Cloud Storage (GCS) 目录中读取约 500 万个文件的管道。我已将其配置为在 Google Cloud Dataflow 上运行。

问题是当我启动管道时,“计算”所有文件的大小需要几个小时:

INFO:apache_beam.io.gcp.gcsio:Starting the size estimation of the input
INFO:apache_beam.io.gcp.gcsio:Finished computing size of: 10000 files
[...]
INFO:apache_beam.io.gcp.gcsio:Finished computing size of: 5480000 files
INFO:apache_beam.io.gcp.gcsio:Finished listing 5483720 files in 5549.38778591156 seconds.
INFO:apache_beam.io.gcp.gcsio:Starting the size estimation of the input
INFO:apache_beam.io.gcp.gcsio:Finished computing size of: 10000 files
[...]
INFO:apache_beam.io.gcp.gcsio:Finished computing size of: 5480000 files
INFO:apache_beam.io.gcp.gcsio:Finished listing 5483720 files in 7563.196493148804 seconds.
INFO:apache_beam.io.gcp.gcsio:Starting the size estimation of the input
INFO:apache_beam.io.gcp.gcsio:Finished computing size of: 10000 files
[...]

如您所见,计算大约 550 万个文件的大小需要一个半小时(5549 秒),然后又从头开始!第二遍又跑了2个小时,然后又开始了第三遍!截至撰写本文时,该作业在 Dataflow 控制台中仍然不可用,这让我相信这一切都发生在我的本地机器上,并且没有利用任何分布式计算。

当我使用较小的输入数据集(2 个文件)测试管道时,它会重复大小估计 4 次:

INFO:apache_beam.io.gcp.gcsio:Starting the size estimation of the input
INFO:apache_beam.io.gcp.gcsio:Finished listing 2 files in 0.33771586418151855 seconds.
INFO:apache_beam.io.gcp.gcsio:Starting the size estimation of the input
INFO:apache_beam.io.gcp.gcsio:Finished listing 2 files in 0.1244659423828125 seconds.
INFO:apache_beam.io.gcp.gcsio:Starting the size estimation of the input
INFO:apache_beam.io.gcp.gcsio:Finished listing 2 files in 0.13422417640686035 seconds.
INFO:apache_beam.io.gcp.gcsio:Starting the size estimation of the input
INFO:apache_beam.io.gcp.gcsio:Finished listing 2 files in 0.14139890670776367 seconds.

按照这个速度,在 Dataflow 作业开始之前,仅对所有 5.5M 文件执行 4 次 GCS 大小估计就需要大约 8 小时。

我的管道配置了 --runner=DataflowRunner 选项,因此它应该在 Dataflow 中运行:

python bigquery_import.py --runner=DataflowRunner #other options...

管道从 GCS 读取如下:

parser = argparse.ArgumentParser()
parser.add_argument(
    '--input',
    required=True,
    help='Input Cloud Storage directory to process.')
known_args, pipeline_args = parser.parse_known_args(argv)
pipeline_options = PipelineOptions(pipeline_args)
pipeline_options.view_as(SetupOptions).save_main_session = True

with beam.Pipeline(options=pipeline_options) as p:
    files = p | beam.io.ReadFromText('gs://project/dir/*.har.gz')

完整代码请参考 GitHub 上的bigquery_import.py

我很困惑为什么这个繁琐的过程会发生在 Dataflow 环境之外,以及为什么需要多次执行。我是从 GCS 正确读取文件还是有更有效的方法?

【问题讨论】:

标签: python google-cloud-dataflow apache-beam


【解决方案1】:

感谢您报告此事。 Beam 有两个用于阅读文本的转换。 ReadFromTextReadAllFromTextReadFromText 会遇到这个问题,但ReadAllFromText 不会。

https://github.com/apache/beam/blob/master/sdks/python/apache_beam/io/textio.py#L438

ReadAllFromText 的缺点是它不会执行动态工作再平衡,但在读取大量文件时这应该不是问题。

创建 https://issues.apache.org/jira/browse/BEAM-9620 用于跟踪 ReadFromText(以及一般基于文件的源)的问题。

【讨论】:

  • 听起来很有希望!更改为 ReadAllFromText 会导致管道现在失败,并在 JSON 解析文件的后续转换步骤中出现 'PBegin' object has no attribute 'windowing' 属性错误。感谢您的帮助。
  • 通过将 p | beam.io.ReadFromText(gcs_path) 更改为 p | beam.Create([gcs_path]) | beam.io.ReadAllFromText() 使其工作。两个值得注意的变化是:将包含 glob 字符串的列表传递给 ReadAllFromText 方法。非常感谢您的帮助!
  • 我正在尝试处理 15M 文件。我使用了推荐的管道p | beam.Create([gcs_path]) | beam.io.ReadAllFromText()。结果是 Dataflow 确实立即生成,但 ReadAllFromText 需要永远计算。我可以在日志中看到它在几个小时内尝试计算文件的大小。它已经花费了大约 8 小时以上的时间,它刚刚完成了 15M 文件中约 2M 的计算。我怎样才能避免计算这些尺寸?这样做的理由是什么?我可以完美地编写自己的转换,立即从 GCS 中列出所有 15M 链接并在下一步中读取它。
猜你喜欢
  • 2018-02-26
  • 1970-01-01
  • 2016-02-10
  • 2023-01-30
  • 1970-01-01
  • 2019-05-01
  • 2017-05-25
  • 2016-11-12
  • 1970-01-01
相关资源
最近更新 更多