适用范围:SQL Server
从 Microsoft Azure 存储进行备份或还原时,SQL Server 将占用无限期租约,以锁定对 blob 的独占访问权。 备份或还原过程成功完成后,该过程将释放租约。 如果备份或还原失败,备份过程会尝试清理任何无效的 Blob 数据。 但是,如果长时间或持续网络连接失败导致备份失败,则备份过程可能无法访问 Blob,Blob 可能仍为孤立状态。 此条件意味着在租约被释放之前,无法对 Blob 进行写入或删除操作。 本文介绍如何释放(中断)租约并删除 Blob 对象。
有关详细信息,请参阅租用 Blob (REST API)。
如果备份操作失败,它可能生成无效的备份文件。 备份 blob 文件可能还有活动租约,以防止其被删除或覆盖。 若要删除或覆盖此类 Blob,请首先释放(中断)租约。 如果发生备份失败,请清理租约并删除 Blob。 还可以定期清理租约并删除 blob,这作为存储管理任务的一部分。
如果还原失败,则不会阻止后续还原,因此活动租约可能不是问题。 只有在需要覆盖或删除 Blob 时,您才需要中断租约。
管理孤立的 blob
本部分中的步骤介绍如何使用 PowerShell 在备份或还原活动失败后进行清理。
识别具有租约的 Blob: 如果有一个运行备份进程的脚本或进程,则可以捕获脚本或进程中的失败,并使用该失败来清理 Blob。 还可以使用
LeaseStats和LeastState属性来标识具有租约的 Blob。 标识 Blob 后,请查看列表,并在删除 Blob 之前验证备份文件的有效性。中断租约:获得授权的请求可以中断租约而不提供租约 ID。 有关详细信息,请参阅 租用 Blob。
提示
SQL Server 使用租约 ID 在还原作期间建立独占访问权限。 还原租约 ID 是 BAC2BAC2BAC2BAC2BAC2BAC2BAC2BAC2。
删除 Blob: 若要删除具有活动租约的 Blob,请先中断租约。
PowerShell 脚本示例
重要
如果运行的是 PowerShell 2.0,则加载Microsoft WindowsAzure.Storage.dll 程序集时可能会遇到问题。 升级 Powershell 以解决该问题。 还可以使用以下解决方法创建或修改 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>
以下示例脚本标识具有活动租约的二进制大对象,然后终止这些租约。 该示例还演示了如何筛选发布的租约ID。
有关运行此脚本的提示
警告
如果备份与此脚本同时运行,备份可能会失败,因为此脚本会中断备份尝试同时获取的租约。 在维护时段或没有正在执行或预计要运行的备份时运行此脚本。
运行此脚本之前,请为存储帐户、存储密钥、容器以及 Azure 存储程序集路径和名称参数添加值。 存储程序集的路径是 SQL Server 实例的安装目录。 存储程序集的文件名为 Microsoft.WindowsAzure.Storage.dll。
如果没有具有锁定租约的 Blob,则会看到以下消息:
There are no blobs with locked lease status如果存在具有锁定租约的 Blob,则会看到以下消息:
Breaking Leases、The lease on <URL of the Blob> is a restore lease: You will see this message only if you have a blob with a restore lease that is still active.和The lease on <URL of the Blob> is not a restore lease Breaking lease on <URL of the Bob>.
$storageAccount = "<myStorageAccount>"
$storageKey = "<myStorageKey>"
$blobContainer = "<myBlobContainer>"
$storageAssemblyPathName = "<myStorageAssemblyPathName>"
# 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($storageAssemblyPathName)
[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
$blobs = $container.ListBlobs($null,$true)
# filter blobs that are have Lease Status as "locked"
$lockedBlobs = @()
foreach($blob in $blobs)
{
$blobProperties = $blob.Properties
if($blobProperties.LeaseStatus -eq "Locked")
{
$lockedBlobs += $blob
}
}
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
}
} else { Write-Host " There are no blobs with locked lease status." }