在心跳丢失的情况下重新启动Hyper-V VM

我有一个Windows Server 2012R2 hyper-v主机。 它正在运行一些虚拟机,包括一些Linux虚拟机。

我有一个正在偶尔发生的linux虚拟机,但是有时会在内核某处崩溃,导致虚拟机变得完全没有响应。

我知道hyper-v有一个“心跳”设施,它成功地检测到虚拟机崩溃为心跳丢失。
然而,我不知道如何设置hyper-v,以便它实际上对心跳信号任何事情。 显然有一点,如果心跳丢失超过1分钟,可以select重置虚拟机,但是它可能已经被移除,或者被放置在某个我找不到的地方。

我只有这一台服务器,所以做集群或故障切换这样的事情是不可行的(这是一个家庭实验室服务器)。


在任何人评论之前,是的,我正在试图追查虚拟机崩溃的原因,但这种不规范已经使得它很难。

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虚拟机而不是检查虚拟机。

我需要一个解决scheme来监视所有 Hyper-V虚拟机的心跳,并在虚拟机locking时自动执行硬重置。 你可能已经知道了。 看起来您可以在使用Hyper-V进行群集设置时执行此操作,但仅使用一台Hyper-V主机,但是如果没有一些自定义脚本,则无法执行此操作。

我发现一个很好的VBS监视所有系统的心跳,甚至在最新版本中有一个可configuration的重试次数和宽限期 。 原始的脚本和描述可以在这里find。 在系统启动的时候安排这个计划是个好主意(不要把它放在启动文件夹中,因为这需要Hyper-Vpipe理员在脚本开始运行之前login系统)。

用法: – 将VMHeartBeat.vbs脚本复制到您select的位置 – 双击脚本或打开命令提示符,切换到脚本被复制到的文件夹,然后运行cscript.exe VMHeartBeat.vbs

注意:如果双击脚本wscript.exe引擎或者使用默认的脚本引擎来运行脚本。 当您使用cscript.exe时,您需要始终打开命令窗口。

该脚本将在脚本的相同位置创build一个日志文件,并不断向其添加成功/失败事件。 日志文件的名称是VMHeartBeatEvents.log

这就对了。 你们都设置为检测虚拟机心跳丢失,然后执行硬重置。

要testing脚本是否正常工作,可以下载NotMyFault.exe ,然后将其复制到虚拟机。 现在,在Hyper-V主机上运行VMHearBeat.vbs,在虚拟机内部打开notmyfault.exe,select一个bug并点击“Do Bug”。 根据您select的错误types,虚拟机可能会出现蓝屏。 此时,VMHearBeat.vbs会检测到心跳损失,并执行虚拟机的硬重置。 如前所述,您可以检查日志文件,查看硬重置是否成功。

为了保留脚本,我也粘贴了最新版本的.VBS代码(带有重试计数和宽限期)。

更新:脚本的最新版本实际上有一些错误,所以下面的脚本已被修改,我确认它在Server 2012R2上工作。 \v2需要添加到行#20和10需要更改为VMHardReset函数的第4行上的11

 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