Haikos Blog Blog von Haiko Hertes zu allen Themen rund um Microsoft und Datacenter

22Nov/170

Hyper-V: Welcher Host ist am besten für eine neue VM geeignet?

Mir stellt sich im Administrations-Alltag immer wieder die Frage, welcher unserer Hyper-V-Hosts derzeit am besten für eine neue VM geeignet ist (Nein, wir verwenden leider kein VMM…). Anstatt aber dabei jedes Mal jeden Host hinsichtlich seiner freien Ressourcen “abzuklappern”, habe ich mir ein entsprechendes PowerShell-Skript geschrieben, was eine passende Function bereithält. Ihr könnt das Skript gerne für eure Zwecke anpassen oder direkt so übernehmen.

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
$AllHyperVHosts = "HostNr1","HostNr2","HostNr3"
 
function Get-HyperVHostInfo([string]$HyperVHost)
{
 
    $vCores = ((Get-VM -ComputerName $HyperVHost).ProcessorCount | Measure-Object -Sum).Sum
 
    $Property = "numberOfCores", "NumberOfLogicalProcessors"
    $CPUs = Get-Ciminstance -class Win32_Processor -Property  $Property -ComputerName $HyperVHost| Select-Object -Property $Property 
    $Cores = ($CPUs.numberOfCores | Measure-Object -Sum).Sum
    $logCores = ($CPUs.NumberOfLogicalProcessors | Measure-Object -Sum).Sum
 
    $os = Get-Ciminstance Win32_OperatingSystem -ComputerName $HyperVHost
    $MemFreePct = [math]::Round(($os.FreePhysicalMemory/$os.TotalVisibleMemorySize)*100,2)
 
    $object = New-Object -TypeName PSObject
    $object | Add-Member –MemberType NoteProperty –Name PhysicalCores –Value $Cores
    $object | Add-Member –MemberType NoteProperty –Name LogicalCores –Value $logCores
    $object | Add-Member –MemberType NoteProperty –Name VirtualCores –Value $vCores
    $object | Add-Member –MemberType NoteProperty –Name MemTotalGB -Value ([int]($os.TotalVisibleMemorySize/1mb))
    $object | Add-Member –MemberType NoteProperty –Name MemFreeGB -Value ([math]::Round($os.FreePhysicalMemory/1mb,2))
    $object | Add-Member –MemberType NoteProperty –Name MemFreePct -Value $MemFreePct
 
    Return $object
}
 
ForEach($OneHost in $AllHyperVHosts)
{
    $HostData = Get-HyperVHostInfo -HyperVHost $OneHost
 
    Write-Host "$OneHost has $($Hostdata.PhysicalCores) physical cores, $($Hostdata.LogicalCores) logical cores and $($Hostdata.VirtualCores) virtual cores are used in all VMs overall." -ForegroundColor Yellow
    Write-Host "The Core:vCore ratio is `t`t1:$([math]::Round(($Hostdata.VirtualCores) /  ($Hostdata.PhysicalCores),2))"
    Write-Host "The Log.Core:vCore ratio is `t1:$([math]::Round(($Hostdata.VirtualCores) /  ($Hostdata.LogicalCores),2))"
    Write-Host "The system has $($Hostdata.MemFreeGB)GB of free memory and $($Hostdata.MemTotalGB)GB memory at all, which is $($Hostdata.MemFreePct)% free"
    Write-Host ""
 
}
Write-Host "The conservative approach for logical cores is `t1:8 "

 

Eine Beispielausgabe sieht dann so aus:

hyperv1

22Mrz/170

PowerShell – RAM-Konfiguration eines Systems auslesen

Bei der Frage, ob ein Server (oder auch Client) noch etwas mehr RAM vertragen kann, stellt sich oft die Frage, wieviel RAM dann aktuell in wie vielen Modulen verbaut ist und wieviele Slots noch frei sind. Natürlich gibt es dazu auch bereits grafische Werkzeuge, die das können, aber spätestens, wenn mehrere Maschinen (ggf. auch Core-Server ohne GUI) abgefragt werden sollen, kann die PowerShell ihre Stärken ausspielen. Daher habe ich ein kleines Skript gebaut, welches diese Aufgabe erfüllt:

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
[Cmdletbinding()]
Param(
    [string]$Computername = "localhost"
)
cls
$PysicalMemory = Get-WmiObject -class "win32_physicalmemory" -namespace "root\CIMV2" -ComputerName $Computername
 
Write-Host "Memory Modules:" -ForegroundColor Green
$PysicalMemory | Format-Table Tag,BankLabel,@{n="Capacity(GB)";e={$_.Capacity/1GB}},Manufacturer,PartNumber,Speed -AutoSize
 
