次の方法で共有


記憶域スペース ダイレクトでボリュームの割り当てを区切る

Windows Server 2019 では記憶域スペース ダイレクトでボリュームの割り当てを手動で区切るオプションが導入されています。 そのようにすると、特定の条件下でフォールト トレランスを大幅に向上させることができますが、管理上の考慮事項と複雑さが増えます。 このトピックでは、そのしくみについて説明し、PowerShell での例を示します。

Important

これは Windows Server 2019 の新機能です。 Windows Server 2016 では使用できません。

Prerequisites

緑のチェックマーク アイコン。 次の場合に、このオプションの使用を検討してください。

  • クラスターに 6 台以上のサーバーがある。
  • Your cluster uses only three-way mirror resiliency

赤の X のアイコン。 次の場合はこのオプションを使用しないでください。

Understand

レビュー: 通常の割り当て

通常の 3 方向ミラーリングでは、ボリュームは多数の小さな "スラブ" に分割され、それらが 3 回コピーされ、クラスター内のすべてのサーバーのすべてのドライブに均等に分散されます。 詳細については、この詳細なブログを参照してください。

ボリュームが 3 つのスラブ スタックに分割され、すべてのサーバーに均等に分散されていることを示す図。

この既定の割り当てにより、並列読み取りと書き込みが最大限に実行され、パフォーマンスが向上します。また次のように、シンプルになります。つまり、すべてのサーバーが均等にビジー状態になり、すべてのドライブが均等にいっぱいになり、すべてのボリュームがいっしょにオンラインのままになるかオフラインになります。 Every volume is guaranteed to survive up to two concurrent failures, as these examples illustrate.

ただし、この割り当てでは、ボリュームは 3 つの同時障害に耐えることはできません。 3 台のサーバーで同時に障害が発生した場合、または 3 台のサーバーのドライブで同時に障害が発生した場合、少なくとも一部のスラブが (非常に高い確率で) 障害が発生した 3 台のドライブまたはサーバーに割り当てられているため、ボリュームにアクセスできなくなります。

次の例では、サーバー 1、3、および 5 で同時に障害が発生します。 多くのスラブには残ったコピーがありますが、一部のスラブにはありません。

6 台中 3 台のサーバーが赤で強調表示され、ボリューム全体が赤であることを示す図。

ボリュームはオフラインになり、サーバーが回復するまでアクセスできなくなります。

新機能: 区切られた割り当て

区切られた割り当てでは、使用するサーバーのサブセットを指定します (最小 4)。 ボリュームは、以前と同様に 3 回コピーされるスラブに分割されますが、すべてのサーバーに割り当てられるのではなく、指定したサーバーのサブセットにのみスラブが割り当てられます

たとえば、8 ノードのクラスター (ノード 1 - 8) を使用している場合は、ノード 1、2、3、4 のディスクにのみボリュームが割り当てられるように指定できます。

Advantages

この例の割り当てでは、ボリュームは同時に 3 つの障害に耐えることができます。 ノード 1、2、および 6 がダウンした場合、ボリュームの 3 つのデータ コピーを保持しているノードのうち 2 つだけがダウンし、ボリュームはオンラインのままになります。

Survival probability depends on the number of servers and other factors – see Analysis for details.

Disadvantages

区切られた割り当てにより、管理上の考慮事項と複雑さが増加します。

  1. The administrator is responsible for delimiting the allocation of each volume to balance storage utilization across servers and uphold high probability of survival, as described in the Best practices section.

  2. 区切られた割り当てでは、サーバーごとに 1 つの容量ドライブ (最大値はありません) に相当するものを予約します。 This is more than the published recommendation for regular allocation, which maxes out at four capacity drives total.

  3. サーバーとそのドライブの削除に関するページで説明されているように、サーバーで障害が発生し、交換が必要になった場合、管理者は、新しいサーバーを追加して障害が発生したボリュームの割り当てを削除することで、影響を受けるボリュームを更新する必要があります。次の例を参照してください。

PowerShell での使用法

New-Volume コマンドレットを使用して記憶域スペース ダイレクトにボリュームを作成できます。

たとえば、通常の 3 方向ミラー ボリュームを作成するには、次のようにします。

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

ボリュームを作成し、その割り当てを区切る

