删除具有活动租约的备份 Blob 文件

备份或从 Azure 存储还原时,SQL Server 会获取无限租约,以便锁定对 Blob 的独占访问。 成功完成备份或还原过程后,将释放租约。 如果备份或还原失败,备份过程将尝试清理任何无效的 Blob。 但是,如果备份由于长时间或持续网络连接失败而失败,则备份过程可能无法访问 Blob,Blob 可能仍然孤立。 这意味着,在释放租约之前,blob 无法被写入或删除。 本主题介绍如何释放租约和删除 blob。

有关租约类型的详细信息,请阅读 本文

如果备份作失败,则可能会导致备份文件无效。 备份 Blob 文件可能还具有正在生效的租约,阻止其被删除或覆盖。 若要删除或覆盖此类 Blob,应首先断开租约。 如果发生备份失败,建议清理租约并删除 Blob。 还可以定期选择清理作为存储管理任务的一部分。

如果还原失败,则不会阻止后续还原,因此活动租约可能不是问题。 仅当必须覆盖或删除 Blob 时,才需要中断租约。

管理孤立的 Blob 对象

以下步骤介绍如何在备份或还原活动失败后进行清理。 可以使用 PowerShell 脚本完成所有步骤。 以下部分提供了代码示例:

  1. 标识具有租约的 blob: 如果有一个运行备份进程的脚本或进程,则可以捕获脚本或进程中的失败,并使用该脚本来清理 Blob。 还可以使用 LeaseStats 和 LeastState 属性来标识具有租约的 blob。 确定 Blob 后,建议查看列表,在删除 Blob 之前验证备份文件的有效性。

  2. 中断租约: 授权请求可以中断租约,而无需提供租约 ID。 有关详细信息,请参阅此处

    小窍门

    SQL Server 在还原操作期间分配租约 ID 来建立独占访问权限。 还原租约 ID 是 BAC2BAC2BAC2BAC2BAC2BAC2BAC2BAC2。

  3. 删除 Blob: 若要删除具有活动租约的 Blob,需要先中断租约。

PowerShell 脚本示例

**重要** 如果运行的是 PowerShell 2.0,则加载Microsoft WindowsAzure.Storage.dll 程序集时可能会遇到问题。 建议升级到 Powershell 3.0 以解决该问题。 还可以对 PowerShell 2.0 使用以下解决方法:

  • 创建或修改 powershell.exe.config 文件,以在运行时加载 .NET 2.0 和 .NET 4.0 程序集,如下所示:

    <?xml version="1.0"?>
    <configuration>
        <startup useLegacyV2RuntimeActivationPolicy="true">
            <supportedRuntime version="v4.0.30319"/>
            <supportedRuntime version="v2.0.50727"/>
        </startup>
    </configuration>
    

以下示例演示如何识别处于有效状态的租约的 blob,然后解除这些租约。 该示例还演示了如何筛选发布的租约 ID。

有关运行此脚本的提示

警告

如果备份到 Azure Blob 存储服务与此脚本同时运行,备份可能会失败,因为此脚本会中断备份尝试同时获取的租约。 建议在维护时段或预计不会运行任何备份时运行此脚本。

  1. 运行此脚本时,系统会提示你提供存储帐户、存储密钥、容器和 Azure 存储程序集路径和名称参数的值。 存储路径是 SQL Server 实例的安装目录。 存储程序集的文件名 Microsoft.WindowsAzure.Storage.dll。 下面是输入的提示和值的示例:

    cmdlet  at command pipeline position 1  
    Supply values for the following parameters:  
    storageAccount: mycloudstorageaccount  
    storageKey: 0BopKY7eEha3gBnistYk+904nf  
    blobContainer: mycontainer   
    storageAssemblyPath: C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Binn\Microsoft.WindowsAzure.Storage.dll  
    
  2. 如果没有锁定租约的 blob,那么您应该会看到以下消息:

    没有具有锁定租约状态的数据块

    如果存在具有锁定租约的 Blob,应会看到以下消息:

    中断租约

    Blob 的 <URL > 租约是还原租约:仅当 Blob 具有仍处于活动状态的还原租约时,才会看到此消息。

    Blob> 的 URL 上的<租约不是 Bob> 的 URL 上的<还原租约中断性租约。

param(  
       [Parameter(Mandatory=$true)]  
       [string]$storageAccount,  
       [Parameter(Mandatory=$true)]  
       [string]$storageKey,  
       [Parameter(Mandatory=$true)]  
       [string]$blobContainer,  
       [Parameter(Mandatory=$true)]  
       [string]$storageAssemblyPath  
)  
  
# Well known Restore Lease ID  
$restoreLeaseId = "BAC2BAC2BAC2BAC2BAC2BAC2BAC2BAC2"  
  
# Load the storage assembly without locking the file for the duration of the PowerShell session  
$bytes = [System.IO.File]::ReadAllBytes($storageAssemblyPath)  
[System.Reflection.Assembly]::Load($bytes)  
  
$cred = New-Object 'Microsoft.WindowsAzure.Storage.Auth.StorageCredentials' $storageAccount, $storageKey  
$client = New-Object 'Microsoft.WindowsAzure.Storage.Blob.CloudBlobClient' "https://$storageAccount.blob.core.windows.net", $cred  
$container = $client.GetContainerReference($blobContainer)  
  
#list all the blobs  
$allBlobs = $container.ListBlobs()
  
$lockedBlobs = @()  
# filter blobs that are have Lease Status as "locked"  
foreach($blob in $allBlobs)  
{  
    $blobProperties = $blob.Properties
    if($blobProperties.LeaseStatus -eq "Locked")  
    {  
        $lockedBlobs += $blob  
    }  
}  
  
if ($lockedBlobs.Count -eq 0)  
{
    Write-Host " There are no blobs with locked lease status"  
}

if($lockedBlobs.Count -gt 0)  
{  
    Write-Host "Breaking leases"  
    foreach($blob in $lockedBlobs )
    {  
        try  
        {  
            $blob.AcquireLease($null, $restoreLeaseId, $null, $null, $null)  
            Write-Host "The lease on $($blob.Uri) is a restore lease"  
        }  
        catch [Microsoft.WindowsAzure.Storage.StorageException]  
        {  
            if($_.Exception.RequestInformation.HttpStatusCode -eq 409)  
            {  
                Write-Host "The lease on $($blob.Uri) is not a restore lease"  
            }  
        }  
  
        Write-Host "Breaking lease on $($blob.Uri)"  
        $blob.BreakLease($(New-TimeSpan), $null, $null, $null) | Out-Null  
    }  
}

另请参阅

SQL Server 备份到 URL 的最佳做法和故障排除