Write-Host "Total Memory:" -ForegroundColor Green
Write-Host "$((($PysicalMemory).Capacity | Measure-Object -Sum).Sum/1GB)GB"
 
$TotalSlots = ((Get-WmiObject -Class "win32_PhysicalMemoryArray" -namespace "root\CIMV2" -ComputerName $Computername).MemoryDevices | Measure-Object -Sum).Sum
Write-Host "`nTotal Memory Slots:" -ForegroundColor Green
Write-Host $TotalSlots
 
$UsedSlots = (($PysicalMemory) | Measure-Object).Count 
Write-Host "`nUsed Memory Slots:" -ForegroundColor Green
Write-Host $UsedSlots
 
If($UsedSlots -eq $TotalSlots)
{
    Write-Host "All memory slots are filled up, none is empty!" -ForegroundColor Yellow
}

Die Ausgabe sieht dann etwa so aus:

PS_Memory1

Auf meinem Notebook mit nur zwei RAM-Slots (beide belegt) kommt zusätzlich noch eine kleine “Warnung”:

PS_Memory2

Ihr könnt das Skript auch hier herunterladen:

https://gallery.technet.microsoft.com/scriptcenter/Get-Memory-RAM-configuratio-35dda12e

8Jan/150

Hyper-V Server: Tatsächlichen freien Speicher der VMs auswerten

Wenn man in einer Hyper-V VM einen Blick auf den belegten bzw. freien RAM wirft, dann wird man häufig feststellen, dass nicht mehr viel übrig ist – und zwar dann, wenn man “Dynamic Memory”, den “Dynamischen Arbeitsspeicher” aktiviert hat. Dieser sorgt dafür, dass eine VM die Menge an Arbeitsspeicher bekommt, die sie aktuell benötigt – zumindest, solange noch Speicher frei ist und sich die VM in den vom Admin gesteckten Grenzen bewegt. So kann man seit dem Windows Server 2012 bzw. seit Hyper-V 3.0 drei verschiedene Werte konfigurieren:

DynMem0

Es lässt sich neben dem Startwert (Wieviel RAM bekommt die VM, wenn sie eingeschaltet wird?) weiterhin festlegen, wieviel die VM mindestens haben muss (Sie kann nie weniger haben, als hier festgelegt ist) und welche Menge ihr maximal zur Verfügung stehen könnte (Vorausgesetzt, es ist genügend RAM vorhanden; hier lässt sich auch ein Wert festlegen, der über dem insgesamt vorhandenen RAM liegt).

Bei Bedarf kann der “Minimale RAM” auch unter dem “Startwert” liegen – dies ist vor allem dann sinnvoll, wenn die VM während des Starts und der Anfangszeit nach dem Boot viel Speicher benötigt, um z.B. Dienste und Anwendungen zu starten, dann im Alltagsbetrieb aber mit weniger auskommt.

Nehmen wir nun an, eine VM hat folgende Konfiguration:

  • Start: 2GB
  • Min: 512MB
  • Max: 3GB

Nun wird sie also beim Einschalten zunächst 2GB bekommen, nach dem erfolgreichen Start ihres Betriebssystems den tatsächlichen RAM-Bedarf an Hyper-V melden und Hyper-V weist der VM dann diesen Bedarf plus einen Sicherheitsaufschlag (den “Arbeitsspeicherpuffer”) zu. Dieser ist nötig, damit die VM nicht jedes weitere benötigte Megabyte speicher einzeln anfordern muss, sondern dies immer “paketweise” tun kann.

Benötigt die VM nun mehr, dann bekommt sie mehr – solange, bis entweder das Maximum der VM-Konfiguration erreicht oder der RAM des Host-Systems voll ist. Einem System im laufenden Betrieb mehr RAM zuzuweisen ist nicht so kompliziert und ging bereits lange vor dem Virtualisierungszeitalter (ja, da musste man dann noch echte Speicherriegel in den Server stecken!).

Spannender wird der Vorgang, einer VM Speicher wegzunehmen, z.B. wenn sie eben nach dem Starten weniger Speicher benötigt, als im Startwert festgelegt. Wirklich Speicher “wegnehmen” kann man nicht. Dies wird durch eine Technik namens “Balooning” gelöst. Wenn der VM nun z.B. 512MB RAM weggenommen werden sollen, dann wird stattdessen in der VM (bzw. in deren Speicherbereich) eine “Ballon aufgeblasen”, der diese 512MB RAM belegt – die VM glaubt also, der Speicher wäre weiterhin vorhanden, aber aktuell belegt. Der Hypervisor “weiss” nun, dass er diesen RAM anderweitig vergeben kann, da er ja nicht wirklich belegt ist. Soll die VM wieder mehr Speicher bekommen, wird der Ballon stückweise kleiner gemacht, bis er verschwindet.

