Delimitación de la asignación de volúmenes en Espacios de almacenamiento directo

Se aplica a: Windows Server 2022, Windows Server 2019

Windows Server 2019 presenta una opción para delimitar manualmente la asignación de volúmenes en Espacios de almacenamiento directo. Si lo hace, puede aumentar significativamente la tolerancia a errores en determinadas condiciones, pero impone algunas consideraciones de administración y complejidad agregadas. En este tema se explica cómo funciona y se proporcionan ejemplos en PowerShell.

Importante

Esta característica es nueva en Windows Server 2019. No está disponible en Windows Server 2016.

Requisitos previos

Green checkmark icon. Considere usar esta opción si:

  • El clúster tiene seis o más servidores; y
  • El clúster solo usa resistencia de reflejo triple

Red X icon. No use esta opción si:

Descripción

Revisión: asignación regular

Con el reflejo triple normal, el volumen se divide en muchos "bloques" pequeños que se copian tres veces y se distribuyen uniformemente por todas las unidades de todos los servidores del clúster. Para más información, lea este blog de profundización.

Diagram showing the volume being divided into three stacks of slabs and distributed evenly across every server.

Esta asignación predeterminada maximiza las lecturas y escrituras en paralelo, lo que conduce a un mejor rendimiento, y es atractiva por su simplicidad: todos los servidores están igualmente ocupados, todas las unidades están igualmente llenas y todos los volúmenes permanecen en línea o se desconectan a la vez. Se garantiza que cada volumen sobreviva a dos errores simultáneos, como se muestra en estos ejemplos.

Sin embargo, con esta asignación, los volúmenes no pueden sobrevivir a tres errores simultáneos. Si tres servidores fallan a la vez, o si las unidades de tres servidores fallan a la vez, los volúmenes se vuelven inaccesibles porque al menos algunos bloques se asignaron (con una probabilidad muy alta) a las tres unidades o servidores exactos que fallaron.

En el ejemplo siguiente, los servidores 1, 3 y 5 producen un error al mismo tiempo. Aunque muchos bloques tienen copias que sobreviven, algunos no las tienen:

Diagram showing three of six servers highlighted in red, and the overall volume is red.

El volumen se queda sin conexión y deja de estar accesible hasta que se recuperan los servidores.

Nuevo: asignación delimitada

Con la asignación delimitada, se especifica un subconjunto de servidores que se van a usar (cuatro como mínimo). El volumen se divide en bloques que se copian tres veces, como antes, pero en lugar de asignarse a todos los servidores, los bloques se asignan solo al subconjunto de servidores que especifique.

Por ejemplo, si tiene un clúster de 8 nodos (nodos del 1 al 8), puede especificar un volumen que solo se ubicará en los discos de los nodos 1, 2, 3, 4.

Ventajas

Con la asignación de ejemplo, es probable que el volumen sobreviva a tres errores simultáneos. Si los nodos 1, 2 y 6 bajan, solo 2 de los nodos que contienen las 3 copias de datos del volumen están inactivos y el volumen permanece en línea.

La probabilidad de supervivencia depende del número de servidores y otros factores: consulte Análisis para más información.

Inconvenientes

La asignación delimitada impone algunas consideraciones de administración y complejidad agregadas:

  1. El administrador es responsable de delimitar la asignación de cada volumen para equilibrar la utilización del almacenamiento entre los servidores y mantener una alta probabilidad de supervivencia, tal y como se describe en la sección Procedimientos recomendados.

  2. Con la asignación delimitada, reserve el equivalente de una unidad de capacidad por servidor (sin máximo). Esto es más que la recomendación publicada para la asignación regular, que tiene un máximo de cuatro unidades de capacidad en total.

  3. Si un servidor falla y necesita ser reemplazado, tal y como se describe en Retirar un servidor y sus unidades, el administrador es responsable de actualizar la delimitación de los volúmenes afectados añadiendo el nuevo servidor y retirando el que ha fallado (ejemplo a continuación).

Uso en PowerShell

Puede usar el cmdlet New-Volume para crear volúmenes en Espacios de almacenamiento directo.

Por ejemplo, para crear un volumen de reflejo triple normal:

New-Volume -FriendlyName "MyRegularVolume" -Size 100GB

Crear un volumen y delimitar su asignación

