香港服务器使用Windows Server 2019时,如何针对Samsung PM1733 NVMe SSD优化文件系统I/O调度?

凌晨两点,香港机房的机柜门刚开,一排 2U 机器的橙绿灯在风里眨眼。我这次要优化的是一台落到香港节点的内容分发/虚拟化混合宿主:Windows Server 2019,数据盘是两块 Samsung PM1733(U.2,PCIe 4.0 x4,3.84TB,1 DWPD,支持双端口与 PLP)。按规格单盘顺序读最高 7 GB/s、随机读最高 150 万 IOPS,属于当年的顶级企业盘;并且带电容掉电保护(PLP),对服务器端写缓存策略的放开很关键。
业务方的诉求很朴素:
- VHDX/镜像仓库 + 日志与小文件混部;
- 白天主要大文件顺序读写、夜里虚拟化备份/合并产生大量小块随机;
- 目标:把 4K 随机延迟拉低(P99 < 1ms),把 128K 顺序带宽打满,别再让 CPU 在 I/O 上空转。
环境与基线
硬件(节选)
| 项 | 规格 |
|---|---|
| 机型 | 2U 单节点(双路 Xeon/或单路 EPYC,PCIe Gen4 背板) |
| 系统盘 | SATA DOM |
| 数据盘 | Samsung PM1733 3.84TB × 2,U.2,PCIe 4.0 x4,1 DWPD,PLP |
| 网卡 | 25GbE × 2(iWARP/RDMA 关闭,本次与磁盘无关) |
软件
| 项 | 版本/说明 |
|---|---|
| OS | Windows Server 2019 Datacenter(最新补丁) |
| NVMe 驱动 | Microsoft StorNVMe(系统自带) |
| 测试工具 | DiskSpd(微软出品) |
基线测试(未优化,单盘直通卷)
使用 DiskSpd 进行 warmup 后测试(命令见下文),仅示例一组结果(实际请以你现场为准):
| 场景 | 指标 | 数值(未优化) |
|---|---|---|
| 4K 随机读(8 线程,QD=64,总 QD=512) | IOPS / 平均延迟 | ~860k / 0.95 ms |
| 4K 随机写(8×64) | IOPS / 平均延迟 | ~230k / 2.6 ms |
| 128K 顺序读(8×4) | 带宽 | ~5.4 GB/s |
| 128K 顺序写(8×4) | 带宽 | ~3.0 GB/s |
先讲原理:在 Windows 上“调度 I/O”意味着什么?
和 Linux 上能切换 I/O 调度器不同,Windows Server 的磁盘 I/O 路径是“应用 → 文件系统/缓存管理器 → 卷管理 → Storport/StorNVMe → 控制器/设备”。NVMe 设备天生多队列、每核一队;要把盘喂满,更关键的是线程模型与 outstanding I/O(队列深度)的匹配,外加合适的文件系统与缓存策略。微软在 SDC 的演讲与文档里也一再强调使用 DiskSpd 进行路径压测与调优验证。
步骤一:固件/驱动与设备状态确认
查看 NVMe 盘固件与插槽信息
Get-PhysicalDisk | Select FriendlyName, BusType, MediaType, Size, HealthStatus
Get-Disk | Select Number, FriendlyName, FirmwareVersion, OperationalStatus
# 查看固件槽位/活动镜像(NVMe 支持多固件插槽)
$pd = Get-PhysicalDisk | ? {$_.FriendlyName -match "SAMSUNG"}
$pd | Get-StorageFirmwareInformation
其中 Get-StorageFirmwareInformation 能显示 NVMe 固件槽、活动镜像与可写槽位,便于后续升级校验。
必要时升级固件
企业盘建议使用三星数据中心工具(Samsung DC Toolkit)或厂商工具链批量刷写,支持命令行与离线模式(生产前做,注意维护窗口与备份)。
示例(工具命令片段,具体以手册为准):
DCToolkit --disk 1 --firmware-update --path <fw-file>
说明:PM1733 自带 PLP(掉电保护),这对后续启用更激进的写缓存策略是前提条件之一。
步骤二:电源与节能策略(别让 CPU 把 I/O“省”没了)
将电源计划切换为 高性能(禁用可能的节能抖动)。
powercfg /setactive SCHEME_MIN # 高性能
(也可以用 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c 这个 GUID 直接激活。)
在“高性能”计划中,将 PCI Express → 链路状态电源管理 设为“关闭”(图形界面操作,避免链路省电影响 NVMe 时延)。
步骤三:写缓存策略(配合 PLP)
在 设备管理器 → 磁盘驱动器 → PM1733 → 属性 → 策略 中:
勾选 “启用设备上的写入缓存”;
结合 PLP 与机柜 UPS 条件,可考虑勾选 “关闭 Windows 对设备的写入缓存缓冲区刷新”,以获得更激进的写合并与更低写放大。(没有 PLP/UPS 时不要勾选这条!)
步骤四:文件系统与簇大小(NTFS / ReFS 的取舍)
怎么选?
以虚拟化/大文件顺序 I/O 为主(VHDX、镜像仓库):
- NTFS:簇 64K,简单直接,工具兼容性最好;
- ReFS:默认簇 4K 对大多数场景合适;大顺序 I/O 可考虑 64K(尤其大块顺序写为主)。
SQL/日志盘:官方与业界长期建议 NTFS 64K(数据库页对齐/减少簇管理开销)。
格式化示例(PowerShell)
# NTFS 64K(适合 VHDX/SQL/大文件)
Format-Volume -DriveLetter X -FileSystem NTFS -AllocationUnitSize 65536 -NewFileSystemLabel 'DATA_NTFS_64K'
# ReFS 64K(顺序 I/O 偏重时考虑;否则默认4K)
Format-Volume -DriveLetter Y -FileSystem ReFS -AllocationUnitSize 65536 -NewFileSystemLabel 'DATA_REFS_64K'
验证簇大小/扇区信息
fsutil fsinfo ntfsinfo X:
fsutil fsinfo sectorinfo X:
关注 Bytes Per Cluster(簇)、以及物理扇区信息(某些现代盘/控制器的原子扇区可能为 4K)。
步骤五:ReFS 的完整性流(Integrity Streams)与虚拟化/备份
ReFS 提供 Integrity Streams,可对用户数据计算校验并在镜像/校验环境下自修复,但它会带来额外的 CPU 与 I/O 放大。在承载 VHD/VHDX、备份仓库 等热点大文件时,通常建议关闭完整性流:
# 关闭整卷默认(根目录)
Get-Item 'Y:\' | Set-FileIntegrity -Enable $false
# 已有文件批量关闭
Get-ChildItem -Recurse 'Y:\' | Set-FileIntegrity -Enable $false
(根据工作负载再选择性开启。)
步骤六:多盘并行时的 Storage Spaces(条带、列数与对齐)
若你有 多块 PM1733 做条带或镜像,创建 Storage Spaces 的时候要把三件事对齐:
- Interleave(条带块大小):默认 256KB(可用 PowerShell 创建时指定)。
- 列数(NumberOfColumns):决定同时条带的盘数,与吞吐正相关(创建时指定)。
- 卷的簇大小:最好让“数据条带总宽度 = 列数×Interleave”能被文件系统簇整除,减少跨条带写放大。
- 例如 4 列 × 256KB = 1MB,那么用 NTFS 64K 或 ReFS 64K 都能良好对齐。
- Parity(校验)卷写入慢的老痛点,很多时候就是条带/簇不对齐导致的。
创建示例(双盘 Simple 条带,仅演示)
$pool = Get-StoragePool -IsPrimordial:$false
New-VirtualDisk -StoragePoolFriendlyName $pool.FriendlyName `
-FriendlyName NVMe_Simple `
-ResiliencySettingName Simple `
-NumberOfColumns 2 `
-Interleave 262144 `
-UseMaximumSize
Initialize-Disk -VirtualDisk (Get-VirtualDisk NVMe_Simple)
New-Volume -FriendlyName DATA -FileSystem NTFS -AllocationUnitSize 65536 -DriveLetter X
步骤七:监控与压测方法(Perfmon + DiskSpd)
建议的 Perfmon 计数器(物理盘或目标卷):
- PhysicalDisk\Avg. Disk sec/Read / Write(时延);
- PhysicalDisk\Disk Bytes/sec(吞吐);
- PhysicalDisk\Avg. Disk Queue Length(队列深度);
- CPU:Processor(_Total)\% Processor Time。
这些是官方/厂商文档中常用的衡量项。
DiskSpd 常用命令模板(X 盘为测试卷;-Sh 关闭系统缓存,-L 打印延迟分布):
:: 预热(顺序写,避免读放大)
diskspd -c50G -b128K -d20 -Sh -w100 -L X:\pre.dat
:: 4K 随机读,8 线程 * 每线程 QD=64(总 QD=512),持续60秒
diskspd -b4K -r -d60 -o64 -t8 -Sh -L X:\test.dat
:: 4K 随机写(注意写放大)
diskspd -b4K -r -d60 -o64 -t8 -w100 -Sh -L X:\test.dat
:: 128K 顺序读
diskspd -b128K -d60 -o4 -t8 -Sh -L X:\test.dat
:: 128K 顺序写
diskspd -b128K -d60 -o4 -t8 -w100 -Sh -L X:\test.dat
工具下载与使用说明见微软官方仓库。
优化后的对比(示例,思路与比例更重要)
在完成高性能电源计划、写缓存策略(基于 PLP)、NTFS 64K/或 ReFS 64K(按场景)、以及**(如有)Storage Spaces 条带/列对齐** 后,我在这台香港节点上得到的 样本结果(同样的测试模型):
| 场景 | 指标 | 未优化 | 优化后 |
|---|---|---|---|
| 4K 随机读(8×64) | IOPS / 平均延迟 | ~860k / 0.95 ms | ~1.20M / 0.70 ms |
| 4K 随机写(8×64) | IOPS / 平均延迟 | ~230k / 2.6 ms | ~310k / 1.9 ms |
| 128K 顺序读(8×4) | 带宽 | ~5.4 GB/s | ~6.6–6.9 GB/s |
| 128K 顺序写(8×4) | 带宽 | ~3.0 GB/s | ~3.6–3.8 GB/s |
这些数字受 CPU 代际、主板背板、驱动栈与线程模型影响很大,但提升方向与幅度在多台节点上是一致的:电源/缓存/文件系统对齐到位后,延迟与吞吐都能上一个台阶。PM1733 作为 PCIe 4.0 盘,本身的上限就摆在那里。
典型坑与现场解法
“写缓存缓冲区刷新”要不要关?
有 PLP + UPS → 可考虑关闭(提升写聚合与顺序写性能)。
无 PLP 或对一致性极敏感 → 不要关。
操作入口与 PLP 说明参考上文链接。
ReFS 完整性流导致 VHDX/备份仓库写入抖动
关闭目标路径的 Integrity Streams,写入延迟会明显稳定(尤其合并/块克隆场景)。
Storage Spaces Parity 写慢
很多案例是 Interleave、列数与簇大小没对齐(见“步骤六”);Parity 本身写放大更大,业务允许的话尽量用 Mirror 或 Simple + 上层做冗余。
扇区大小/对齐
用 fsutil fsinfo sectorinfo 确认 PhysicalBytesPerSectorForAtomicity/Performance 为 4096;遇到异常时先查控制器/固件兼容性再动注册表。(Windows 11 上与部分 NVMe 的 4Kn 行为曾经影响 SQL 安装,虽然本机是 Server 2019,但检查一遍心里更有底。)
线程/队列不合理
NVMe 多队列的优势需要多线程+足够 QD才能吃到;DiskSpd 的 -t 与 -o 是你最该先动的两个旋钮。微软与 SNIA 的资料里也用它做评估基准。
附:我用的检查/格式化/压测脚本片段(可直接抄)
# 0. 电源计划:高性能
powercfg /setactive SCHEME_MIN
# 1. 盘/固件信息
Get-PhysicalDisk | Select FriendlyName, BusType, MediaType, Size, HealthStatus
Get-Disk | Select Number, FriendlyName, FirmwareVersion, OperationalStatus
(Get-PhysicalDisk | ? {$_.BusType -eq 'NVMe'}) | Get-StorageFirmwareInformation
# 2. 新卷(NTFS 64K)
Initialize-Disk -Number 2 -PartitionStyle GPT
New-Partition -DiskNumber 2 -UseMaximumSize -DriveLetter X
Format-Volume -DriveLetter X -FileSystem NTFS -AllocationUnitSize 65536 -NewFileSystemLabel 'DATA_NTFS_64K'
# 3. 扇区/簇确认
fsutil fsinfo ntfsinfo X:
fsutil fsinfo sectorinfo X:
# 4. DiskSpd 示例(4K 随机读)
diskspd -b4K -r -d60 -o64 -t8 -Sh -L X:\test.dat
(DiskSpd 下载与说明:微软官方 仓库;PowerShell 存储/固件 cmdlet 见微软文档。)
做完这一切,Perfmon 上那条“Avg. Disk sec/Read/Write”曲线更平了,P99 尖刺也不再扎眼。广州同事凌晨发来消息说夜间备份合并时间从 1 小时出头降到了 40 分钟以内;CDN 汇总任务也不再卡在 I/O 等待。
我把机柜门关上,冷风被挡回了冷通道,风声一下子小了。掏出口袋里那张小纸条,勾掉最后一项“ReFS 完整性流确认”。电梯里,手机嗡了一下:白天的变更单回执“性能已恢复,用户无感”。这类事,第一次你会觉得只是调参;做多了,就知道它其实是在替团队把确定性从机房带回会议室。