先說他的備份環境大致是這樣:「所有 Production 的 Hyper-V Hosts 先將 VM Replica 到一台肚子超大的 Server 裡, 然後再用 Veeam 去備份這些副本 VM」
聽起來這個策略沒什麼問題, 在副本 Host 上備份根本理所當然, 不會去影響到 Production 的效能
但當備份到容量較大的 VM, 尤其是 SQL Server 的時候卻產生了問題
Full Backup 時總會遇到以下錯誤:
Processing Mercury Error: Failed to call wmi method 'DestroySnapshot'. Wmi error: '32775' Failed to delete VM snapshot, snapshot path '%2'.
Failed to create VM recovery checkpoint (mode: Crash consistent) Details: Failed to call wmi method 'CreateSnapshot'.
Wmi error: '32775' Failed to create VM recovery snapshot,VM ID 'ooooooooooooooooooo'.
Retrying snapshot creation attempt (Failed to create production checkpoint.)
Task has been rescheduled
Queued for processing at [Date Time]
Unable to allocate processing resources. Error: Failed to call wmi method 'CreateSnapshot'.
Wmi error: '32775' Failed to create VM recovery snapshot, VM ID 'ooooooooooooooooooo'.
在備份的 Repository 裡面的確有看到 vbk 檔案, 看起來很像有備份成功
但上述錯誤發生後該 VM 會卡在 Applying Changes, 後續複寫則全部失敗
且 Hyper-V Virtual Machine Management Service 無法 Stop, 重開機指令下去後要等待兩小時左右才能重開機成功
一步一步來, Workaround 的方式如下:
- 遇到問題後先將 Hyper-V Virtual Machine Management Service 改為手動啟動, 不要讓他開機自動啟動
- Stop Hyper-V Virtual Machine Management Service
- 下指令 taskkill /f /im vmms.exe 將 Process Kill 掉
- 重開機就不需要等兩小時
- 開好機後在 net start vmms 指令之後緊接著快速地連續下達以下指令
Get-VM "YourVMName" | Get-VMCheckpoint -SnapshotType Recovery | Remove-VMCheckpoint - 步驟 5 最好是多開幾個視窗, 連續下指令, 錯誤沒關係, 就怕來不及, VM 又進入了卡在 Apply Changes 的狀態
- 這樣做完後可以至少將 VM 的狀態復原, 後續再嘗試備份
★. 在備份之前 Pause Replication
問題是一個 Backup Job 裡面有很多 VM, Veeam 又不提供在每一個 VM 備份前後執行 Script 的功能, 只能在 Backup Job 開始前、後跑 Script, 因此勢必要找其他辦法辦到此事。最後根據 Veeam 所提供的 PowerShell CMDLet 指令, 完成了以下 Script
運作邏輯是:
- 找出 Job 中所要備份的 VM List 存成一個 txt 檔
- 從第一台 VM 開始, 將其他的 VM 先設為排除 (Exclude) 項目
- 將 Backup Job 中留下要進行備份的 VM 暫停複寫
- 執行 Backup Job
- 完成備份後將該已完成的 VM 寫入一個 txt 檔作為已完成備份的標記
- 將剛剛備份完成的 VM 恢復複寫
- 將剛剛設為排除的所有其他 VM 加回 Backup Job
- 比對 VM List 與已完成 VM List 的 txt 檔比較, 找出下一台還沒備份的 VM
- 重複上述迴圈直到所有 VM 備份完畢
Script 中有一段要去讀取一個 Password.txt 檔案, 是因為 Veeam Backup 一定不是安裝在 Hyper-V Host 上, 所以去把 VM 複寫暫停這件事情要透過 Remote PowerShell 去執行. 要做到這件事情要進行以下步驟
- 在被控端 Hyper-V-Host 執行指令: WinRM quickconfig 允許 WinRM 連入
- 在控制端 Veeam Backup Server 上面設定相信被控端 Hyper-V-Host
指令: Set-Item WSMan:\localhost\Client\TrustedHosts "Hyper-V-Host"
(我一直覺得很怪, 為什麼是控制端要去相信被控端而不是反過來呢....:Q) - 步驟二執行完畢可以用以下指令檢查
winrm s winrm/config/client '@{TrustedHosts="Hyper-V-Host"}'
- Read-Host -Prompt 'Enter Password' -AsSecureString | ConvertFrom-SecureString | Out-File Password.txt
以下為 Powershell Script:
#----- 設定開始
$JobName = "VMBackupJob";
#----- 程式開始
$DateTimeString = Get-Date -format yyyyMMdd_HHmmss
$TranscriptLog = (Get-Item -Path ".\" -Verbose).FullName + "\Logs\" + ("CertRenew_" + $DateTimeString + ".log")
start-transcript -path $TranscriptLog
Add-PsSnapin -Name VeeamPSSnapIn -ErrorAction SilentlyContinue;
$AllVM_Text = 'AllVM.txt';
$ProcessedVM_Text = 'ProcessedVM.txt';
write-host "";
Write-Host "Get All VMs in Job";
write-host "";
$Job = Get-VBRJob -Name $JobName;
$AllVM = $Job.GetObjectsInJob().name;
if ((Test-Path $AllVM_Text) -eq $True) {
Remove-Item $AllVM_Text;
};
if ((Test-Path $ProcessedVM_Text) -eq $True) {
Remove-Item $ProcessedVM_Text;
};
$AllVM | Out-File $AllVM_Text;
New-Item $ProcessedVM_Text -ItemType File | out-null;
foreach ($VM in $AllVM) {
$Done = 0
$ProcessedVM = @();
$ProcessedVM = Get-Content $ProcessedVM_Text;
foreach ($VMed in $ProcessedVM) {
if ($VMed -eq $VM) {
$Done = 1;
};
};
if ($Done -eq 0) {
write-host "";
Write-Host "Check Excluded VMs and Add Back to Job";
write-host "";
$ExcludeObjs = $Job.GetObjectsInJob() | where {$_.Type -eq "Exclude"};
Add-VBRHvJobObject -job $Job -Entities (Find-VBRHvEntity -Name $ExcludeObjs.Name) | out-null;
$ExcludeObjs.Delete();
write-host "";
Write-Host "Exclude VMs other than $VM";
write-host "";
Remove-VBRJobObject -Objects ($Job.GetObjectsInJob() | where {$_.Name -ne $VM});
# Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File 'Password.txt'
$Password = Get-Content 'Password.txt' | ConvertTo-SecureString
$Cred = new-object -TypeName System.Management.Automation.PSCredential -argumentlist "Hyper-V-Host\Administrator", $Password
write-host "";
Write-Host "Suspend-VMReplication on VM: $VM";
write-host ""
Invoke-Command -ComputerName "Hyper-V-Host" -Authentication Negotiate -Credential $Cred {
$VM = $args[0];
Suspend-VMReplication -ComputerName "Hyper-V-Host" -VMName $VM -Confirm:$False
} -ArgumentList $VM;
write-host "";
Write-Host "Start Backup Job on VM: $VM";
write-host "";
Start-VBRJob -Job $Job
# Mark VM as Backuped
Add-Content $ProcessedVM_Text $VM
write-host "";
Write-Host "Resume-VMReplication on VM: $VM";
write-host "";
Invoke-Command -ComputerName "Hyper-V-Host" -Authentication Negotiate -Credential $Cred {
$VM = $args[0];
Resume-VMReplication -ComputerName "Hyper-V-Host" -VMName $VM -Confirm:$False
} -ArgumentList $VM;
write-host "";
Write-Host "Add Excluded VMs Back to Job";
write-host "";
$ExcludeObjs = $Job.GetObjectsInJob() | where {$_.Type -eq "Exclude"};
Add-VBRHvJobObject -job $Job -Entities (Find-VBRHvEntity -Name $ExcludeObjs.Name) | out-null;
$ExcludeObjs.Delete();
};
};
Remove-Item $AllVM_Text
Remove-Item $ProcessedVM_Text
write-host "";
Write-Host "ackup Job Finished";
write-host ""
Stop-Transcript
exit;
沒有留言:
張貼留言