저장소 공간 Direct에서 볼륨 할당 구분
Windows Server 2019에는 저장소 공간 Direct에서 볼륨 할당을 수동으로 구분하는 옵션이 도입되었습니다. 이렇게 하면 특정 조건에서 내결함성을 크게 높일 수 있지만 몇 가지 관리 고려 사항 및 복잡성이 추가됩니다. 이 항목에서는 작동 방식을 설명하고 PowerShell의 예제를 제공합니다.
Important
이 기능은 Windows Server 2019의 새로운 기능입니다. Windows Server 2016에서는 사용할 수 없습니다.
필수 조건
다음과 같은 경우 이 옵션을 사용하는 것이 좋습니다.
- 클러스터에는 6개 이상의 서버가 있습니다. 그리고
- 클러스터는 3방향 미러 복원력만 사용합니다.
이 경우 이 생성자를 사용하지 마세요.
이해
검토: 일반 할당
일반 3방향 미러링을 사용하면 볼륨이 세 번 복사되고 클러스터의 모든 서버의 모든 드라이브에 균등하게 분산되는 많은 작은 "슬래브"로 나뉩니다. 자세한 내용은 이 딥 다이브 블로그를 참조하세요.
이 기본 할당은 병렬 읽기 및 쓰기를 최대화하여 성능이 향상되며, 모든 서버가 동일하게 사용 중이고, 모든 드라이브가 균등하게 꽉 찼으며, 모든 볼륨이 온라인 상태를 유지하거나 함께 오프라인으로 전환되므로 편의상 매력적입니다. 이러한 예제에서 알 수 있듯이 모든 볼륨은 최대 두 번의 동시 오류에서 살아남을 수 있습니다 .
그러나 이 할당을 사용하면 볼륨이 세 번의 동시 실패에서 살아남을 수 없습니다. 세 개의 서버가 한 번에 실패하거나 3대의 서버에서 드라이브가 한 번에 실패하는 경우, 실패한 정확한 3개의 드라이브 또는 서버에 적어도 일부 슬래브가 할당되었기 때문에 볼륨에 액세스할 수 없게 됩니다.
아래 예제에서는 서버 1, 3 및 5가 동시에 실패합니다. 많은 슬래브에는 복사본이 남아 있지만 일부는 다음을 수행하지 않습니다.
볼륨이 오프라인 상태가 되고 서버가 복구될 때까지 액세스할 수 없게 됩니다.
새로 만들기: 구분된 할당
구분된 할당을 사용하면 사용할 서버의 하위 집합(최소 4개)을 지정합니다. 볼륨은 이전과 같이 세 번 복사되는 슬래브로 나뉘지만, 모든 서버에 할당하는 대신, 슬래브는 지정한 서버의 하위 집합에만 할당됩니다.
예를 들어 노드 클러스터가 8개(노드 1~8)인 경우 노드 1, 2, 3, 4의 디스크에만 배치할 볼륨을 지정할 수 있습니다.
장점
예제 할당을 사용하면 볼륨이 세 번의 동시 실패에서 살아남을 수 있습니다. 노드 1, 2 및 6이 다운되면 볼륨에 대한 3개의 데이터 복사본을 보유하는 노드 중 2개만 다운되고 볼륨이 온라인 상태로 유지됩니다.
생존 확률은 서버 수 및 기타 요인에 따라 달라집니다. 자세한 내용은 분석을 참조하세요.
단점
구분된 할당은 몇 가지 추가된 관리 고려 사항 및 복잡성을 적용합니다.
관리자는 모범 사례 섹션에 설명된 대로 서버 간에 스토리지 사용률의 균형을 맞추고 생존 확률이 높도록 각 볼륨의 할당을 구분할 책임이 있습니다.
구분된 할당을 사용하여 서버당 하나의 용량 드라이브에 해당하는 용량 드라이브(최대값 없음)를 예약합니다. 이는 총 4개의 용량 드라이브에서 최대로 계산되는 일반 할당에 대해 게시된 권장 사항보다 많은 수입니다.
서버 및 해당 드라이브 제거에 설명된 대로 서버가 실패하고 교체해야 하는 경우 관리자는 새 서버를 추가하고 실패한 서버를 제거하여 영향을 받는 볼륨의 구분을 업데이트할 책임이 있습니다(아래 예).
PowerShell의 사용량
New-Volume
cmdlet을 사용하여 저장소 공간 Direct에서 볼륨을 만들 수 있습니다.
예를 들어, 일반 3방향 미러 볼륨을 만들려면:
New-Volume -FriendlyName "MyRegularVolume" -Size 100GB
볼륨을 만들고 해당 할당을 구분합니다.
3방향 미러 볼륨을 만들고 할당을 구분하려면 다음을 수행합니다.
먼저 클러스터의 서버를 변수
$Servers
에 할당합니다.$Servers = Get-StorageFaultDomain -Type StorageScaleUnit | Sort FriendlyName
팁
저장소 공간 Direct에서 '스토리지 배율 단위'라는 용어는 직접 연결된 드라이브와 드라이브가 있는 직접 연결된 외부 엔클로저를 포함하여 하나의 서버에 연결된 모든 원시 스토리지를 의미합니다. 이 컨텍스트에서는 '서버'와 동일합니다.
새
-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-StorageFaultDomain
및 Remove-StorageFaultDomain
cmdlet을 사용하여 할당이 구분되는 방식을 변경합니다.
예를 들어 MyVolume을 한 서버로 이동하려면 다음을 수행합니다.
다섯 번째 서버가 MyVolume의 슬래브를 저장할 수 있도록 지정합니다.
Get-VirtualDisk MyVolume | Add-StorageFaultDomain -StorageFaultDomains $Servers[4]
첫번째 서버가 MyVolume의 슬래브를 저장할 수 없도록 지정합니다.
Get-VirtualDisk MyVolume | Remove-StorageFaultDomain -StorageFaultDomains $Servers[0]
변경 내용이 적용되도록 스토리지 풀의 균형을 다시 조정합니다.
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방향 미러 볼륨은 할당에 관계없이 동시에 최대 두 번의 오류에서 살아남을 수 있습니다. 2개의 드라이브가 실패하거나 두 개의 서버가 실패하거나 각 서버 중 하나가 실패하는 경우 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