使用 Go 基于异步计划复制 Blob

本文介绍了如何使用适用于 Go 的 Azure 存储客户端模块基于异步计划复制 Blob。 你可以从同一存储帐户中的源、不同存储帐户中的源或从通过 HTTP GET 请求在给定 URL 上检索的任何可访问对象复制 Blob。 还可以中止挂起的复制操作。

本文中介绍的方法将使用 Copy Blob REST API 操作,并且可以在想要基于异步计划执行复制时使用。 对于要将数据移动到存储帐户且具有源对象的 URL 的大多数复制方案,请参阅使用 Go 从源对象 URL 复制 Blob

先决条件

设置你的环境

如果没有现有项目,请查看本部分,其中介绍了如何设置项目来使用适用于 Go 的 Azure Blob 存储客户端模块。 步骤包括模块安装、添加 import 路径以及创建授权的客户端对象。 有关详细信息,请参阅 Azure Blob 存储和 Go 入门

安装模块

使用以下命令安装 azblob 模块:

go get github.com/Azure/azure-sdk-for-go/sdk/storage/azblob

若要使用 Microsoft Entra ID 进行身份验证(建议),请使用以下命令安装 azidentity 模块:

go get github.com/Azure/azure-sdk-for-go/sdk/azidentity

添加导入路径

在代码文件中添加以下导入路径:

import (
    "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
)

这些导入路径代表了开始之前需要满足的最低要求。 本文中的某些代码示例可能需要其他导入路径。 有关具体详细信息和示例用法,请参阅代码示例

创建客户端对象

若要将应用连接到 Blob 存储,请使用 azblob.NewClient 创建客户端对象。 以下示例演示如何使用 DefaultAzureCredential 创建客户端对象进行授权:

func getServiceClientTokenCredential(accountURL string) *azblob.Client {
    // Create a new service client with token credential
    credential, err := azidentity.NewDefaultAzureCredential(nil)
    handleError(err)

    client, err := azblob.NewClient(accountURL, credential, nil)
    handleError(err)

    return client
}

授权

授权机制必须具有执行复制操作或中止挂起的复制的必要权限。 若要使用 Microsoft Entra ID 进行授权(建议),需要 Azure RBAC 内置角色“存储 Blob 数据参与者”或更高级别的角色。 若要了解详细信息,请参阅复制 Blob中止复制 Blob 的授权指导。

关于基于异步计划复制 Blob

Copy Blob 操作可以异步完成,并且是在尽最大努力的基础上执行的,这意味着该操作不一定会立即开始或在指定的时间范围内完成。 复制操作是在后台安排的,并在服务器具有可用资源时执行。 如果复制发生在同一存储帐户内,则操作可以同步完成。

Copy Blob 操作可以执行以下任何操作:

  • 将源 Blob 复制到具有不同名称的目标 Blob。 目标 Blob 可以是相同类型(块、追加或页类型)的现有 Blob,也可以是复制操作创建的新 Blob。
  • 将源 Blob 复制到具有相同名称的目标 Blob,从而替换目标 Blob。 此类复制操作会移除所有未提交的块,并覆盖目标 Blob 的元数据。
  • 将 Azure 文件服务中的源文件复制到目标 Blob。 目标 Blob 可以是现有的块 Blob,也可以是复制操作创建的新块 Blob。 不支持从文件复制到页 Blob 或追加 Blob。
  • 将快照复制到其基本 Blob 上。 通过将快照提升到基本 Blob 的位置,可还原早期版本的 Blob。
  • 将快照复制到具有不同名称的目标 Blob。 生成的目标 Blob 是可写的 Blob,而不是快照。

复制操作的源 Blob 可以是以下类型之一:块 Blob、追加 Blob、页 Blob、Blob 快照或 Blob 版本。 该复制操作会始终复制整个源 Blob 或文件。 不支持复制字节范围或块集。

如果目标 Blob 已存在,则其类型必须与源 Blob 相同,并且系统将会覆盖现有目标 Blob。 进行复制操作时无法修改目标 Blob,并且目标 Blob 只能有一个未完成的复制操作。

