上传 blob 或块内容在 Azure Blob 存储 中失败

本文介绍如何解决Microsoft Azure Blob 存储与云应用程序一起使用上传 blob 或阻止内容时可能发生的故障。

先决条件

现象

收到以下错误消息之一。

错误代码 错误消息
BlockCountExceedsLimit “未提交的块计数不能超过最大限制 100,000 个块。
InvalidBlobOrBlock “指定的 blob 或块内容无效。
InvalidBlockInvalidBlockList “指定的块列表无效。”

原因 1:Put Block 调用中指定的块长度无效

在 Put Block URI 请求中指定的 长度对于以下一个或多个原因无效:

  • 应用程序或客户端指定了不支持的块大小。

  • 块的大小大于允许的最大块大小。 若要查找不同版本的 Blob 服务 REST API 的块大小限制,请参阅 “放置块”参考文章的“备注 ”部分。

  • 尝试使用多个应用程序上传数据块时,存在不一致的块长度的未提交块。 出现这种情况的原因是不同的应用程序使用不同的长度上传数据,或者因为以前的上传失败。

  • Blob 具有过多未提交的块,因为先前的上传操作已取消。 与 Blob 关联的未提交的块的最大数目为 100,000。

通过实现其中一个解决方案来删除未提交的块。

解决方案 1:等待垃圾回收选取未提交的数据

等待七天,让未提交的阻止列表通过垃圾回收来清理。

解决方案 2:使用虚拟 Blob 进行数据传输

使用 Azure 存储 SDK 通过虚拟 Blob 传输数据。 为此,请按照下列步骤进行操作:

  1. 创建具有相同 Blob 名称且位于同一容器中的虚拟 Blob。 此 Blob 的长度可以为零。

  2. 使用未阻止的传输来传输 Blob。

解决方案 3:使用 Azure 存储 SDK 提交未提交的阻止列表

使用 Azure 存储 SDK 提交未提交的块列表并清理 Blob。 为此,请按照下列步骤进行操作:

  1. 通过发出 URI 参数设置为uncommittedblocklisttype“获取阻止列表 URI”请求来检索未提交的阻止列表

  2. 使用 Put Block List URI 请求提交阻止列表

  3. 删除 Blob。

以下 PowerShell 函数是一个示例,演示如何检索未提交的块列表,然后将其删除。 该函数需要以下参数。

参数名称 说明
-StorageAccountName 存储帐户的名称。
-SharedAccessSignature 使用 URI 参数 <ss=b;srt=sco;sp=rwldc>的共享访问签名 (SAS) 令牌。 构造帐户 SAS URI介绍了这些参数。
-ContainerName 存储容器的名称。
-BlobName blob 的名称。
[CmdletBinding()] Param(
    [Parameter(Mandatory=$true, Position=1)] [string] $StorageAccountName,
    [Parameter(Mandatory=$True, Position=1)] [string] $SharedAccessSignature,
    [Parameter(Mandatory=$True, Position=1)] [string] $ContainerName,
    [Parameter(Mandatory=$True, Position=1)] [string] $BlobName
)

# Build the URI strings in the REST API for GET and DELETE.
$uriDelete = (
    "https://$StorageAccountName.blob.core.windows.net/",
    "$ContainerName",
    "/",
    "$BlobName",
    "$SharedAccessSignature"
) -Join ""
$uriGet = (
    "$uriDelete",
    "&comp=blocklist",
    "&blocklisttype=uncommitted"
) -Join ""
Write-Host "The Delete URI is $uriDelete."
Write-Host "The Get URI is $uriGet."

# Make a REST API call to get the uncommitted block list.
$listFileURI = Invoke-WebRequest -Uri $uriGet -Method Get
$FileSystemName = $listFileURI.Content
$String = $FileSystemName -replace '' , ''
$String |
    Select-Xml –XPath "/BlockList/UncommittedBlocks/Block" |
        Select-Object -Expand Node
$Count = $String.Count

# Delete the blob and the uncommitted block.
if ($Count.Count -gt 0) {
    $listFileURI1 =  Invoke-WebRequest -Uri $uriDelete -Method Delete
    $FileSystemName1 = $listFileURI1.StatusCode
    Write-Host "The deletion was successful. The API returned status code $FileSystemName1."
}

Write-Host "Check whether the uncommitted blocks are still present."
Try {
    $listFileURI2 = Invoke-WebRequest -Uri $uriGet -Method Get
} Catch {
    # $err = $_.Exception
    Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__
    Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
}

Write-Host (
    "In this error message, we can verify that the",
    "uncommitted blocks and their respective blob have been deleted.",
    "The name and size of the uncommitted blocks that have been deleted are shown."
)

原因 2:BLOB 同时执行 PUT 操作

出现计时或并发问题。 这会导致单个 Blob 在同一时间执行多个 PUT(放置块)操作。 “放置块列表”操作通过指定构成 Blob 的块 ID 列表来写入 Blob。 若要作为 Blob 的一部分写入,必须在之前的 Put 块 操作中成功将块写入服务器。

注意

在启动上传之后,但在提交之前,并发上传提交期间可能会出现此错误。 在这种情况下,上传失败。 应用程序可以在发生错误时重试上传,也可以尝试基于所需方案的其他恢复操作。

解决方案:使用租约

尝试使用 Azure 存储 SDK 或基于 GUI 的工具(如Azure 存储资源管理器)实现悲观并发(租约),而不是使用乐观并发。 有关乐观和悲观并发的详细信息,请参阅 管理 Blob 存储中的并发。

如果错误是由并发问题引起的,则你可能还必须按照原因 1 中的其中一个解决方案来清理未提交的块。

联系我们寻求帮助

如果你有任何疑问或需要帮助,请创建支持请求联系 Azure 社区支持。 你还可以将产品反馈提交到 Azure 反馈社区