3 方向ミラー ボリュームを作成し、その割り当てを区切るには、次のようにします。

  1. まず、クラスター内のサーバーを変数 $Servers に割り当てます。

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

    Tip

    記憶域スペース ダイレクトでは、"ストレージ スケール ユニット" という用語は、直接接続されたドライブや、ドライブを含む直接接続された外部エンクロージャなどの、1 台のサーバーに接続されているすべての未加工のストレージを指します。 このコンテキストでは、"サーバー" と同じです。

  2. 新しい -StorageFaultDomainsToUse パラメーターを使うか、$Servers にインデックスを付けることによって、どのサーバーを使用するかを指定します。 たとえば、1 番目、2 番目、3 番目、および 4 番目のサーバー (インデックス 0、1、2、および 3) に対して割り当てを区切るには、次のようにします。

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

区切られた割り当てを表示する

To see how MyVolume is allocated, use the Get-VirtualDiskFootprintBySSU.ps1 script in Appendix:

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

Note that only Server1, Server2, Server3, and Server4 contain slabs of MyVolume.

区切られた割り当てを変更する

新しい Add-StorageFaultDomain コマンドレットと Remove-StorageFaultDomain コマンドレットを使用して、割り当ての区切り方を変更します。

For example, to move MyVolume over by one server:

  1. Specify that the fifth server can store slabs of MyVolume:

    Get-VirtualDisk MyVolume | Add-StorageFaultDomain -StorageFaultDomains $Servers[4]
    
  2. Specify that the first server cannot store slabs of MyVolume:

    Get-VirtualDisk MyVolume | Remove-StorageFaultDomain -StorageFaultDomains $Servers[0]
    
  3. 変更を有効にするために、記憶域プールの負荷を再調整します。

    Get-StoragePool S2D* | Optimize-StoragePool
    

Get-StorageJob を使用して、再均衡化の進行状況を監視できます。

Once it is complete, verify that MyVolume has moved by running Get-VirtualDiskFootprintBySSU.ps1 again.

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

Note that Server1 does not contain slabs of MyVolume anymore – instead, Server5 does.

Best practices

区切られたボリュームの割り当てを使用する場合のベスト プラクティスを次に示します。

4 台のサーバーを選択する

3 方向ミラー ボリュームをそれぞれ 4 台のサーバーだけに区切ります。

Balance storage

ボリュームのサイズを考慮して、各サーバーに割り当てられるストレージの量を調整します。

段階的にボリュームの割り当てを区切る

To maximize fault tolerance, make each volume's allocation unique, meaning it does not share all its servers with another volume (some overlap is okay).

たとえば、8 ノード システムの場合、次のようにします。ボリューム 1: サーバー 1、2、3、4、ボリューム 2: サーバー 5、6、7、8、ボリューム 3: サーバー 3、4、5、6、ボリューム 4: サーバー 1、2、7、8

Analysis

このセクションでは、障害の数とクラスター サイズに応じて、ボリュームがオンラインでアクセス可能である算術的な確率 (または、オンラインでアクセス可能なストレージ全体の予想される割合) を導き出します。

Note

このセクションは省略可能です。 数値演算が得意な場合は、読んでください。 そうでない場合でも心配しないでください。区切られた割り当てを正常に実装するために必要なのは、PowerShell の使用方法ベスト プラクティスだけです。

常に最大 2 つの障害に耐える

3 方向ミラー ボリュームはいずれも、割り当てに関係なく、同時に最大 2 つの障害に耐えることができます。 2 台のドライブで障害が発生した場合、または 2 台のサーバーで障害が発生した場合、またはそれぞれの 1 台で障害が発生した場合、通常の割り当てであっても、3 方向ミラー ボリュームはオンライン状態を維持し、アクセスできます。

クラスターの障害が半分を超えた場合は問題

逆に、クラスター内の半分以上のサーバーまたはドライブで一度に障害が発生した場合は、割り当てに関係なく、クォーラムが失われ、3 方向ミラー ボリュームがすべてオフラインになり、アクセスできなくなります。

その中間の場合

3 つ以上の障害が一度に発生しても、少なくとも半数のサーバーとドライブが引き続き稼働している場合、障害が発生しているサーバーによっては、区切られた割り当てを持つボリュームが引き続きオンラインでアクセス可能になることがあります。

よく寄せられる質問

一部のボリュームを区切り、他のボリュームを区切らないようにすることができますか?

Yes. 割り当てを区切るかどうかは、ボリュームごとに選択できます。

区切られた割り当てによってドライブ置換の動作が変更されますか?

いいえ。通常の割り当てと同じです。

Additional References

Appendix

このスクリプトは、ボリュームがどのように割り当てられているかを確認するのに役立ちます。

前述のとおりに使用するには、コピー/貼り付けを行って、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