DynMem1

(In der Abbildung sehen wir eine VM, die nach dem Start, der mit 2GB RAM durchgeführt wurde,
nur noch 661MB benötigt und inkl. Aufschlag 788MB RAM zugewiesen bekommen hat)

Soweit die Technik, die in der Praxis sehr gut funktioniert. Jedoch hat sie einen Haken: Die VM im obigen Beispiel, welche nach dem erfolgreichen Start einen RAM-Bedarf von bspw. 661MB an Hyper-V meldet und 20% “Aufschlag” bekommt, soll nun 788MB RAM zugewiesen bekommen (Also 1260MB weniger als beim Start). In der Realisierung sieht sie weiterhin ihre 2GB – davon aber einmal die 1260MB Differenz (den “Ballon”) plus den tatsächlichen RAM-Bedarf (also 661MB) belegt. In der Konsequenz sind als (z.B. im TaskManager) 1921MB (1,87GB) belegt – von 2048MB insgesamt – also nur noch ca. 6% frei!

DynMem2 Der Taskmanager innerhalb der VM zeigt etwa zur selben Zeit, zu der der vorherige Screenshot erzeugt wurde, einen RAM-Verbrauch von 1,8GB und freien Speicher in Höhe von 204MB. Das hier etwas mehr RAM frei ist als bei der Rechnung oben liegt daran, dass die VM etwas mehr Speicherbedarf an Hyper-V meldet als tatsächlich bereits belegt sind.

Eine entsprechende Serverüberwachung, die es nicht besser weiss, meldet nun also, dass der RAM zu Neige geht. Das Fatale dabei ist aber, dass wenn man dieser VM z.B. einen größeren Startwert gibt, bspw. 3GB, dann wird die Rechnung noch schlimmer:

  • 3072MB beim Start
  • Nach dem Start 661MB belegt, 788MB zugewiesen
  • Ballon iHv 2284MB
  • Als belegt zu sehender Speicher: 2945MB (Ballon + 661MB tatsächlicher Bedarf)
  • Übrig bleiben dann 127MB (Der Puffer) – was hier nur noch etwa 4% (statt 6% bei 2GB Start-RAM) entspricht!

Dies geschieht, obwohl die VM augenscheinlich mehr RAM hat (oder zumindest haben KÖNNTE) und immer noch den selben Bedarf (von 661MB) hat! Hier darf man sich also nicht täuschen lassen.

Als Lösung könnte man den RAM-Verbrauch der VMs mittels PowerShell analysieren und dann bspw. bei Unterschreitung eines Schwellwertes bzgl. des freien RAMs alamieren. Ein solcher Aufruf, der den freien RAM aller VMs in Prozenten zeigt, könnte dabei so aussehen:

DynMem3

Zum Kopieren:

1
2
3
4
5
6
Get-VM | Where DynamicMemoryEnabled | Where State -eq "Running"
    Format-Table Name,
                 @{n='Benötigt(GB)';e={$_.MemoryDemand/1GB};FormatString='N3'},
                 @{n='Zugewiesen(GB)';e={$_.MemoryAssigned/1GB};FormatString='N3'},
                 @{n='Frei/Aktuell (%)';e={100-($_.MemoryDemand/$_.MemoryAssigned*100)};FormatString='N2'},
                 @{n='Frei/Max (%)';e={100-($_.MemoryDemand/$_.MemoryMaximum*100)};FormatString='N2'} -AutoSize

Die Spalte “Frei/Aktuell” liefert einen Wert, wieviel Speicher bezogen auf den aktuell zugewiesenen Wert frei ist (dieser Wert sollte sich in etwa in der Größe des Speicherpuffers bewegen, solange genügend RAM verfügbar ist und die VM mehr RAM als das Minimum benötigt).

Die letzte Spalte “Frei/Max” zeigt, wieviel Speicher bezogen auf den maximal möglichen RAM der VM noch frei ist. Erst wenn dieser Wert zu niedrig wird (bspw. unter 20% fällt) besteht Bedarf, der VM mehr RAM zuzuweisen.

Insgesamt sehen dann die Werte in der PowerShell, dem Taskmanager der VM und dem Hyper-V Manager so aus:

DynMem4 (Anklicken zum Vergrößern)