Share via


저장소 공간 Direct에서 볼륨 할당 구분

적용 대상: Windows Server 2022, Windows Server 2019

Windows Server 2019에는 저장소 공간 Direct에서 볼륨 할당을 수동으로 구분하는 옵션이 도입되었습니다. 이렇게 하면 특정 조건에서 내결함성을 크게 높일 수 있지만 몇 가지 관리 고려 사항 및 복잡성이 추가됩니다. 이 항목에서는 작동 방식을 설명하고 PowerShell의 예제를 제공합니다.

Important

이 기능은 Windows Server 2019의 새로운 기능입니다. Windows Server 2016에서는 사용할 수 없습니다.

필수 조건

Green checkmark icon. 다음과 같은 경우 이 옵션을 사용하는 것이 좋습니다.

  • 클러스터에는 6개 이상의 서버가 있습니다. 및
  • 클러스터는 3방향 미러 복원력만 사용합니다.

Red X icon. 다음 경우에는 이 옵션을 사용하지 마세요.

  • 클러스터에는 6개 미만의 서버가 있습니다. 또는
  • 클러스터에서 패리티 또는 미러 가속 패리티 복원력을 사용합니다.

이해

검토: 일반 할당

일반 3방향 미러 사용하면 볼륨이 세 번 복사되고 클러스터의 모든 서버의 모든 드라이브에 균등하게 분산되는 많은 작은 "슬래브"로 나뉩니다. 자세한 내용은 이 심층 분석 블로그를 참조하세요.

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

이 기본 할당은 병렬 읽기 및 쓰기를 최대화하여 성능이 향상되며, 모든 서버가 동일하게 사용 중이고, 모든 드라이브가 균등하게 꽉 찼으며, 모든 볼륨이 온라인 상태를 유지하거나 함께 오프라인으로 전환되므로 편의상 매력적입니다. 이러한 예제에서 알 수 있듯이 모든 볼륨은 최대 두 번의 동시 오류에서 살아남을 수 있습니다 .

그러나 이 할당을 사용하면 볼륨이 세 번의 동시 실패에서 살아남을 수 없습니다. 세 개의 서버가 한 번에 실패하거나 3대의 서버에서 드라이브가 한 번에 실패하는 경우, 실패한 정확한 3개의 드라이브 또는 서버에 적어도 일부 슬래브가 할당되었기 때문에 볼륨에 액세스할 수 없게 됩니다.

아래 예제에서는 서버 1, 3 및 5가 동시에 실패합니다. 많은 슬래브에는 복사본이 남아 있지만 일부는 다음을 수행하지 않습니다.

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

볼륨이 오프라인 상태가 되고 서버가 복구될 때까지 액세스할 수 없게 됩니다.

새로 만들기: 구분된 할당

구분된 할당을 사용하면 사용할 서버의 하위 집합(최소 4개)을 지정합니다. 볼륨은 이전과 같이 세 번 복사되는 슬래브로 나뉘지만, 모든 서버에 할당하는 대신, 슬래브는 지정한 서버의 하위 집합에만 할당됩니다.

예를 들어 노드 클러스터가 8개(노드 1~8)인 경우 노드 1, 2, 3, 4의 디스크에만 배치할 볼륨을 지정할 수 있습니다.

장점

예제 할당을 사용하면 볼륨이 세 번의 동시 실패에서 살아남을 수 있습니다. 노드 1, 2 및 6이 다운되면 볼륨에 대한 3개의 데이터 복사본을 보유하는 노드 중 2개만 다운되고 볼륨이 온라인 상태로 유지됩니다.

생존 확률은 서버 수 및 기타 요인에 따라 달라집니다. 자세한 내용은 분석을 참조하세요.

단점

구분된 할당은 몇 가지 추가된 관리 고려 사항 및 복잡성을 적용합니다.

  1. 관리자는 모범 사례 섹션에 설명된 대로 서버 간에 스토리지 사용률의 균형을 맞추고 생존 확률이 높도록 각 볼륨의 할당을 구분할 책임이 있습니다 .

  2. 구분된 할당을 사용하여 서버당 하나의 용량 드라이브에 해당하는 용량 드라이브를 예약합니다(최대값 없음). 이는 총 4개의 용량 드라이브에서 최대로 계산되는 일반 할당에 대해 게시된 권장 사항보다 많은 수입니다.

  3. 서버 및 해당 드라이브 제거에 설명된 대로 서버가 실패하고 교체해야 하는 경우 관리자는 새 서버를 추가하고 실패한 서버를 제거하여 영향을 받는 볼륨의 구분을 업데이트할 책임이 있습니다( 아래 예).

PowerShell의 사용량

cmdlet을 New-Volume 사용하여 저장소 공간 Direct에서 볼륨을 만들 수 있습니다.

예를 들어 일반 3방향 미러 볼륨을 만들려면 다음을 수행합니다.

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

볼륨을 만들고 해당 할당을 구분합니다.

