可续传上传

设置

本页面讨论 Cloud Storage 中的可续传上传。建议您使用可续传上传来上传大型文件,因为在上传过程中网络出现故障时,您不必从头开始重新上传。

简介

借助可续传上传,您可以在数据流因通信故障而中断后,恢复数据传输到 Cloud Storage 的操作。可续传上传的工作原理是发送多个请求,每个请求包含您正在上传的对象的一部分。这与简单上传不同,后者在单个请求中包含对象的所有数据,一旦中途失败,则必须从头开始重新上传。

  • 如果您要上传大型文件或通过较慢的连接上传,请使用可续传上传。如需了解使用可续传上传时的示例文件大小临界值,请参阅上传大小注意事项

  • 可续传上传必须在启动后的一周内完成,但可以随时取消

  • 只有已完成的可续传上传会显示在您的存储桶中,并替换具有相同名称的现有对象(如适用)。

    • 对象的创建时间取决于上传完成时间。

    • 用户设置的对象元数据是在初始请求中指定的。此元数据在上传完成后会应用于对象。

    • 如果您在最终请求中包括前缀为 X-Goog-Meta- 的标头,则 JSON API 还支持在最终请求中设置自定义元数据

  • 一次完成的可续传上传视为一项 A 类操作

工具和 API 如何使用可续传上传

根据您与 Cloud Storage 的交互方式,系统可能会代表您自动管理可续传上传。本部分介绍不同工具的可续传上传行为,并说明如何为应用配置适当的缓冲区大小。

控制台

Google Cloud 控制台会代表您自动管理可续传上传。但是,如果您在上传过程中刷新或离开 Google Cloud 控制台,则系统会取消上传。

命令行

在将数据上传到 Cloud Storage 时,gcloud CLI 会通过 gcloud storage cpgcloud storage rsync 命令使用可续传上传。如果上传被中断,您可以通过运行用于启动上传的命令来恢复上传。在恢复这种包含多个文件的上传时,请使用 --no-clobber 标志以防止重新上传已成功完成的文件。

客户端库

C++

storage::Client 中的函数具有不同的行为:

默认情况下,当对象大于 20 MiB 时,UploadFile() 会执行可续传上传。否则,它会执行简单上传或分段上传。您可以在创建 storage::Client 时设置 MaximumSimpleUploadsSizeOption 来配置此阈值。

8 MiB 是默认缓冲区大小,您可以使用 UploadBufferSizeOption 选项进行修改。

C++ 客户端库使用的缓冲区大小等于数据块大小。缓冲区大小必须是 256 KiB(256 x 1024 字节)的倍数。使用 WriteObject()UploadFile() 时,您可能需要考虑上传速度和内存用量之间的权衡。使用小缓冲区上传大型对象可能会导致上传速度变慢。如需详细了解 C++ 的上传速度和缓冲区大小之间的关系,请参阅 GitHub 中的详细分析

C#

上传时,C# 客户端库始终会执行可续传上传。您可以使用 CreateObjectUploader 启动可续传上传。

C# 客户端库使用的缓冲区大小等于数据块大小。默认缓冲区大小为 10 MB,您可以通过在 UploadObjectOptions 上设置 ChunkSize 更改此值。缓冲区大小必须是 256 KiB(256 x 1024 字节)的倍数。较大的缓冲区大小通常有助于加快上传速度,但请注意,速度和内存用量之间存在权衡。

Go

默认情况下,当文件大于 16 MiB 时,系统会自动进行可续传上传。您可以使用 Writer.ChunkSize 更改执行可续传上传的截止时间。使用 Go 客户端库时,可续传上传始终会进行分块。

当对象小于 Writer.ChunkSizeWriter.ChunkSize 设置为 0(停用分块)时,系统会执行分段上传。如果 ChunkSize 设置为 0,则 Writer 无法重试请求

Go 客户端库使用的缓冲区大小等于数据块大小。缓冲区大小必须是 256 KiB(256 x 1024 字节)的倍数。较大的缓冲区大小通常有助于加快上传速度,但请注意,速度和内存用量之间存在权衡。如果您要同时运行多个可续传上传,则应将 Writer.ChunkSize 设置为小于 16 MiB 的值,以避免内存溢出。

请注意,在您调用 Writer.Close() 并收到成功响应之前,系统不会在 Cloud Storage 中最终确定对象。如果请求不成功,则 Writer.Close 将返回错误。

