When should you use Storage Pools for your Windows VM in Azure?
If you are creating a SQL Sever failover cluster instance (FCI) in Azure, you can use Storage Spaces Direct (S2D) and configure Storage Pools to set-up the Cluster Storage.
The other main reason for using Storage Pools in Azure is Performance, which is what we are going to talk about in this blog.
When you are configuring storage for SQL Server VMs you should always consider the below:
Now, each Premium SSD disk in Azure provides different performance depending on its size. This is measured in IOPS (I/O operations per second) or throughput (MBs per second):
SSD size | Disk size in GiB | Provisioned IOPS | Provisioned Throughput |
P1 | 4 | 120 | 25 MB/sec |
P2 | 8 | 120 | 25 MB/sec |
P3 | 16 | 120 | 25 MB/sec |
P4 | 32 | 120 | 25 MB/sec |
P6 | 64 | 240 | 50 MB/sec |
P10 | 128 | 500 | 100 MB/sec |
P15 | 256 | 1100 | 125 MB/sec |
P20 | 512 | 2300 | 150 MB/sec |
P30 | 1024 | 5000 | 200 MB/sec |
P40 | 2048 | 7500 | 250 MB/sec |
P50 | 4096 | 7500 | 250 MB/sec |
P60 | 8192 | 16000 | 500 MB/sec |
P70 | 16384 | 18000 | 750 MB/sec |
P80 | 32767 | 20000 | 900 MB/sec |
So if you are planning to create a 4TB disk for your data files you could instead create a Storage Pool with 4 P30 disks and get the disks' combined performance:
As you can see from the above example, you can achieve optimal performance having a Storage Pool with multiple disks rather than a single large disk. The gain could be significant depending on the size and number of disks in your pool.
A few gotchas and considerations to keep in mind when using Storage Pools in Azure:
Let’s say you are building a new SQL Server High Availability Group in Azure. You should configure the Storage Pools locally on each node before adding the servers into the Windows Server Failover Cluster (I've explained why later).
### CREATE STORAGE STORAGE POOL $StripeSize = 65536 $allocationUnit = 65536 [array]$PhysicalDisks = Get-StorageSubSystem -FriendlyName "Windows Storage*" | Get-PhysicalDisk -CanPool $True $DiskCount = $PhysicalDisks.count New-StoragePool -FriendlyName "SQLDATAPOOL" -StorageSubsystemFriendlyName "Windows Storage*" -PhysicalDisks $PhysicalDisks | New-VirtualDisk -FriendlyName "SQLDATA01" -Interleave $StripeSize -NumberOfColumns $DiskCount -ResiliencySettingName simple –UseMaximumSize |Initialize-Disk -PartitionStyle GPT -PassThru | New-Partition -DriveLetter "G" -UseMaximumSize | Format-Volume -FileSystem NTFS -NewFileSystemLabel "SQLDATA01" -AllocationUnitSize $allocationUnit -Confirm:$false -UseLargeFRS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
### ADDING DISKS TO EXISTING STORAGE POOL [array] $PhysicalDisks = Get-StorageSubSystem -FriendlyName "Windows Storage*" | Get-PhysicalDisk -CanPool $True Add-PhysicalDisk -StoragePoolFriendlyName "SQLDATAPOOL" -PhysicalDisks $PhysicalDisks | Initialize-Disk -PartitionStyle GPT -PassThru Get-VirtualDisk "SQLDATA01" | Resize-VirtualDisk -Size (4000GB) #Choose virtual disk $VirtualDisk = Get-VirtualDisk "SQLDATA01" #Get its partition $Partition = $VirtualDisk | Get-Disk | Get-Partition | Where PartitionNumber -Eq 2 #Resize the Partition to its maximum size $Partition | Resize-Partition -Size ( $Partition | Get-PartitionSupportedSize ).SizeMax |
Now, things get a little bit tricky if you want to create Storage Pools on an existing Cluster. This is because the Cluster automatically discovers and take ownership of any new physical disks attached to a VM and the disks will be in the “Clustered Windows Storage*” storage sub system.
The other problem is that, whereas you can have local Storage Pools with a single disk, the minimum number of disks allowed for Cluster Storage Pools is 3 due to striping and parity requirements. This means that every time you expand the storage pool you must add 3 disks at the time.
Again, you should always configure local storage pools before the cluster is created, but let's assume that you were not aware of this and you now need to use Storage Pools due to performance requirements. There is a workaround:
1
2
3
4
5
6
7
8
9
10
|
### NEW STORAGE POOL $StripeSize = 65536 $allocationUnit = 65536 [array] $PhysicalDisks = Get-StorageSubSystem -FriendlyName "Clustered*" | Get-PhysicalDisk -CanPool $True $DiskCount = $PhysicalDisks .count New-StoragePool -FriendlyName "SQLDATAPOOL" -StorageSubsystemFriendlyName "Clustered*" -PhysicalDisks $PhysicalDisks | New-VirtualDisk -FriendlyName "SQLDATA01" -Interleave $StripeSize -NumberOfColumns $DiskCount -ResiliencySettingName simple –UseMaximumSize | Initialize-Disk -PartitionStyle GPT -PassThru | New-Partition -DriveLetter "G" -UseMaximumSize | Format-Volume -FileSystem NTFS -NewFileSystemLabel "SQLDATA01" -AllocationUnitSize $allocationUnit -Confirm : $false -UseLargeFRS |
Running the below script or checking the failover cluster manager you can see that there is now a Cluster Pool but is in the failed state:
1
2
3
4
5
|
### REMOVE CLUSTER STORAGE POOL $ClusterPoolName = Get -ClusterResource | Where-Object {$_.resourcetype -eq "Storage Pool" } | Select Name Remove -ClusterResource -Name $ClusterPoolName .Name |
1
2
3
|
### CREATE VIRTUAL DISK New-VirtualDisk -StoragePoolFriendlyName "SQLDATAPOOL" -FriendlyName "SQLDATA01" -Interleave $StripeSize -NumberOfColumns $DiskCount -ResiliencySettingName simple –UseMaximumSize | Initialize-Disk -PartitionStyle GPT -PassThru |
1
2
3
4
5
6
7
|
### REMOVE VIRTUAL DISK AND POOL FROM CLUSTER $ClusterPoolName = Get -ClusterResource | Where-Object {$_.resourcetype -eq "Storage Pool" } | Select Name $ClusterVirtualDisk = Get -ClusterResource | Where-Object {$_.resourcetype -eq "Physical Disk" } | Select Name Remove -ClusterResource -Name $ClusterVirtualDisk .Name Remove -ClusterResource -Name $ClusterPoolName .Name |
1
2
3
|
### ATTACH VIRTUAL DISK Connect-VirtualDisk -FriendlyName "SQLDATA01" |
1
2
3
4
5
|
### FORMAT VOLUME AND CREATE PARTITION $diskNumber = Get-Disk | Where-Object {$_.FriendlyName -eq "SQLDATA01" } New-Partition -DiskNumber $diskNumber .Number -DriveLetter "G" -UseMaximumSize | Format-Volume -FileSystem NTFS -NewFileSystemLabel "SQLDATA01" -AllocationUnitSize $allocationUnit -Confirm : $false -UseLargeFRS |
You can really enhance your disks' performance by a correct use of Storage Pools in Azure. Plan your storage structure head to make the most of the Azure offering and avoid any surprises in the future.