Reservations of VMs per ESXi host.

To paraphrase 1998s The Waterboy (best sports film of all time)..
Reservations are the devil.

The more you deep dive into reservations and resource pools the more you don’t want to touch them.

I wont go into great detail about the dangers as vFrankEric Sloof and Duncan Epping (to name but a few) have been telling us for years.

Basically unless you REALLY know what you are doing and you have a REALLY good reason to use them… Don’t.

However, back in the real world reservations are still being demanded by some vendors. Most notably anything to do with VOIP. Which is understandable as you don’t want these guys fighting for resources. I will say though, some of the numbers they ask for can be eye watering.

One problem with reservations is that it can be quite difficult to determine how much non reserved CPU MHz is actually left on a single host. vCenter will show you for the cluster but it doesn’t dive down to each host.

So you can have a scenario where you have a host with 10 VMs. 5 of them have reservations for half the CPU between them and the rest have none.

Although do remember when the reservation VMs are doing nothing the CPU scheduler will allow the other VMs to use those cycles.

But.. what happens when the host gets busy. This is when things get tricky. If the reservation VMs are using 50% of the CPU then the other 5 hosts have to fight for the rest. If the reservations set are not high enough, the reservation VMs will ask for additional resources as well. Then you have to factor in hypervisor overhead for things like VSAN, iSCSI etc the list goes on.

What is worse using DRS for VOIP VMs can be a no no or the host itself may not even be licensed for it. So you end up in a scenario where your host is congested, VMs are working poorly and you dont really know where you stand. Not ideal at 3am.

So, what can you do to see how much actual free cycles are on each host?

PowerCLI of course

Here is some code I threw together to help me report on this to help me make smarter VM migrations.

# Display reservation for a host in each cluster
# Chris McChesney
# Use at your own risk, code provided as is

$vmCluster = "Cluster1" #Insert your ClusterName here
Get-VM | Where-Object { $_.ExtensionData.ResourceConfig.CpuAllocation.Reservation -ne "0" }
ForEach ($VM in $VMs)
{
	$vmClusters = Get-Cluster | Sort-Object Name
	ForEach ($vmCluster in $vmClusters)
	{
		Write-Host $vmCluster -ForegroundColor Green
		$returnObj = @()
		ForEach ($vmHost in $vmCluster | Get-VMHost | Sort-Object Name)
		{
			$VMs = Get-VMHost -Name $vmHost | Get-VM | Where-Object { $_.ExtensionData.ResourceConfig.CpuAllocation.Reservation -ne "0" }
			$CPUTotal = 0
			ForEach ($VM in $VMs)
			{
				$VM |
				Select-Object @{ N = "Name"; E = { $VM.Name } },
							  @{ N = "CPU Reservation"; E = { $VM.ExtensionData.ResourceConfig.CpuAllocation.Reservation } },
							  @{ N = "Memory Reservation"; E = { $VM.ExtensionData.ResourceConfig.MemoryAllocation.Reservation } }, @{ N = "Host"; E = { $VM.VMHost.Name } }
				$VMReservation = $VM | Select-Object @{ N = "CPUReservation"; E = { $VM.ExtensionData.ResourceConfig.CpuAllocation.Reservation } }
				
				
				$CPUTotal += $VMReservation.CPUReservation
			}
			$vmHostCPU = $vmHost.CpuTotalMhz
			$vmHostCPUUsed = $vmHost.CpuUsageMhz
			$CPUNotReserved = $vmHostCPU - $CPUTotal
			$hostResPcent = [math]::Round(($CPUTotal / $vmHostCPU) * 100)
			$obj = New-Object psobject -Property @{ "Host" = $vmHost;
				"ReservationTotal" = $vmHostCPU;
				"Used"			   = $vmHostCPUUsed;
				"Reserved"		   = $CPUTotal;
				"PcentReserved"    = $hostResPcent;
				"NotReservedFree"  = $CPUNotReserved
			}
			$returnObj += $obj | Select-Object Host, ReservationTotal, Used, Reserved, PcentReserved, NotReservedFree
		}
		$returnObj | Select-Object -Property Host, @{ name = "Host Mhz"; expression = { $($_.ReservationTotal) } }, @{ name = "VM Reserved Mhz"; expression = { $($_.Reserved) } }, @{ name = "Host Reserved %"; expression = { $($_.PcentReserved) } }, @{ name = "Current Used Mhz"; expression = { $($_.Used) } }, @{ name = "Non Reserved Mhz"; expression = { $($_.NotReservedFree) } } | Format-Table
	}
}

Originally posted by me at my good friend Tim Durfee’s blog at https://www.virtuallytrivial.com/index.php/2019/11/18/reservations-of-vms-per-host/