Para crear un volumen de reflejo triple y delimitar su asignación:

  1. En primer lugar, asigne los servidores del clúster a la variable $Servers:

    $Servers = Get-StorageFaultDomain -Type StorageScaleUnit | Sort FriendlyName
    

    Sugerencia

    En Espacios de almacenamiento directo, el término "Unidad de escalado de almacenamiento" se refiere a todo el almacenamiento en bruto conectado a un servidor, incluidas las unidades conectadas directamente y los contenedores externos con unidades conectados directamente. En este contexto, es lo mismo que "servidor".

  2. Especifique qué servidores usar con el nuevo parámetro -StorageFaultDomainsToUse y mediante la indexación en $Servers. Por ejemplo, para delimitar la asignación a los servidores primero, segundo, tercero y cuarto (índices 0, 1, 2 y 3):

    New-Volume -FriendlyName "MyVolume" -Size 100GB -StorageFaultDomainsToUse $Servers[0,1,2,3]
    

Ver una asignación delimitada

Para ver cómo se asigna MyVolume, use el script Get-VirtualDiskFootprintBySSU.ps1 en Apéndice:

PS C:\> .\Get-VirtualDiskFootprintBySSU.ps1

VirtualDiskFriendlyName TotalFootprint Server1 Server2 Server3 Server4 Server5 Server6
----------------------- -------------- ------- ------- ------- ------- ------- -------
MyVolume                300 GB         100 GB  100 GB  100 GB  100 GB  0       0

Observe que solo Server1, Server2, Server3 y Server4 contienen bloques de MyVolume.

Cambiar una asignación delimitada

Use los nuevos cmdlets Add-StorageFaultDomain y Remove-StorageFaultDomain para cambiar cómo se delimita la asignación.

Por ejemplo, para mover MyVolume por un servidor:

  1. Especifique que el quinto servidor puede almacenar bloques de MyVolume:

    Get-VirtualDisk MyVolume | Add-StorageFaultDomain -StorageFaultDomains $Servers[4]
    
  2. Especifique que el primer servidor no puede almacenar bloques de MyVolume:

    Get-VirtualDisk MyVolume | Remove-StorageFaultDomain -StorageFaultDomains $Servers[0]
    
  3. Vuelva a equilibrar el grupo de almacenamiento para que el cambio surta efecto:

    Get-StoragePool S2D* | Optimize-StoragePool
    

Puede supervisar el progreso del reequilibrio con Get-StorageJob.

Una vez completado, compruebe que MyVolume se ha movido ejecutando de nuevo Get-VirtualDiskFootprintBySSU.ps1.

PS C:\> .\Get-VirtualDiskFootprintBySSU.ps1

VirtualDiskFriendlyName TotalFootprint Server1 Server2 Server3 Server4 Server5 Server6
----------------------- -------------- ------- ------- ------- ------- ------- -------
MyVolume                300 GB         0       100 GB  100 GB  100 GB  100 GB  0

Observe que Server1 ya no contiene bloques de MyVolume, en su lugar, lo hace Server5.

Procedimientos recomendados

Estos son los procedimientos recomendados que se deben seguir al usar la asignación de volúmenes delimitada:

Elegir cuatro servidores

Delimite cada volumen de reflejo triple a cuatro servidores, no más.

Equilibrar el almacenamiento

Equilibre la cantidad de almacenamiento que se asigna a cada servidor, teniendo en cuenta el tamaño del volumen.

Escalonar volúmenes de asignación delimitados

Para maximizar la tolerancia a fallos, haga que la asignación de cada volumen sea única, es decir, que no comparta todos sus servidores con otro volumen (cierto solapamiento es aceptable).

Por ejemplo, en un sistema de ocho nodos: Volumen 1: Servidores 1, 2, 3, 4 Volumen 2: Servidores 5, 6, 7, 8 Volumen 3: Servidores 3, 4, 5, 6 Volumen 4: Servidores 1, 2, 7, 8

Análisis

Esta sección deriva la probabilidad matemática de que un volumen permanezca en línea y accesible (o, de forma equivalente, la fracción esperada del almacenamiento global que permanece en línea y accesible) en función del número de fallos y del tamaño del clúster.

Nota

