Configuring anti-affinity for Hyper-V virtual machines

If you have worked on VMware, you might already be aware of a feature called DRS rules. Using DRS rules, we can create VM anti-affinity rules so that no two virtual machines hosting similar application roles run on the same ESX host. For example, when you have a virtualized SQL mirror or a virtualized SQL failover cluster, it is critical to separate the SQL virtual machines participating in the application group onto different ESX hosts. This is where we can use VMware DRS rules – “Separate Virtual Machines” rule to be specific.

Now, how can we do this on a Hyper-V failover cluster?

Update: After I published this, I did further research around this topic and found that another PowerShell MVP Jan Egil Ring wrote a PowerShell module for setting anti-affinity classnames. Do check his work @ http://blog.powershell.no/2012/02/23/how-to-configure-antiaffinityclassnames-in-failover-clustering-using-windows-powershell/

Well, there is no direct and GUI-based method to do this. However, we can use something called anti-affinity class names to achieve this. The AntiAffinityClassNames is a property of cluster groups. As I’d mentioned, there is no GUI to configure this hence we need to use commandline – PowerShell, of course! :)

When a group is moved during failover, anti-affinity affects the algorithm used to determine the destination node as follows:

  • Using the preferred owner list of the group being moved, the Cluster service finds the next preferred node.
  • If the node is not hosting any group anti-affined with the group being moved, it is selected as the destination node.
  • If the next preferred available node is currently hosting a group anti-affined with the group being moved, the Cluster service moves to the next preferred available node in the preferred owner list.
  • If the only available nodes are hosting anti-affined groups, the Cluster service ignores anti-affinity and selects the next preferred available node as the destination node.

So, whether these anti-affinity rules are honored or not really depends on the above 4 conditions.

Now, let us see how we can create these rules. Consider an imaginary example of a SharePoint farm with two web frontends, two application servers, and two database servers. For obvious reasons, in a given set of clustered Hyper-V nodes, we never want the virtual machines hosting the similar SharePoint farm roles appear on the same Hyper-V node. We will create the AntiAffinityClassNames and assign them to the cluster groups.

You can get the values of AntiAffinityClassNames property by using the Get-ClusterGroup cmdlet in the Failover clusters PowerShell module.

Get-ClusterGroup | Select AntiAffinityClassNames

This won’t return anything if you don’t already have any value set for the given cluster groups.

To add the AntiAffinityClassNames property, we first need to define the names:

$wfeAntiAffinity = New-Object System.Collections.Specialized.StringCollection
$wfeAntiAffinity.Add("SharePoint WFE")

$appAntiAffinity = New-Object System.Collections.Specialized.StringCollection
$appAntiAffinity.Add("SharePoint APP")

$dbAntiAffinity = New-Object System.Collections.Specialized.StringCollection
$dbAntiAffinity.Add("SharePoint DB")

The AntiAffinityClassNames is of type “System.Collections.Specialized.StringCollection” and we cannot simply assign a string value to it. Now that we have the affinity class names defined, we can assign these to the cluster groups. Once again, we can use the Get-ClusterGroup cmdlet to update the value of this property for each virtual machine.

(Get-ClusterGroup -Name SP-WFE1).AntiAffinityClassNames = $wfeAntiAffinity
(Get-ClusterGroup -Name SP-WFE2).AntiAffinityClassNames = $wfeAntiAffinity
(Get-ClusterGroup -Name SP-APP1).AntiAffinityClassNames = $appAntiAffinity
(Get-ClusterGroup -Name SP-APP2).AntiAffinityClassNames = $appAntiAffinity
(Get-ClusterGroup -Name SP-SQL1).AntiAffinityClassNames = $dbAntiAffinity
(Get-ClusterGroup -Name SP-SQL2).AntiAffinityClassNames = $dbAntiAffinity

This is it. After this setting is complete, we can restart a Hyper-V host in the cluster to ensure the virtual machines follow the anti-affinity rules.

Make a note that any new setting on the property will override the old values. So, if you need to add a VM to another set of class names, you need to add all the values to StringCollection (using the Add() method) and then re-set the value for the cluster group. For example,

$appAntiAffinity = New-Object System.Collections.Specialized.StringCollection
$appAntiAffinity.Add("SharePoint APP")
$appAntiAffinity.Add("SharePoint Search")

Hope this helps!