![心跳丢失时重启 Hyper-V VM](https://linux22.com/image/644051/%E5%BF%83%E8%B7%B3%E4%B8%A2%E5%A4%B1%E6%97%B6%E9%87%8D%E5%90%AF%20Hyper-V%20VM.png)
我有一台 Windows Server 2012R2 hyper-v 主机。它运行着许多虚拟机,包括一些 Linux 虚拟机。
我有一个 Linux VM,它偶尔会在内核的某个地方崩溃,但有点规律,导致 VM 完全没有响应。
我知道 hyper-v 有一个“心跳”功能,它成功地将虚拟机崩溃检测为心跳丢失。
然而,我不知道如何设置 hyper-v,以便它实际上做任何有心跳信号的东西。显然在某一时刻,有如果心跳丢失超过 1 分钟,则可以重置 VM,但它已被删除,或放在我无法找到的地方。
我只有这台服务器,因此执行集群或故障转移之类的操作实际上不可行(这是一个家庭实验室服务器)。
在任何人发表评论之前,是的,我正在尝试找出虚拟机崩溃的原因,但它的不规则性使事情变得困难。
答案1
powershell 是你的救星:
$VM = Get-VMIntegrationService -VMName test-vm -Name Heartbeat
if ($VM.PrimaryStatusDescription -ne "OK")
{
write-host "VM Dead ? restarting ..."
Stop-VM test-vm -Force -TurnOff
Start-VM test-vm
}
只需将其添加到任务计划程序即可。
如果您的虚拟机不支持心跳,则修改它以 ping 虚拟机而不是检查 HB。
答案2
我需要一个解决方案来监测全部Hyper-V 虚拟机,并在 VM 锁定时自动执行硬重置。您可能已经知道。似乎您可以在拥有群集设置时使用 Hyper-V 执行此操作,但如果只有一台 Hyper-V 主机,则如果没有一些自定义脚本,这是不可能的。
我发现了一个不错的 VBS,它可以监控所有系统的心跳,甚至还有一个可配置重试次数和宽限期在里面最新版本. 原始脚本和描述可以在这里找到这里。将其安排在系统启动时运行是一个好主意(不要只将其放在启动文件夹中,因为这需要 Hyper-V 管理员在脚本开始运行之前登录系统)。
使用方法: - 将 VMHeartBeat.vbs 脚本复制到您选择的位置 - 双击脚本或打开命令提示符,更改为复制脚本的文件夹,然后运行 cscript.exe VMHeartBeat.vbs
注意:如果您双击脚本 wscript.exe,则将使用您的默认脚本引擎或任何其他引擎来运行该脚本。当您使用 cscript.exe 时,您需要始终保持命令窗口打开。
此脚本将在与脚本相同的位置创建一个日志文件,并不断将成功/失败事件附加到其中。日志文件名为 VMHeartBeatEvents.log
就是这样。您已准备好检测 VM 心跳丢失,然后执行硬重置。
要测试脚本是否正常工作,您可以下载 错误修复工具然后将其复制到虚拟机。现在,只需在 Hyper-V 主机上运行 VMHearBeat.vbs 并在虚拟机内打开 notmyfault.exe,选择一个错误并单击“执行错误”。根据您选择的错误类型,虚拟机可能会出现蓝屏。此时,VMHearBeat.vbs 会检测到心跳丢失并对虚拟机执行硬重置。您可以检查前面提到的日志文件,看看硬重置是否成功。
为了保存脚本,我还在下面粘贴了最新版本的 .VBS 代码(带有重试次数和宽限期)。
更新:该脚本的最新版本实际上存在一些错误,因此下面的脚本已被修改,并且我确认它可以在 Server 2012R2 上运行。\v2
需要添加到第 20 行,并且10
需要更改为函数11
的第 4 行VMHardReset
。
Option Explicit
'Define Event log constants here
Const EVENT_INFO = 4
Const EVENT_ERROR = 1
Const RETRY_COUNT = 3
Const CHECK_EVERY_X_SECS = 6
Dim objSummaryInfo, objWMIService, objVMService, intValArray, objVMitems
Dim InParam, OutParam, objItem, strQuery
Dim Job, objShell
Dim colArgs, strLog, dict, compName
Set colArgs = WScript.Arguments.Named
'Get Command Line arguments in to some variables
strLog = colArgs.Item("log")
Set objShell = Wscript.CreateObject("Wscript.Shell")
Set objWMIService = GetObject("winmgmts:\\" & "." & "\root\virtualization\v2")
Set objVMService = objWMIService.ExecQuery("SELECT * FROM Msvm_VirtualSystemManagementService").ItemIndex(0)
intValArray = Array(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199)
Set dict = CreateObject("Scripting.Dictionary")
While (1)
Wscript.echo(CStr(Now()) +": Testing Loop ")
objVMItems = objVMService.GetSummaryInformation(NULL,intValArray,objSummaryInfo)
for each objItem in objSummaryInfo
compName = objItem.ElementName
if (not dict.Exists(compName)) then
dict.add compName,0
end if
If (objItem.EnabledState=2 AND (objItem.HeartBeat = 6 OR objItem.HeartBeat = 13)) Then
dict.Item(compName)=dict.Item(compName)+1
WriteLog(" **"+compName+"** missed heartbeat check; count "+CStr(dict.Item(compName)))
if (dict.Item(compName) >= RETRY_COUNT ) then
dict.Item(compName)= 0
Wscript.echo(CStr(Now()) +": Now performing a hard reset on "+compName)
VMHardReset(compName)
end if
Else
dict.Item(compName)= 0
End If
Next
Set objVMItems=Nothing
Set objItem = Nothing
Set objSummaryInfo = Nothing
Wscript.Sleep CHECK_EVERY_X_SECS * 1000
Wend
Set objWMIService = Nothing
Set objVMService = Nothing
Set InValArray = Nothing
Function VMHardReset(vmElementName)
Dim objvm, strLine
Set objvm = GetComputerSystem(vmElementName)
Set InParam = objvm.Methods_("RequestStateChange").InParameters.SpawnInstance_()
InParam.RequestedState=11
Set OutParam = objvm.ExecMethod_("RequestStateChange",InParam)
If (TrackJob(OutParam)) Then
strLine = "Virtual Machine: " & vmElementName & " has been successfully recovered from a hearbeat failure"
'Write Success Event to text log
WriteLog(strLine)
Set strLine=Nothing
'Write a Windows Event Log
objShell.LogEvent EVENT_INFO, strLine
Else
strLine = "Virtual Machine: " & vmElementName & " could not be recovered from a hearbeat failure"
'Write Failure Event to text log
WriteLog(strLine)
Set strLine=Nothing
'Write a Windows Event Log
objShell.LogEvent EVENT_ERROR, strLine
End If
Wscript.echo(CStr(Now()) +": "+strLine)
Set InParam = nothing
Set objvm = nothing
Set vmElementName = Nothing
End Function
Function GetComputerSystem(vmElementName)
strQuery = "select * from Msvm_ComputerSystem where ElementName = '" & vmElementName & "'"
set GetComputerSystem = objWMIService.ExecQuery(strQuery).ItemIndex(0)
'Set GetComputerSystem = Nothing
Set strQuery = Nothing
End Function
Function TrackJob(OutParam)
Dim Job
If (OutParam.ReturnValue = 0) Then
TrackJob=True
ElseIf (OutParam.ReturnValue <> 4096) Then
TrackJob=False
Else
Set Job = objWMIService.Get(OutParam.Job)
While (Job.JobState = 3) or (Job.JobState = 4)
Set Job = objWMIService.Get(OutParam.Job)
Wend
If (Job.JobState <> 7) Then
TrackJob=False
Else
TrackJob = True
End If
End If
Set OutParam = Nothing
Set Job = Nothing
End Function
Sub WriteLog(line)
Dim objFileStream, objFileSystem
Set objFileSystem = CreateObject("Scripting.FileSystemObject")
Set objFileStream = objFileSystem.OpenTextFile("VMHeartBeatEvents.log", 8, true, -1)
objfileStream.WriteLine CStr(Now()) +": "+line
objfileStream.Close
Set objFileSystem = Nothing
End Sub