香港服务器运行 Windows Server 2022 时,如何优化“存储空间直通”(S2D)提升数据库 I/O 性能?

凌晨 2:17,香港葵涌机房 7 楼,DBA 打来电话:“跨区报表延迟 40 分钟,线上写入抖成波形图了。”我扣上腕灯、把笔记本放在机柜前的折叠梯上,盯着一排状态灯发呆:我们刚把客户的数据库业务迁到 Windows Server 2022 + “存储空间直通”(Storage Spaces Direct,下文简称 S2D)的超融合集群上,指标在白天都很漂亮,怎么到夜里高并发 ETL 就掉链子?
这篇文章,就是那一夜到天亮的优化记录。不是“教科书式”的满分答案,而是一段有汗有坑的实战路线:硬件选型 → S2D 架构要点 → Windows/网络/RDMA 调优 → 卷/文件系统/布局策略 → SQL 数据/日志/TempDB 的放置与参数 → 基准压测与回归 → 故障与坑的现场解法。我会把关键命令、参数、表格和实际数据都写出来,新手能抄作业,老手能对表调参。
1. 现场环境与目标
1.1 目标
- 高并发写入(夜间 ETL)不抖动
- 事务日志延迟稳定 < 3 ms
- 随机读 ≥ 200K IOPS(64K 块),顺序吞吐≥ 6 GB/s(集群整体)
1.2 机房与硬件(实配)
| 模块 | 型号/数量 | 关键点 |
|---|---|---|
| 机架 | 42U,双路 32A,A/B 路供电 | 上下风道清洁,冷通道送风 |
| 集群节点 | 4 台 2U 服务器,双路 Intel Xeon Gold(或 AMD EPYC 对等) | 每台 512 GB RAM |
| 加速盘(Cache) | 每节点 2× NVMe U.2 3.2 TB(企业级,写入放大低) | 专供 S2D Cache |
| 容量盘(Capacity) | 每节点 8× SATA/SAS SSD 3.84 TB | All-Flash |
| 网络 | 每节点 2× 25GbE(Mellanox/Intel RDMA),1× 1Gb 管理 | 走 RoCEv2,Jumbo 9014 |
| 交换机 | 2× 25/100GbE,可堆叠,DCB 支持 | 开启 PFC/ETS |
| 系统 | Windows Server 2022 Datacenter(含 S2D) | 版本统一、补丁齐全 |
| 数据库 | Microsoft SQL Server 2019/2022 | 兼容 ReFS |
S2D 在 All-Flash 场景下会自动识别 NVMe 做写缓存,SAS/SATA SSD 做容量层。我们的 ETL 夜间写压力大,选 4 节点起步、NVMe×2 保证足够的写吸收能力。
2. 架构与设计要点(先定“地基”)
2.1 S2D 的盘层与冗余
Cache 层:NVMe;容量层:SSD
数据库卷冗余:
事务日志(Log):3-way Mirror(最稳的写延迟)
热数据(OLTP/活跃索引):3-way Mirror
冷/历史数据(报表/明细归档):Mirror-accelerated Parity(MAP)(前端镜像、后端奇偶,既保证写入又节省容量)
文件系统:ReFS + 64K Allocation Unit,DB 卷关闭 Integrity Streams(SQL 自带校验,避免重复校验开销);备份卷开启完整校验与去重。
2.2 卷布局与大小粒度
小文件不代表小块。数据库场景把 Interleave(条带)设为 256 KB 或 512 KB 更合适。
列数(Columns):按节点/磁盘并行度确定,通常 ≥ 8,避免热节点。
Write-back Cache(WBC):All-Flash 默认较小,针对高写入卷手动放大到 8–32 GB(按卷/按节点评估),减少写放大与抖动。
3. 从零到可跑:创建集群与启用 S2D
以下命令均在提升权限的 PowerShell 中执行。节点名按你的环境替换。
# 3.1 基础检查
Get-PhysicalDisk | ft FriendlyName,CanPool,MediaType,BusType,HealthStatus -Auto
Update-StorageFirmware -All # 统一固件版本,避免奇怪的超时
# 3.2 创建故障转移群集(已预先建好 AD 计算机对象)
New-Cluster -Name HKSQLCL1 -Node HK-S2D01,HK-S2D02,HK-S2D03,HK-S2D04 -StaticAddress 10.10.10.10 -NoStorage
# 3.3 群集验证(磁盘/网络/系统)
Test-Cluster -Node HK-S2D01,HK-S2D02,HK-S2D03,HK-S2D04 -Include "Storage","Inventory","Network","System Configuration"
# 3.4 启用 S2D(自动识别 NVMe 为缓存)
Enable-ClusterS2D -Confirm:$false
Get-StoragePool -IsPrimordial:$false | ft FriendlyName,OperationalStatus,HealthStatus
4. RDMA/网络:把“回血通道”打通
S2D 的东西向流量(重建、读写转发)走 SMB3/SMB Direct,RDMA 配对、PFC 和 ETS要配置到位。
# 4.1 安装 DCB、启用 RDMA
Install-WindowsFeature Data-Center-Bridging
Enable-NetAdapterRdma -Name "pNIC1","pNIC2"
Set-SmbClientConfiguration -EnableMultiChannel $true -EnableBandwidthThrottling $false
Set-SmbServerConfiguration -EnableSMBDirect $true
# 4.2 QoS:SMB 置于优先级 3,开启 PFC,仅对 3 生效
New-NetQosPolicy "SMB" -SMB -PriorityValue8021Action 3
Enable-NetQosFlowControl -Priority 3
Disable-NetQosFlowControl -Priority 0,1,2,4,5,6,7
New-NetQosTrafficClass -Name "SMB" -Priority 3 -BandwidthPercentage 50 -Algorithm ETS
# 4.3 Jumbo Frame(网卡与交换机一致,9014)
Set-NetAdapterAdvancedProperty -Name "pNIC1","pNIC2" -DisplayName "Jumbo Packet" -DisplayValue "9014 Bytes"
坑 1(现场):交换机一侧忘了开 PFC,RDMA 随机掉,SMB Direct 被迫回退 TCP,延迟飙升。解决:交换机与网卡两端都要开 PFC,且只为优先级 3 开启,避免“全局暂停风暴”。
5. 卷与层:把盘做“对”比做好更重要
5.1 创建存储层(Tiers)与卷(数据库/日志/TempDB/备份)
$pool = Get-StoragePool -IsPrimordial:$false
# 5.1.1 创建性能/容量层
New-StorageTier -StoragePoolFriendlyName $pool.FriendlyName -FriendlyName PerfTier -MediaType SSD -ResiliencySettingName Mirror
New-StorageTier -StoragePoolFriendlyName $pool.FriendlyName -FriendlyName CapTier -MediaType SSD -ResiliencySettingName Parity
# 5.1.2 事务日志卷(3-way Mirror,WBC 16GB,ReFS 64K)
New-Volume -StoragePoolFriendlyName $pool.FriendlyName -FriendlyName SQL_LOG `
-FileSystem CSVFS_ReFS -Size 2TB -ResiliencySettingName Mirror `
-AllocationUnitSize 65536 -ProvisioningType Fixed `
-WriteCacheSize 16GB
# 5.1.3 热数据卷(3-way Mirror,列数/条带自定义)
New-VirtualDisk -StoragePoolFriendlyName $pool.FriendlyName -FriendlyName SQL_DATA_VD `
-ResiliencySettingName Mirror -WriteCacheSize 32GB -Interleave 262144 -NumberOfColumns 8 -Size 20TB
Initialize-Disk -VirtualDisk (Get-VirtualDisk SQL_DATA_VD)
New-Volume -FriendlyName SQL_DATA -FileSystem CSVFS_ReFS -AllocationUnitSize 65536 -Path "C:\ClusterStorage\Volume1"
# 5.1.4 冷数据卷(MAP:前端 20% Mirror + 后端 80% Parity)
New-Volume -StoragePoolFriendlyName $pool.FriendlyName -FriendlyName SQL_COLD `
-FileSystem CSVFS_ReFS -StorageTiers @(Get-StorageTier PerfTier, Get-StorageTier CapTier) `
-StorageTierSizes 2TB,8TB -AllocationUnitSize 65536
# 5.1.5 备份卷(ReFS + Integrity + 去重)
New-Volume -StoragePoolFriendlyName $pool.FriendlyName -FriendlyName SQL_BAK `
-FileSystem CSVFS_ReFS -Size 30TB -AllocationUnitSize 65536
Enable-DedupVolume -Volume "C:\ClusterStorage\VolumeX" -UsageType Backup
建议:数据库卷(SQL_DATA/SQL_LOG/TempDB)关闭 Integrity Streams:
Set-FileIntegrity -FileName "C:\ClusterStorage\Volume1\SQL_DATA" -Enable $false -IncludeStream:$true
备份卷和文件共享卷保持开启,并使用去重(2022 上对 ReFS/CSV 已成熟)。
5.2 CSV Cache 要不要开?
主要利好 Hyper-V 的未缓冲 I/O。SQL Server 默认使用缓冲 I/O,受益有限,还可能与内存策略冲突。
做法:不在 SQL 卷上开启 CSV Cache;只在需要的 Hyper-V 卷上按需开启。
6. Windows/SQL 层面:把系统“掰正”
# 6.1 电源计划:高性能
powercfg /S 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
# 6.2 关闭不必要的实时杀毒(为 SQL/CSV、备份目录设置排除)
# Defender 示例(按需)
Add-MpPreference -ExclusionPath "C:\ClusterStorage\Volume1","C:\Program Files\Microsoft SQL Server"
# 6.3 SMB 加密:数据中心内网可关闭以减小开销(按合规评估)
Set-SmbServerConfiguration -EncryptData $false
# 6.4 SQL 服务器本身的关键项(T-SQL/策略)
# - 启用Instant File Initialization(授予SQL服务账号“执行卷维护任务”)
# - 预分配日志/数据文件尺寸,避免频繁增长
# - TempDB 多文件均衡(<= 每核 1,先 8-12 观察),放在 Mirror 卷
# - MAXDOP/Cost Threshold 按业务校准,这里略
7. 基准与监控:用数据说话
7.1 使用 DiskSpd 压测(对 CSV 路径)
# 顺序读吞吐
diskspd.exe -c100G -b1M -d60 -o8 -t8 -r -Sh \\HKSQLCL1\ClusterStorage\Volume1\test1.dat > seq_read.txt
# 随机读(64K),模拟报表/索引
diskspd.exe -c100G -b64K -d60 -o32 -t8 -r -w0 -Sh \\HKSQLCL1\ClusterStorage\Volume1\test2.dat > rand_read.txt
# 混合写(64K 30%写),模拟夜间ETL
diskspd.exe -c100G -b64K -d60 -o16 -t16 -r -w30 -Sh \\HKSQLCL1\ClusterStorage\Volume1\test3.dat > mix_30w.txt
7.2 PerfMon/计数器(必看)
- Cluster CSVFs:CSVFS 读/写延迟
- PhysicalDisk/Storage Spaces:Avg. Disk sec/Read/Write,Current Disk Queue Length
- SMB Direct:RDMA Connections, Avg. Read/Write Queue
- S2D:Cluster Storage Spaces Direct(*)\Cache Write Latency、Rebuild Rate
- SQL:SQLServer:Buffer Manager、Databases: Log Flushes/sec & Log Flush Wait Time
8. 优化前后对比(来自现场数据)
| 指标 | 优化前(模板配置) | 优化后(本文方案) |
|---|---|---|
| 顺序读吞吐(1MB) | 3.2 GB/s | 7.1 GB/s |
| 随机读 IOPS(64K) | 92K | 238K |
| 混合读写 IOPS(64K/30%写) | 58K | 164K |
| 日志写入延迟(P99) | 12.7 ms | 2.6 ms |
| 夜间 ETL 峰值抖动 | 持续锯齿 | 平稳(偶见尖峰 < 5%) |
主要收益点(按贡献大到小):
- RDMA + PFC/ETS 正确落地(从 TCP 回退拉回 RDMA,延迟腰斩)
- 日志卷 3-way Mirror + 放大 WBC(写入瞬态吸收更稳)
- 条带/列数合适 + ReFS 64K + 关闭 Integrity Streams(减少小写放大与元数据开销)
- 电源/杀软/加密细节(避免“隐形刹车”)
9. 数据库文件放置与参数清单(可直接抄)
| 类型 | 卷 | 文件系统 | 冗余 | 建议 |
|---|---|---|---|---|
| 用户数据(高热) | SQL_DATA |
ReFS 64K | 3-way Mirror | 关闭 Integrity;预分配;索引隔离可考虑同卷不同子目录 |
| 事务日志 | SQL_LOG |
ReFS 64K | 3-way Mirror | 预分配大日志文件;增长固定步长;监控 Log Flush |
| TempDB | SQL_TEMP(可与 DATA 同卷分目录或单独卷) |
ReFS 64K | 3-way Mirror | 多文件等分,初始 8–12 个;文件大小一致 |
| 冷/历史数据 | SQL_COLD |
ReFS 64K | MAP(20%/80%) | 报表与归档,定期重建索引/压缩 |
| 备份 | SQL_BAK |
ReFS 64K | Parity | 开 Integrity + 去重;后台校验 |
SQL 侧:
- 授权服务账号“执行卷维护任务”(IFIs)
- 数据/日志预分配,禁用自动小步增长
- trace flag 1117/1118 在新版本已不再需要,采用默认行为即可
- MAXDOP 与 Cost Threshold 按硬件与查询形态实测
10. 我踩过的坑(以及怎么爬出来)
固件不一致 → 间歇性 SCSI 重置
现象:Event ID 129/153,延迟尖刺。
解法:统一 SSD/NVMe 固件与 HBA/Backplane 固件,Update-StorageFirmware -All;必要时黑名单问题批次。
混用 4Kn 与 512e
现象:对齐/队列深度表现异常。
解法:集群内统一扇区规格;不混搭。
RDMA 配置“一边开一边没开”
现象:RDMA 连接非对称,SMB Direct 回退。
解法:交换机/网卡两端同时开 PFC,优先级一致,Jumbo 全链路一致。
WBC 过小导致夜间写入抖动
现象:ETL 高峰期间写入阶梯状卡顿。
解法:针对日志/热数据卷放大 WBC 至 16–32GB,观察“写入吸收”曲线。
在 SQL 卷开启 CSV Cache
现象:收益不明显甚至内存争用。
解法:SQL 卷关闭 CSV Cache,仅在 Hyper-V/VDI 卷上启用。
杀毒/实时扫描未做排除
现象:无规律延迟尖刺。
解法:对 CSV 路径和 SQL 安装/数据目录做排除。
11. 一套“可复用”的上线检查清单
- Test-Cluster 全绿
- RDMA:Get-SmbClientNetworkInterface 显示 RSS/Direct Enabled;netstat -xan 有 RDMA 通道
- 交换机:PFC=on(prio 3),ETS 配置一致,Jumbo=9014
- ReFS 卷:Allocation Unit=64K;数据库卷 Integrity=off;备份卷 Integrity/Dedup=on
- WBC:日志/热数据卷 ≥ 16GB
- SQL:IFIs 打开;数据/日志预分配;TempDB 多文件等分
- Defender/第三方杀软排除路径就位
- PerfMon 基线一套(白天/夜间各 60 分钟)
12. 复盘与回报(生产观测 7 天)
夜间 ETL 峰值窗口从 02:00–04:00 的“锯齿”变为平台型曲线,P99 延迟从 12–15 ms 降到 2–3 ms
白天 OLTP 平均响应缩短 18–25%
备份窗口利用 ReFS + 去重,平均节省存储 38–52%(取决于备份策略)
13. 夜班后的机房清晨
凌晨 5:40,KVM 上的曲线终于平了。机房走廊尽头透进来一点浅蓝,像把风从冷通道里吹了出来。我把那套 PowerShell 脚本传到配置库,给下一位夜班值守留了句话:“S2D 不可怕,怕的是‘差一点点’。”
那一夜,我们把“差一点点”补上了:RDMA 的一个开关,WBC 的几个 GB,ReFS 的一个勾。数据库 I/O 性能不是凭空长出来的,它是被一项项基本功“对齐”出来的。
希望这份实操笔记,能让你下一次站在机柜前的时候,少流点汗、少挨几通电话。
附录:关键命令速查
# 查看 RDMA/SMB Direct 状态
Get-SmbClientNetworkInterface
Get-SmbMultichannelConnection
# 查看 S2D 健康
Get-StorageSubSystem *Cluster* | Get-StorageHealthReport
# 查看卷与虚拟磁盘参数
Get-VirtualDisk | ft FriendlyName,ResiliencySettingName,Interleave,NumberOfColumns,WriteCacheSize
Get-Volume | ft DriveLetter,FriendlyName,FileSystem,AllocationUnitSize
# 调整写回缓存
Set-VirtualDisk -FriendlyName SQL_LOG_VD -WriteCacheSize 16GB
# 观察 CSV/SMB 性能计数器(示例)
typeperf "\Cluster CSVFS File System(_Total)\Avg. sec/Write" -sc 60
typeperf "\SMB Direct Connection(_Total)\Current Send Queue Depth" -sc 60