Java

Java 客户端库有单独的方法用于分段和可续传上传。以下方法始终执行可续传上传:

默认缓冲区大小为 15 MiB。如需设置缓冲区大小,可以使用 WriteChannel#setChunkSize(int) 方法,或者将 bufferSize 参数传入到 Storage#createFrom 方法。缓冲区大小的硬性最小值为 256KiB。在内部调用 WriteChannel#setChunkSize(int) 时,缓冲区大小将调整为 256 KiB 的倍数。

可续传上传的缓冲用作最小 flush 阈值,其中小于缓冲区大小的写入操作会被缓冲,直到写入操作使缓冲字节数超过缓冲区大小为止。

如果上传的数据量较少,请考虑使用 Storage#create(BlobInfo, byte[], Storage.BlobTargetOption...)Storage#create(BlobInfo, byte[], int, int, Storage.BlobTargetOption...)

Node.js

可续传上传会自动进行。您可以通过将 UploadOptions 上的 resumable 设置为 false 来关闭可续传上传。使用 createWriteStream 方法时,系统会自动管理可续传上传。

没有默认的缓冲区大小,并且必须通过在 CreateResumableUploadOptions 上设置 chunkSize 选项来手动调用分块上传。如果指定了 chunkSize,则系统会在单独的 HTTP 请求中发送数据,每个请求的载荷大小为 chunkSize。如果未指定 chunkSize,并且库正在执行可续传上传,则所有数据都会流式传输到单个 HTTP 请求中。

Node.js 客户端库使用的缓冲区大小等于数据块大小。缓冲区大小必须是 256 KiB(256 x 1024 字节)的倍数。较大的缓冲区大小通常有助于加快上传速度,但请注意,速度和内存用量之间存在权衡。

PHP

默认情况下,当对象大小超过 5 MB 时,系统会自动进行可续传上传。否则,将进行分段上传。此阈值无法更改。您可以通过在 upload 函数中设置 resumable 选项来强制进行可续传上传。

PHP 客户端库使用的缓冲区大小等于数据块大小。256 KiB 是可续传上传的默认缓冲区大小,您可以通过设置 chunkSize 属性来更改缓冲区大小。缓冲区大小必须是 256 KiB(256 x 1024 字节)的倍数。较大的缓冲区大小通常有助于加快上传速度,但请注意,速度和内存用量之间存在权衡。

Python

当对象大于 8 MiB 时,系统会执行可续传上传;当对象小于 8 MiB 时,系统会执行分段上传。此阈值无法更改。Python 客户端库使用的缓冲区大小等于数据块大小。100 MiB 是可续传上传的默认缓冲区大小,您可以通过设置 blob.chunk_size 属性来更改缓冲区大小。

如需始终执行可续传上传,而不论对象大小如何,请使用 storage.BlobWriter 类或 storage.Blob.open(mode='w') 方法。对于这些方法,默认缓冲区大小为 40 MiB。您还可以使用 Resumable Media 来管理可续传上传。

数据块大小必须是 256 KiB(256 x 1024 字节)的倍数。较大的数据块大小通常可使上传速度更快,但请注意,速度和内存用量之间存在权衡。

Ruby

Ruby 客户端库将所有上传视为未分块的可续传上传。

REST API

JSON API

Cloud Storage JSON API 使用包含查询参数 uploadType=resumablePOST Object 请求来启动可续传上传。此请求会返回一个会话 URI,您随后可以在一个或多个 PUT Object 请求中使用该 URI 上传对象数据。如需查看有关构建您自己的可续传上传逻辑的分步指南,请参阅执行可续传上传

XML API

Cloud Storage XML API 使用包含标头 x-goog-resumable: startPOST Object 请求来启动可续传上传。此请求会返回一个会话 URI,您随后可以在一个或多个 PUT Object 请求中使用该 URI 上传对象数据。如需查看有关构建您自己的可续传上传逻辑的分步指南,请参阅执行可续传上传

未知规模的可续传上传

可续传上传机制支持传输事先不知道大小的文件。对于在上传过程中即时压缩对象等情况而言,这非常有用,因为在传输开始时很难预测压缩文件的确切大小。如果您希望进行可在中断后恢复的流式传输,或者如果分块传输编码不适用于您的应用,则该机制非常有用。

