Windows Server 2022 Storage Spaces Direct (S2D) Configuration Guide
Introduction
Storage Spaces Direct (S2D) is a software-defined storage feature in Windows Server 2022 that enables building highly available and scalable storage systems using industry-standard servers with local-attached drives. This guide provides comprehensive instructions for planning, deploying, and managing Storage Spaces Direct.
Prerequisites
Hardware Requirements
- Minimum 2 servers, maximum 16 servers per cluster
- Identical or similar server configurations
- Minimum 4 drives per server (excluding boot drives)
- 10 GbE or faster network adapters (RDMA recommended)
- Separate networks for management and storage traffic
Software Requirements
- Windows Server 2022 Datacenter Edition
- Latest Windows updates installed
- Active Directory domain membership
- Administrator privileges
Supported Drive Types
- NVMe (recommended for cache)
- SSD SATA/SAS (cache or capacity)
- HDD SATA/SAS (capacity only)
1. Pre-Deployment Validation
Hardware Inventory
# Check server hardware configuration
Get-PhysicalDisk | Select-Object FriendlyName, MediaType, Size, HealthStatus
Get-NetAdapter | Where-Object {$_.Status -eq "Up"} | Select-Object Name, InterfaceDescription, LinkSpeed
Get-WmiObject Win32_ComputerSystem | Select-Object Manufacturer, Model, TotalPhysicalMemory
Network Validation
# Test RDMA capability
Get-NetAdapterRdma | Select-Object Name, Enabled, RdmaCapabilities
# Test network connectivity between nodes
Test-Cluster -Node server1,server2,server3,server4 -Include "Network"
# Verify jumbo frames
Get-NetAdapterAdvancedProperty -Name * | Where-Object {$_.DisplayName -match "Jumbo"} | Select-Object Name, DisplayName, DisplayValue
2. Initial Configuration
Configure Network
# Configure management network
New-NetIPAddress -InterfaceAlias "Management" -IPAddress 192.168.1.10 -PrefixLength 24 -DefaultGateway 192.168.1.1
Set-DnsClientServerAddress -InterfaceAlias "Management" -ServerAddresses 192.168.1.5,192.168.1.6
# Configure storage networks (2 for redundancy)
New-NetIPAddress -InterfaceAlias "Storage1" -IPAddress 10.10.10.10 -PrefixLength 24
New-NetIPAddress -InterfaceAlias "Storage2" -IPAddress 10.10.20.10 -PrefixLength 24
# Enable jumbo frames
Set-NetAdapterAdvancedProperty -Name "Storage1" -DisplayName "Jumbo Frame" -DisplayValue "9014"
Set-NetAdapterAdvancedProperty -Name "Storage2" -DisplayName "Jumbo Frame" -DisplayValue "9014"
# Configure RDMA
Enable-NetAdapterRdma -Name "Storage1","Storage2"
Set-NetAdapterRdma -Name "Storage1","Storage2" -RdmaMode iWARP
Install Required Features
# Install on all servers
$servers = @("Server1", "Server2", "Server3", "Server4")
Invoke-Command -ComputerName $servers -ScriptBlock {
Install-WindowsFeature -Name Hyper-V, Failover-Clustering, Data-Deduplication, BitLocker, File-Server, RSAT-Clustering-PowerShell, Hyper-V-PowerShell -IncludeManagementTools -Restart
}
3. Create Failover Cluster
Validate Cluster Configuration
# Run comprehensive cluster validation
Test-Cluster -Node Server1,Server2,Server3,Server4 -Include "Storage Spaces Direct", Inventory, Network, "System Configuration"
Create Cluster
# Create new cluster
New-Cluster -Name S2DCluster -Node Server1,Server2,Server3,Server4 -StaticAddress 192.168.1.100 -NoStorage
# Configure cluster network names
(Get-ClusterNetwork -Name "Cluster Network 1").Name = "Management"
(Get-ClusterNetwork -Name "Cluster Network 2").Name = "Storage1"
(Get-ClusterNetwork -Name "Cluster Network 3").Name = "Storage2"
# Configure cluster network roles
(Get-ClusterNetwork -Name "Management").Role = 3 # Cluster + Client
(Get-ClusterNetwork -Name "Storage1").Role = 1 # Cluster Only
(Get-ClusterNetwork -Name "Storage2").Role = 1 # Cluster Only
Configure Cluster Quorum
# Configure cloud witness
Set-ClusterQuorum -CloudWitness -AccountName "s2dwitness" -AccessKey "your-storage-account-key"
# Or configure file share witness
Set-ClusterQuorum -FileShareWitness "\\fileserver\witness$"
4. Enable Storage Spaces Direct
Clean Drives
# Clean all drives on all nodes (WARNING: This will erase all data)
Invoke-Command -ComputerName $servers -ScriptBlock {
Get-PhysicalDisk | Where-Object {$_.CanPool -eq $true} | Reset-PhysicalDisk
Get-Disk | Where-Object {$_.Number -ne 0 -and $_.IsBoot -ne $true} | Set-Disk -IsOffline $false
Get-Disk | Where-Object {$_.Number -ne 0 -and $_.IsBoot -ne $true} | Set-Disk -IsReadOnly $false
Get-Disk | Where-Object {$_.Number -ne 0 -and $_.IsBoot -ne $true} | Clear-Disk -RemoveData -RemoveOEM -Confirm:$false
}
Enable S2D
# Enable Storage Spaces Direct
Enable-ClusterStorageSpacesDirect -PoolFriendlyName "S2DPool" -Confirm:$false
# Verify S2D is enabled
Get-ClusterStorageSpacesDirect
5. Storage Configuration
Create Volumes
# Create mirror volume (2-way or 3-way)
New-Volume -StoragePoolFriendlyName "S2DPool" -FriendlyName "Mirror-Volume" -Size 1TB -ResiliencySettingName Mirror -ProvisioningType Thin
# Create parity volume (for cold data)
New-Volume -StoragePoolFriendlyName "S2DPool" -FriendlyName "Parity-Volume" -Size 5TB -ResiliencySettingName Parity -ProvisioningType Thin
# Create tiered volume (mirror + parity)
New-StorageTier -StoragePoolFriendlyName "S2DPool" -FriendlyName "Performance" -MediaType SSD -ResiliencySettingName Mirror
New-StorageTier -StoragePoolFriendlyName "S2DPool" -FriendlyName "Capacity" -MediaType HDD -ResiliencySettingName Parity
New-Volume -StoragePoolFriendlyName "S2DPool" -FriendlyName "Tiered-Volume" -StorageTierFriendlyNames "Performance", "Capacity" -StorageTierSizes 200GB, 800GB
Configure CSV (Cluster Shared Volumes)
# Add volumes to CSV
Get-ClusterSharedVolume
Add-ClusterSharedVolume -Name "Cluster Virtual Disk (Mirror-Volume)"
Add-ClusterSharedVolume -Name "Cluster Virtual Disk (Parity-Volume)"
# Rename CSV mount points
$csv = Get-ClusterSharedVolume -Name "Cluster Virtual Disk (Mirror-Volume)"
$csv.Name = "CSV-Mirror"
6. Performance Optimization
Configure Storage QoS
# Create QoS policies
New-StorageQosPolicy -Name "Gold" -PolicyType Dedicated -MinimumIops 1000 -MaximumIops 5000
New-StorageQosPolicy -Name "Silver" -PolicyType Dedicated -MinimumIops 500 -MaximumIops 2500
New-StorageQosPolicy -Name "Bronze" -PolicyType Dedicated -MinimumIops 100 -MaximumIops 1000
# Apply QoS to volumes
Get-Volume -FriendlyName "Mirror-Volume" | Set-StorageQosPolicy -Name "Gold"
Configure Cache
# View cache configuration
Get-ClusterStorageSpacesDirect | Select-Object CacheState, CacheMetadataReserveBytes, CachePageSizeKBytes
# Modify cache settings (requires restart of S2D)
Set-ClusterStorageSpacesDirect -CacheModeSSD ReadWrite -CacheModeHDD ReadOnly
Enable Deduplication
# Enable dedup on volume
Enable-DedupVolume -Volume "C:\ClusterStorage\Volume1" -UsageType HyperV
# Configure dedup schedule
Set-DedupSchedule -Name "BackgroundOptimization" -Start 22:00 -DurationHours 6 -Days Monday,Tuesday,Wednesday,Thursday,Friday
7. Fault Tolerance Configuration
Configure Fault Domains
# Create fault domains for rack awareness
New-ClusterFaultDomain -Type Rack -Name "Rack1"
New-ClusterFaultDomain -Type Rack -Name "Rack2"
# Assign nodes to racks
Set-ClusterFaultDomain -Name "Server1" -Parent "Rack1"
Set-ClusterFaultDomain -Name "Server2" -Parent "Rack1"
Set-ClusterFaultDomain -Name "Server3" -Parent "Rack2"
Set-ClusterFaultDomain -Name "Server4" -Parent "Rack2"
# View fault domain configuration
Get-ClusterFaultDomain
Configure Storage Resiliency
# Set resiliency period
(Get-Cluster).ResiliencyDefaultPeriod = 240 # 4 minutes
# Configure storage repair
Set-StoragePool -FriendlyName "S2DPool" -RepairPolicy Parallel -RetireMissingPhysicalDisks Always
8. Monitoring and Health
Health Service Configuration
# View health service status
Get-ClusterResource "Health Service" | Get-ClusterParameter
# Configure health service settings
Get-ClusterResource "Health Service" | Set-ClusterParameter -Name "Enable" -Value 1
Performance Monitoring
# Create performance baseline
$counters = @(
"\Cluster Storage Hybrid Disk(*)\*",
"\Cluster Storage Cache Stores(*)\*",
"\Storage Spaces Direct\*",
"\PhysicalDisk(*)\*"
)
# Create data collector set
$datacollector = New-Object -ComObject Pla.DataCollectorSet
$datacollector.DisplayName = "S2D Performance"
$datacollector.Duration = 300
$datacollector.SubdirectoryFormat = 1
$datacollector.RootPath = "C:\PerfLogs\S2D"
$collector = $datacollector.DataCollectors.CreateDataCollector(0)
$collector.FileName = "S2D_Performance"
$collector.FileNameFormat = 0
$collector.PerformanceCounters = $counters
$datacollector.DataCollectors.Add($collector)
$datacollector.Commit("S2D Performance", $null, 0x0003)
Storage Health Monitoring
# Check storage subsystem health
Get-StorageSubsystem -FriendlyName "*Clustered*" | Get-StorageHealthReport
# Monitor storage jobs
Get-StorageJob
# Check disk health
Get-PhysicalDisk | Select-Object FriendlyName, HealthStatus, OperationalStatus, Size, MediaType
# View storage pool health
Get-StoragePool "S2DPool" | Get-StorageHealthReport
9. Maintenance Operations
Pause and Drain Node
# Pause node for maintenance
Suspend-ClusterNode -Name "Server1" -Drain
# Resume node after maintenance
Resume-ClusterNode -Name "Server1"
# Move all resources off a node
Move-ClusterGroup -Node "Server2"
Move-ClusterSharedVolume -Node "Server2"
Drive Replacement
# Identify failed drive
Get-PhysicalDisk | Where-Object {$_.HealthStatus -ne "Healthy"}
# Retire failed drive
$disk = Get-PhysicalDisk -FriendlyName "PhysicalDisk-1"
$disk | Set-PhysicalDisk -Usage Retired
# After physical replacement, add new drive to pool
$newDisk = Get-PhysicalDisk | Where-Object {$_.CanPool -eq $true}
Add-PhysicalDisk -StoragePoolFriendlyName "S2DPool" -PhysicalDisks $newDisk
Storage Repair
# Check repair status
Get-StoragePool "S2DPool" | Get-StorageHealthReport
# Trigger storage repair
Repair-VirtualDisk -FriendlyName "Mirror-Volume"
# Monitor repair progress
Get-StorageJob | Where-Object {$_.Name -like "*repair*"}
10. Scaling Operations
Add Node to Cluster
# Prepare new node
Install-WindowsFeature -Name Hyper-V, Failover-Clustering, Data-Deduplication -IncludeManagementTools
# Add node to cluster
Add-ClusterNode -Name "Server5" -Cluster "S2DCluster"
# Rebalance storage
Optimize-StoragePool -FriendlyName "S2DPool"
Add Capacity
# Add new drives to existing nodes
Get-PhysicalDisk | Where-Object {$_.CanPool -eq $true} | Add-PhysicalDisk -StoragePoolFriendlyName "S2DPool"
# Optimize storage pool
Optimize-StoragePool -FriendlyName "S2DPool"
11. Backup and Disaster Recovery
Configure Backup
# Install Windows Server Backup
Install-WindowsFeature -Name Windows-Server-Backup
# Create backup policy for CSV
$policy = New-WBPolicy
$volume = Get-WBVolume -VolumePath "C:\ClusterStorage\Volume1"
Add-WBVolume -Policy $policy -Volume $volume
# Set backup target
$target = New-WBBackupTarget -NetworkPath "\\backup-server\S2D-Backups"
Add-WBBackupTarget -Policy $policy -Target $target
# Schedule backup
Set-WBSchedule -Policy $policy -Schedule 02:00
Set-WBPolicy -Policy $policy
Storage Replica Configuration
# Configure Storage Replica for DR
New-SRPartnership -SourceComputerName "S2DCluster" -SourceRGName "RG01" -SourceVolumeName "C:\ClusterStorage\Volume1" -DestinationComputerName "DRCluster" -DestinationRGName "RG02" -DestinationVolumeName "C:\ClusterStorage\Volume1" -LogVolumeName "L:" -LogSizeInBytes 8GB
12. Troubleshooting
Common Diagnostics
# Check cluster logs
Get-ClusterLog -Destination C:\ClusterLogs
# View storage spaces direct events
Get-WinEvent -LogName Microsoft-Windows-StorageSpacesDirect*/Operational | Select-Object -First 50
# Test storage spaces direct
Test-Cluster -Include "Storage Spaces Direct"
# Check storage communication
Get-ClusterPerformanceHistory -ObjectType StorageSubsystem -TimeFrame LastHour
Performance Troubleshooting
# Check cache hit ratio
Get-ClusterPerformanceHistory -ObjectType Volume -TimeFrame LastHour | Where-Object {$_.MetricId -eq "Volume.Cache.HitRate"}
# Monitor IOPS and latency
Get-ClusterPerformanceHistory -ObjectType Volume -TimeFrame LastHour | Where-Object {$_.MetricId -match "IOPS|Latency"}
# Check network utilization
Get-ClusterPerformanceHistory -ObjectType NetAdapter -TimeFrame LastHour
Best Practices
- Hardware
- Use identical hardware across all nodes
- Use enterprise-grade SSDs for cache
- Implement proper cooling for NVMe drives
-
Use RDMA-capable network adapters
-
Network
- Dedicate networks for storage traffic
- Enable jumbo frames on storage networks
- Use RDMA for better performance
-
Implement network redundancy
-
Configuration
- Keep firmware and drivers updated
- Use thin provisioning for flexibility
- Configure appropriate resiliency settings
-
Plan for 20-30% free space in pool
-
Maintenance
- Perform regular health checks
- Monitor performance baselines
- Test backup and restore procedures
-
Document configuration changes
-
Performance
- Size cache tier appropriately (10% minimum)
- Use tiered storage for mixed workloads
- Enable deduplication for suitable workloads
- Monitor and adjust QoS policies