Esta sección es de lectura opcional. Si quiere ver los cálculos, ¡siga leyendo! Pero si no es así, no se preocupe: Uso en PowerShell y Procedimientos recomendados es todo lo que necesita para implementar con éxito la asignación delimitada.

Hasta dos errores siempre es aceptable

Cada volumen de reflejo triple puede sobrevivir hasta dos fallos al mismo tiempo, independientemente de su asignación. Si fallan dos unidades, o dos servidores, o uno de cada, cada volumen de reflejo triple permanece en línea y accesible, incluso con una asignación regular.

Que falle más de la mitad del clúster nunca es aceptable

Por el contrario, en el caso extremo de que más de la mitad de los servidores o unidades del clúster fallen a la vez, se pierde el quórum y cada volumen de reflejo triple se desconecta y queda inaccesible, independientemente de su asignación.

¿Y entre medias?

Si se producen tres o más fallos a la vez, pero al menos la mitad de los servidores y las unidades siguen funcionando, los volúmenes con asignación delimitada pueden permanecer en línea y accesibles, dependiendo de qué servidores tengan fallos.

Preguntas más frecuentes

¿Puedo delimitar algunos volúmenes, pero no otros?

Sí. Puede elegir por volumen si se va a delimitar o no la asignación.

¿Cambia la asignación delimitada el funcionamiento del reemplazo de unidades?

No, es lo mismo que con la asignación normal.

Referencias adicionales

Apéndice

Este script le ayuda a ver cómo se asignan los volúmenes.

Para usarlo como se describió anteriormente, copie y pegue y guarde como Get-VirtualDiskFootprintBySSU.ps1.

