【问题标题】:GCP Python copy large files between bucketsGCP Python 在存储桶之间复制大文件
【发布时间】:2020-06-24 18:44:43
【问题描述】:

我有一堆存储桶,它们会在文件上传时向 Pub/Sub 主题发布通知。然后我有一个订阅 Pub/Sub 主题的云函数,它将这些文件复制到它们的最终目标存储桶中。这对大多数文件都适用,但是当我有大文件(> 1GB)时,它们无法复制。源桶是多区域的,目标桶是区域和近线的。

我的代码本质上是:

client = storage.Client()
src_bucket = client.get_bucket(src_bucket_name)
src_blob = src_bucket.get_blob(src_filename)
dst_bucket = client.get_bucket(dst_bucket_name)
dst_blob = dst_bucket.blob(dst_filename)

dst_blob.rewrite(src_blob)

最初,云函数在 60 秒时超时,所以我认为这是问题所在,但后来我将云函数超时时间增加到 540 秒,但该函数仍然超时。我的功能重试了 20 分钟,所以我可以看到问题是可重复的。 在将云函数超时设置失败后,我阅读了 blob 文档,发现 blob.rewrite 也有 60 秒的默认超时,因此我也将其设置为 540 秒,但这仍然超时。

在这一点上,我不确定我错过了什么。这是超时问题吗?或者这是否与 Pub/Sub 发布多条消息有关,所以我可以有多个云功能尝试同时制作同一个副本?或者有没有更好的方法在存储桶之间自动移动大文件?

【问题讨论】:

    标签: python google-cloud-platform google-cloud-functions google-cloud-storage


    【解决方案1】:

    首先,了解一下幕后发生的事情:

    GCS 的rewrite 操作是在线操作。当rewrite请求确认成功时,rewrite已经完成,新的操作准备好了。缺点是用户必须在复制完成时保持打开重写连接。但是,连接不会永远持续下去。如果操作将花费超过 30 秒左右的时间,则重写请求可能会不完整地结束。在这种情况下,它将返回一个重写令牌,客户端必须使用该令牌来恢复请求,否则将无法取得进一步的进展。

    Python 中,看起来像这样:

    rewrite_token = ''
    while rewrite_token is not None:
      rewrite_token, bytes_rewritten, bytes_to_rewrite = dst_blob.rewrite(
          src_blob, token=rewrite_token)
      print(f'Progress so far: {bytes_rewritten}/{bytes_to_rewrite} bytes.')
    

    这对于较小的对象或服务不需要做任何工作来移动数据的对象无关紧要。但是对于大型操作,您需要检查是否需要恢复。

    也就是说,我不希望从您的代码中看到超时。那是另一种失败。你确定你得到的错误是超时吗?

    【讨论】:

    • 我实际上是在循环blob.rewrite。只是在我总结我的代码时忘记包含它。关于重写令牌的要点。我没有使用它,并且一定完全错过了文档中的内容。
    • 啊,这就解释了!您一遍又一遍地进行重写的前 30 秒,直到您的函数超时。
    • 经典菜鸟错误!现在就像一个魅力!谢谢!
    【解决方案2】:

    我注意到你的代码的第 2 行和第 4 行,你有 client.get_bucket - 在 GCP 文档中,他们没有提到 get_bucket 方法: https://cloud.google.com/storage/docs/renaming-copying-moving-objects#storage-copy-object-python

    (您必须单击“代码示例”选项卡,然后选择“Python”才能看到我在说什么。)

    您的代码是否可以在您自己的 Python 环境中本地运行?愚蠢的问题,我知道,但有时人们会直接进入云端。 ¯\_(ツ)_/¯

    【讨论】:

    • 该代码适用于较小的文件。它只是文件 > ~1 GB。 get_bucket 记录在这里:googleapis.dev/python/storage/latest/…
    • client.bucket() 和client.get_bucket() 的区别在于前者是本地动作;它创建一个 Python 对象,表示要在某个存储桶上完成的操作。另一方面,client.get_bucket() 对 GCS 进行 GET 调用以获取有关存储桶的信息(确保它存在)。在这种情况下可能没有必要使用 get_bucket(),但它肯定是有效的。
    • 啊!感谢@BrandonYarbrough 的澄清!
    猜你喜欢
    • 2021-07-03
    • 1970-01-01
    • 2022-06-10
    • 1970-01-01
    • 1970-01-01
    • 2019-11-07
    • 2021-02-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多