本页面讨论 Cloud Storage 中的可续传上传。建议您使用可续传上传来上传大型文件,因为在上传过程中网络出现故障时,您不必从头开始重新上传。
简介
借助可续传上传,您可以在数据流因通信故障而中断后,恢复数据传输到 Cloud Storage 的操作。可续传上传的工作原理是发送多个请求,每个请求包含您正在上传的对象的一部分。这与简单上传不同,后者在单个请求中包含对象的所有数据,一旦中途失败,则必须从头开始重新上传。
如果您要上传大型文件或通过较慢的连接上传,请使用可续传上传。如需了解使用可续传上传时的示例文件大小临界值,请参阅上传大小注意事项。
可续传上传必须在启动后的一周内完成,但可以随时取消。
只有已完成的可续传上传会显示在您的存储桶中,并替换具有相同名称的现有对象(如适用)。
对象的创建时间取决于上传完成时间。
用户设置的对象元数据是在初始请求中指定的。此元数据在上传完成后会应用于对象。
如果您在最终请求中包括前缀为
X-Goog-Meta-
的标头,则 JSON API 还支持在最终请求中设置自定义元数据。
- 一次完成的可续传上传视为一项 A 类操作。
工具和 API 如何使用可续传上传
根据您与 Cloud Storage 的交互方式,系统可能会代表您自动管理可续传上传。本部分介绍不同工具的可续传上传行为,并说明如何为应用配置适当的缓冲区大小。
控制台
Google Cloud 控制台会代表您自动管理可续传上传。但是,如果您在上传过程中刷新或离开 Google Cloud 控制台,则系统会取消上传。
命令行
在将数据上传到 Cloud Storage 时,gcloud CLI 会通过 gcloud storage cp
和 gcloud storage rsync
命令使用可续传上传。如果上传被中断,您可以通过运行用于启动上传的命令来恢复上传。在恢复这种包含多个文件的上传时,请使用 --no-clobber
标志以防止重新上传已成功完成的文件。
客户端库
C++
storage::Client
中的函数具有不同的行为:
Client::WriteObject()
始终执行可续传上传。Client::InsertObject()
始终执行简单或分段上传。Client::UploadFile()
可以执行可续传上传、简单上传或分段上传。
默认情况下,当对象大于 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.ChunkSize
或 Writer.ChunkSize
设置为 0(停用分块)时,系统会执行分段上传。如果 ChunkSize
设置为 0,则 Writer
无法重试请求。
Go 客户端库使用的缓冲区大小等于数据块大小。缓冲区大小必须是 256 KiB(256 x 1024 字节)的倍数。较大的缓冲区大小通常有助于加快上传速度,但请注意,速度和内存用量之间存在权衡。如果您要同时运行多个可续传上传,则应将 Writer.ChunkSize
设置为小于 16 MiB 的值,以避免内存溢出。
请注意,在您调用 Writer.Close()
并收到成功响应之前,系统不会在 Cloud Storage 中最终确定对象。如果请求不成功,则 Writer.Close
将返回错误。
Java
Java 客户端库有单独的方法用于分段和可续传上传。以下方法始终执行可续传上传:
Storage#createFrom(BlobInfo, java.io.InputStream, Storage.BlobWriteOption...)
Storage#createFrom(BlobInfo, java.io.InputStream, int, Storage.BlobWriteOption...)
Storage#createFrom(BlobInfo, java.nio.file.Path, Storage.BlobWriteOption...)
Storage#createFrom(BlobInfo, java.nio.file.Path, int, Storage.BlobWriteOption...)
Storage#writer(BlobInfo, Storage.BlobWriteOption...)
Storage#writer(java.net.URL)
默认缓冲区大小为 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=resumable
的 POST Object
请求来启动可续传上传。此请求会返回一个会话 URI,您随后可以在一个或多个 PUT Object
请求中使用该 URI 上传对象数据。如需查看有关构建您自己的可续传上传逻辑的分步指南,请参阅执行可续传上传。
XML API
Cloud Storage XML API 使用包含标头 x-goog-resumable: start
的 POST 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 个字节处发送的数据。
后续步骤
- 执行可续传上传。
- 了解如何重试对 Cloud Storage 的请求。
- 了解 Cloud Storage 中的上传的其他类型。