若要详细了解 Copy Blob 操作,包括有关属性、索引标记、元数据和计费的信息,请参阅 Copy Blob 注解

基于异步计划复制 Blob

本部分概述了适用于 Go 的 Azure 存储客户端模块提供的基于异步计划执行复制操作的方法。

以下方法将会封装 Copy Blob REST API 操作,并开始从源 Blob 异步复制数据:

在 Azure 中从源复制 blob

如果要在同一存储帐户中复制 Blob,操作可以同步完成。 可以通过 Microsoft Entra ID(推荐)、共享访问签名 (SAS) 或帐户密钥来授权对源 Blob 的访问。 有关引起改变的同步复制操作,请参阅使用 Go 从源对象 URL 复制 Blob

如果复制源是其他存储帐户中的 Blob,则操作可以异步完成。 源 Blob 必须是公共的或通过 SAS 令牌获得授权。 SAS 令牌需要包含读取 ('r') 权限。 若要详细了解 SAS 令牌,请参阅使用共享访问签名委派权限

以下示例演示使用异步计划从其他存储帐户复制源 Blob 的方案。 在此示例中,我们将使用追加的用户委派 SAS 令牌创建源 Blob URL。 该示例假定你提供自己的 SAS。 此示例还演示了如何在复制操作期间租用源 Blob,以防止有人从其他客户端对该 Blob 进行更改。 Copy Blob 操作会在复制操作开始时保存源 Blob 的 ETag 值。 如果 ETag 值在复制操作完成之前发生了更改,则操作将失败。 我们还使用 StartCopyFromURLOptions 结构将目标 Blob 的访问层设置为 Cool

func copyFromSourceAsync(srcBlob *blockblob.Client, destBlob *blockblob.Client) {
    // Lease the source blob during copy to prevent other clients from modifying it
    blobLeaseClient, err := lease.NewBlobClient(srcBlob, nil)
    handleError(err)

    _, err = blobLeaseClient.AcquireLease(context.TODO(), int32(60), nil)
    handleError(err)

    // Retrieve the SAS token for the source blob and append it to the URL
    sas := "<sas-token>"
    url := srcBlob.URL() + "?" + sas

    // Set copy options
    copyOptions := blob.StartCopyFromURLOptions{
        Tier: to.Ptr(blob.AccessTierCool),
    }

    // Copy the blob from the source URL to the destination blob
    startCopy, err := destBlob.StartCopyFromURL(context.TODO(), url, &copyOptions)
    handleError(err)

    // If startCopy.CopyStatus returns a status of "pending", the operation has started asynchronously
    // You can optionally add logic to poll the copy status and wait for the operation to complete
    // Example:
    copyStatus := *startCopy.CopyStatus
    for copyStatus == blob.CopyStatusTypePending {
        time.Sleep(time.Second * 2)

        properties, err := destBlob.GetProperties(context.TODO(), nil)
        handleError(err)

        copyStatus = *properties.CopyStatus
    }

    // Release the lease on the source blob
    _, err = blobLeaseClient.ReleaseLease(context.TODO(), nil)
    handleError(err)
}

以下示例演示了示例用法:

// TODO: replace <storage-account-name> placeholders with actual storage account names
srcURL := "https://<src-storage-account-name>.blob.core.chinacloudapi.cn/"
destURL := "https://<dest-storage-account-name>.blob.core.chinacloudapi.cn/"

credential, err := azidentity.NewDefaultAzureCredential(nil)
handleError(err)

srcClient, err := azblob.NewClient(srcURL, credential, nil)
handleError(err)
destClient, err := azblob.NewClient(destURL, credential, nil)
handleError(err)

srcBlob := srcClient.ServiceClient().NewContainerClient("source-container").NewBlockBlobClient("source-blob")
destBlob := destClient.ServiceClient().NewContainerClient("destination-container").NewBlockBlobClient("destination-blob-1")

copyFromSourceAsync(srcBlob, destBlob)