如需了解详情,请参阅流式上传

上传性能

选择会话区域

可续传上传固定在您启动上传操作的地区中。例如,如果您在美国启动可续传上传,并将会话 URI 提供给亚洲的客户端,则上传仍会经由美国进行。为了减少跨区域流量并提高性能,您应该将可续传上传会话保留在创建它的区域中。

如果您使用 Compute Engine 实例启动可续传上传,则该实例应与您上传到的 Cloud Storage 存储桶位于同一位置。然后,您可以使用地理位置 IP 服务来选择将客户请求路由到的 Compute Engine 地区,这有助于将流量局限到某个地理位置地区。

分块上传

尽可能避免将传输分成较小的数据块,而是在一个数据块中上传全部内容。避免分块消除了查询每个数据块的持久偏移时增加的延迟时间费用和操作费用,并提高了吞吐量。不过,在以下情况中,您应考虑分块上传:

  • 系统正在动态生成您的源数据,并且您希望在上传失败时限制缓冲客户端所需的数据量。

  • 与许多浏览器一样,您的客户端具有请求大小限制。

如果您使用 JSON 或 XML API 并且客户端收到错误,它们可以向服务器查询持久偏移,并从该偏移处继续上传剩余的字节。Google Cloud 控制台、Google Cloud CLI 和客户端库将自动代表您处理此问题。如需详细了解如何对特定客户端库进行分块,请参阅工具和 API 如何使用可续传上传

注意事项

如果您正在构建自己的客户端(用于直接将可续传上传请求发送到 JSON 或 XML API),此部分会非常有用。

会话 URI

启动可续传上传时,Cloud Storage 会返回一个会话 URI,您可以在后续请求中使用该 URI 上传实际数据。JSON API 中的会话 URI 示例如下:

https://storage.googleapis.com/upload/storage/v1/b/my-bucket/o?uploadType=resumable&name=my-file.jpg&upload_id=ABg5-UxlRQU75tqTINorGYDgM69mX06CzKO1NRFIMOiuTsu_mVsl3E-3uSVz65l65GYuyBuTPWWICWkinL1FWcbvvOA

XML API 中的会话 URI 示例如下:

 https://storage.googleapis.com/my-bucket/my-file.jpg?upload_id=ABg5-UxlRQU75tqTINorGYDgM69mX06CzKO1NRFIMOiuTsu_mVsl3E-3uSVz65l65GYuyBuTPWWICWkinL1FWcbvvOA

此会话 URI 充当身份验证令牌,因此使用它的请求不需要签名,并且任何人都可以在不进行任何进一步的身份验证的情况下,使用这些请求将数据上传到目标存储桶。因此,请谨慎分享会话 URI,并且仅通过 HTTPS 分享。

会话 URI 的有效期为一周,但在到期之前可以进行取消。如果您使用已失效的会话 URI 发出请求,则会收到以下其中一个错误:

  • 410 Gone 状态代码(如果启动上传后不到一周)。
  • 404 Not Found 状态代码(如果启动上传已超过一周)。

在两种情况下,您都必须启动新的可续传上传,获得新的会话 URI,然后使用新的会话 URI 从头开始上传。

完整性检查

我们建议您请求对最终上传的对象进行完整性检查,以确保其与源文件相同。为此,您可以计算源文件的 MD5 digest,并将其添加到 Content-MD5 请求标头中。

如果您花了很长时间上传大型文件,检查上传文件的完整性尤其重要,这是因为上传操作过程中源文件被修改可能性会增加。

启动可续传上传时,系统会忽略 x-goog-content-sha256 值。因此,建议将 x-goog-content-sha256 设置为 UNSIGNED-PAYLOAD

重试和重新发送数据

当 Cloud Storage 在可续传上传操作中保留字节后,这些字节将无法被覆盖,且 Cloud Storage 会忽略尝试这样做。因此,在回滚到您先前发送的偏移时,您不应发送不同的数据。

例如,假设您要上传一个 10 万个字节的对象,并且您的连接已中断。当您检查状态时,会发现已成功上传并保留 50000 个字节。如果您尝试在第 40000 个字节处重启上传,则 Cloud Storage 会忽略您从 40000 发送到 50000 的字节。Cloud Storage 将开始保留您在第 50001 个字节处发送的数据。

后续步骤