Function ConvertTo-PrettyCapacity {
    Param (
        [Parameter(
            Mandatory = $True,
            ValueFromPipeline = $True
            )
        ]
    [Int64]$Bytes,
    [Int64]$RoundTo = 0
    )
    If ($Bytes -Gt 0) {
        $Base = 1024
        $Labels = ("bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
        $Order = [Math]::Floor( [Math]::Log($Bytes, $Base) )
        $Rounded = [Math]::Round($Bytes/( [Math]::Pow($Base, $Order) ), $RoundTo)
        [String]($Rounded) + " " + $Labels[$Order]
    }
    Else {
        "0"
    }
    Return
}

Function Get-VirtualDiskFootprintByStorageFaultDomain {

    ################################################
    ### Step 1: Gather Configuration Information ###
    ################################################

    Write-Progress -Activity "Get-VirtualDiskFootprintByStorageFaultDomain" -CurrentOperation "Gathering configuration information..." -Status "Step 1/4" -PercentComplete 00

    $ErrorCannotGetCluster = "Cannot proceed because 'Get-Cluster' failed."
    $ErrorNotS2DEnabled = "Cannot proceed because the cluster is not running Storage Spaces Direct."
    $ErrorCannotGetClusterNode = "Cannot proceed because 'Get-ClusterNode' failed."
    $ErrorClusterNodeDown = "Cannot proceed because one or more cluster nodes is not Up."
    $ErrorCannotGetStoragePool = "Cannot proceed because 'Get-StoragePool' failed."
    $ErrorPhysicalDiskFaultDomainAwareness = "Cannot proceed because the storage pool is set to 'PhysicalDisk' fault domain awareness. This cmdlet only supports 'StorageScaleUnit', 'StorageChassis', or 'StorageRack' fault domain awareness."

    Try  {
        $GetCluster = Get-Cluster -ErrorAction Stop
    }
    Catch {
        throw $ErrorCannotGetCluster
    }

    If ($GetCluster.S2DEnabled -Ne 1) {
        throw $ErrorNotS2DEnabled
    }

    Try  {
        $GetClusterNode = Get-ClusterNode -ErrorAction Stop
    }
    Catch {
        throw $ErrorCannotGetClusterNode
    }

    If ($GetClusterNode | Where State -Ne Up) {
        throw $ErrorClusterNodeDown
    }

    Try {
        $GetStoragePool = Get-StoragePool -IsPrimordial $False -ErrorAction Stop
    }
    Catch {
        throw $ErrorCannotGetStoragePool
    }

    If ($GetStoragePool.FaultDomainAwarenessDefault -Eq "PhysicalDisk") {
        throw $ErrorPhysicalDiskFaultDomainAwareness
    }

    ###########################################################
    ### Step 2: Create SfdList[] and PhysicalDiskToSfdMap{} ###
    ###########################################################

    Write-Progress -Activity "Get-VirtualDiskFootprintByStorageFaultDomain" -CurrentOperation "Analyzing physical disk information..." -Status "Step 2/4" -PercentComplete 25

    $SfdList = Get-StorageFaultDomain -Type ($GetStoragePool.FaultDomainAwarenessDefault) | Sort FriendlyName # StorageScaleUnit, StorageChassis, or StorageRack

    $PhysicalDiskToSfdMap = @{} # Map of PhysicalDisk.UniqueId -> StorageFaultDomain.FriendlyName
    $SfdList | ForEach {
        $StorageFaultDomain = $_
        $_ | Get-StorageFaultDomain -Type PhysicalDisk | ForEach {
            $PhysicalDiskToSfdMap[$_.UniqueId] = $StorageFaultDomain.FriendlyName
        }
    }

    ##################################################################################################
    ### Step 3: Create VirtualDisk.FriendlyName -> { StorageFaultDomain.FriendlyName -> Size } Map ###
    ##################################################################################################

    Write-Progress -Activity "Get-VirtualDiskFootprintByStorageFaultDomain" -CurrentOperation "Analyzing virtual disk information..." -Status "Step 3/4" -PercentComplete 50

    $GetVirtualDisk = Get-VirtualDisk | Sort FriendlyName

    $VirtualDiskMap = @{}

    $GetVirtualDisk | ForEach {
        # Map of PhysicalDisk.UniqueId -> Size for THIS virtual disk
        $PhysicalDiskToSizeMap = @{}
        $_ | Get-PhysicalExtent | ForEach {
            $PhysicalDiskToSizeMap[$_.PhysicalDiskUniqueId] += $_.Size
        }
        # Map of StorageFaultDomain.FriendlyName -> Size for THIS virtual disk
        $SfdToSizeMap = @{}
        $PhysicalDiskToSizeMap.keys | ForEach {
            $SfdToSizeMap[$PhysicalDiskToSfdMap[$_]] += $PhysicalDiskToSizeMap[$_]
        }
        # Store
        $VirtualDiskMap[$_.FriendlyName] = $SfdToSizeMap
    }

    #########################
    ### Step 4: Write-Out ###
    #########################

    Write-Progress -Activity "Get-VirtualDiskFootprintByStorageFaultDomain" -CurrentOperation "Formatting output..." -Status "Step 4/4" -PercentComplete 75

    $Output = $GetVirtualDisk | ForEach {
        $Row = [PsCustomObject]@{}

        $VirtualDiskFriendlyName = $_.FriendlyName
        $Row | Add-Member -MemberType NoteProperty "VirtualDiskFriendlyName" $VirtualDiskFriendlyName

        $TotalFootprint = $_.FootprintOnPool | ConvertTo-PrettyCapacity
        $Row | Add-Member -MemberType NoteProperty "TotalFootprint" $TotalFootprint

        $SfdList | ForEach {
            $Size = $VirtualDiskMap[$VirtualDiskFriendlyName][$_.FriendlyName] | ConvertTo-PrettyCapacity
            $Row | Add-Member -MemberType NoteProperty $_.FriendlyName $Size
        }

        $Row
    }

    # Calculate width, in characters, required to Format-Table
    $RequiredWindowWidth = ("TotalFootprint").length + 1 + ("VirtualDiskFriendlyName").length + 1
    $SfdList | ForEach {
        $RequiredWindowWidth += $_.FriendlyName.Length + 1
    }

    $ActualWindowWidth = (Get-Host).UI.RawUI.WindowSize.Width

    If (!($ActualWindowWidth)) {
        # Cannot get window width, probably ISE, Format-List
        Write-Warning "Could not determine window width. For the best experience, use a Powershell window instead of ISE"
        $Output | Format-Table
    }
    ElseIf ($ActualWindowWidth -Lt $RequiredWindowWidth) {
        # Narrower window, Format-List
        Write-Warning "For the best experience, try making your PowerShell window at least $RequiredWindowWidth characters wide. Current width is $ActualWindowWidth characters."
        $Output | Format-List
    }
    Else {
        # Wider window, Format-Table
        $Output | Format-Table
    }
}

Get-VirtualDiskFootprintByStorageFaultDomain