注意

用户委派 SAS 令牌提供了更高的安全性,因为它们是使用 Microsoft Entra 凭据而不是帐户密钥进行签名的。 若要创建用户委托 SAS 令牌,Microsoft Entra 安全主体需要适当的权限。 有关授权要求,请参阅获取用户委派密钥

从 Azure 外部的源复制 Blob

你可以对可通过 HTTP GET 请求在给定 URL 上检索的任何源对象执行复制操作,包括 Azure 外部的可访问对象。 以下示例演示了从可访问的源对象 URL 复制 Blob 的方案:

func copyFromExternalSourceAsync(srcURL string, destBlob *blockblob.Client) {
    // Set copy options
    copyOptions := blob.StartCopyFromURLOptions{
        Tier: to.Ptr(blob.AccessTierCool),
    }

    // Copy the blob from the source URL to the destination blob
    startCopy, err := destBlob.StartCopyFromURL(context.TODO(), srcURL, &copyOptions)
    handleError(err)

    // If startCopy.CopyStatus returns a status of "pending", the operation has started asynchronously
    // You can optionally add logic to poll the copy status and wait for the operation to complete
    // Example:
    copyStatus := *startCopy.CopyStatus
    for copyStatus == blob.CopyStatusTypePending {
        time.Sleep(time.Second * 2)

        properties, err := destBlob.GetProperties(context.TODO(), nil)
        handleError(err)

        copyStatus = *properties.CopyStatus
    }
}

以下示例演示了示例用法:

externalURL := "<source-url>"

destBlob = destClient.ServiceClient().NewContainerClient("destination-container").NewBlockBlobClient("destination-blob-2")

copyFromExternalSourceAsync(externalURL, destBlob)

检查复制操作的状态

若要检查异步 Copy Blob 操作的状态,可以轮询 GetProperties 方法并检查复制状态。

以下代码示例演示了如何检查复制操作的状态:

func checkCopyStatus(destBlob *blockblob.Client) {
    // Retrieve the properties from the destination blob
    properties, err := destBlob.GetProperties(context.TODO(), nil)
    handleError(err)

    copyID := *properties.CopyID
    copyStatus := *properties.CopyStatus

    fmt.Printf("Copy operation %s is %s\n", copyID, copyStatus)
}

中止复制操作

中止挂起的 Copy Blob 操作会导致目标 Blob 长度为零。 但是,目标 Blob 的元数据将包含从源 Blob 复制的新值,或者在复制操作过程中显式设置的新值。 若要在复制之前保留原始元数据,请在调用一个复制方法之前创建目标 Blob 的快照。

要中止挂起的复制操作,请调用以下某个操作:

此方法会包装中止复制 Blob REST API 操作,这会取消挂起的 Copy Blob 操作。 以下代码示例演示了如何中止挂起的 Copy Blob 操作:

func abortCopy(destBlob *blockblob.Client) {
    // Retrieve the copy ID from the destination blob
    properties, err := destBlob.GetProperties(context.TODO(), nil)
    handleError(err)

    copyID := *properties.CopyID
    copyStatus := *properties.CopyStatus

    // Abort the copy operation if it's still pending
    if copyStatus == blob.CopyStatusTypePending {
        _, err := destBlob.AbortCopyFromURL(context.TODO(), copyID, nil)
        handleError(err)

        fmt.Printf("Copy operation %s aborted\n", copyID)
    }
}

资源

若要详细了解如何使用适用于 Go 的 Azure Blob 存储客户端模块来通过异步计划复制 blob,请参阅以下资源。

代码示例

REST API 操作

Azure SDK for Go 包含基于 Azure REST API 而生成的库,从而允许你通过熟悉的 Go 范式与 REST API 操作进行交互。 本文中介绍的方法使用以下 REST API 操作:

客户端模块资源

  • 本文是适用于 Go 的 Blob 存储开发人员指南的一部分。 若要了解详细信息,请参阅构建 Go 应用中的完整开发人员指南文章列表。