3방향 미러 볼륨을 만들고 할당을 구분하려면 다음을 수행합니다.

  1. 먼저 클러스터의 서버를 변수 $Servers에 할당합니다.

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

    저장소 공간 Direct에서 '스토리지 배율 단위'라는 용어는 직접 연결된 드라이브와 드라이브가 있는 직접 연결된 외부 엔클로저를 포함하여 하나의 서버에 연결된 모든 원시 스토리지를 의미합니다. 이 컨텍스트에서는 '서버'와 동일합니다.

  2. -StorageFaultDomainsToUse 매개 변수 및 인덱싱을 사용하여 사용할 서버를 지정합니다 $Servers. 예를 들어 할당을 첫 번째, 두 번째, 세 번째 및 네 번째 서버(인덱스 0, 1, 2 및 3)로 구분합니다.

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

구분된 할당 참조

MyVolume이 할당되는 방법을 확인하려면 부록에서 스크립트를 Get-VirtualDiskFootprintBySSU.ps1 사용합니다.

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

Server1, Server2, Server3 및 Server4에만 MyVolume슬래브가 포함되어 있습니다.

구분된 할당 변경

Add-StorageFaultDomainRemove-StorageFaultDomain cmdlet을 사용하여 할당이 구분되는 방식을 변경합니다.

예를 들어 MyVolume을 한 서버로 이동하려면 다음을 수행합니다.

  1. 다섯 번째 서버가 MyVolume의 슬래브를 저장할 수 있도록 지정합니다.

    Get-VirtualDisk MyVolume | Add-StorageFaultDomain -StorageFaultDomains $Servers[4]
    
  2. 첫 번째 서버가 MyVolume의 슬래브를 저장할 수 없게 지정합니다.

    Get-VirtualDisk MyVolume | Remove-StorageFaultDomain -StorageFaultDomains $Servers[0]
    
  3. 변경 내용이 적용되도록 스토리지 풀의 균형을 다시 조정합니다.

    Get-StoragePool S2D* | Optimize-StoragePool
    

를 사용하여 리밸런스 Get-StorageJob의 진행률을 모니터링할 수 있습니다.

완료되면 MyVolume다시 실행 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

Server1에는 MyVolume의 슬래브가 더 이상 포함되어 있지 않습니다. 대신 Server5는 이 작업을 수행합니다.

모범 사례

구분된 볼륨 할당을 사용할 때 따라야 할 모범 사례는 다음과 같습니다.

서버 4개 선택

각 3방향 미러 볼륨을 4개의 서버로 구분합니다.

스토리지 균형 조정

볼륨 크기를 고려하여 각 서버에 할당되는 스토리지의 양과 균형을 유지합니다.

분리된 할당 볼륨 스태거

내결함성을 최대화하려면 각 볼륨의 할당을 고유하게 지정합니다. 즉, 모든 서버를 다른 볼륨과 공유하지는 않습니다(일부 겹치는 것은 괜찮습니다).

예를 들어 8노드 시스템의 경우: 볼륨 1: 서버 1, 2, 3, 4 볼륨 2: 서버 5, 6, 7, 8 볼륨 3: 서버 3, 4, 5, 6 볼륨 4: 서버 1, 2, 7, 8

분석

이 섹션에서는 볼륨이 온라인 상태로 유지되고 액세스할 수 있는 수학적 확률(또는 온라인 상태로 유지되고 액세스할 수 있는 전체 스토리지의 예상 비율)을 오류 수 및 클러스터 크기의 함수로 파생합니다.

참고 항목

이 섹션은 선택적 읽기입니다. 수학을 보고 싶다면 계속 읽으세요! 그렇지 않은 경우 걱정하지 마세요. PowerShell모범 사례 의 사용법은 구분된 할당을 성공적으로 구현하는 데 필요합니다.

최대 두 번의 실패는 항상 괜찮습니다.

모든 3방향 미러 볼륨은 할당에 관계없이 동시에 최대 두 번의 오류에서 살아남을 수 있습니다. 두 개의 드라이브가 실패하거나 두 개의 서버가 실패하거나 각 서버 중 하나가 실패하는 경우 3방향 미러 볼륨은 정기적으로 할당되더라도 온라인 상태로 유지되고 액세스할 수 있습니다.

클러스터 실패의 절반 이상이 정상이 아닌 경우

반대로 클러스터에 있는 서버 또는 드라이브의 절반 이상이 한 번에 실패하는 극단적인 경우 쿼럼이 손실되고 3방향 미러 볼륨이 오프라인 상태가 되고 할당에 관계없이 액세스할 수 없게 됩니다.

그 사이에는 어떤 것이 있을까요?

한 번에 3개 이상의 오류가 발생하지만 서버와 드라이브의 절반 이상이 계속 가동되면 오류가 발생한 서버에 따라 구분된 할당이 있는 볼륨이 온라인 상태로 유지되고 액세스할 수 있습니다.

자주 묻는 질문

일부 볼륨은 구분할 수 있지만 다른 볼륨은 구분할 수 없나요?

예. 할당을 구분할지 여부를 볼륨별로 선택할 수 있습니다.

구분된 할당은 드라이브 교체의 작동 방식을 변경하나요?

아니요, 일반 할당과 동일합니다.

추가 참조

부록

이 스크립트는 볼륨이 할당되는 방법을 확인하는 데 도움이 됩니다.

위에서 설명한 대로 사용하려면 복사/붙여넣고 다음으로 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