如何在香港服务器的 Windows Server 2016 上通过“动态磁盘扩展”,解决存储与性能双瓶颈

清晨 6:40,我在香港葵涌机房的冷风里打了个喷嚏。柜门刚开,一排蓝灯像是在催促:D: 盘只剩不到 2% 了,业务是跨境 API 与日志聚合,夜里流量尖峰叠加 ETL 落盘,阈值报警把我从床上叫起。客户一句话——“别停业务,先把容量顶上去,再把吞吐上去”——决定了今天的方案走向:先用 Windows 动态磁盘做“在线扩容(Spanned/Striped)”,稳住容量与吞吐,再分时优化。
下面是我那天从评估、上架、扩容到压测与复盘的完整记录,既写给刚入行的同学,也给老手一个细节对照。
一、现场与硬件参数(真实环境)
| 项 | 明细 |
|---|---|
| 机房 | 香港葵涌(多线 BGP,10GbE 口上联),远程带外 iDRAC |
| 机型 | Dell PowerEdge R730(2U) |
| CPU | 2 × Intel Xeon E5-2680 v4(14C/2.4GHz) |
| 内存 | 128GB DDR4-2133 |
| 系统盘 | 2 × 480GB SATA SSD,硬件 RAID1(PERC H730P) |
| 数据盘(存量) | 1 × 1.92TB SATA SSD(直通 JBOD) → 挂 D:(日志+中间结果) |
| 新增盘(容量) | 1 × 1.92TB SATA SSD(JBOD) |
| 新增盘(性能) | 2 × 1.6TB NVMe U.2(Intel P4510,PCIe 3.0 x4,主板直连) |
| 网卡 | 2 × 10GbE(Intel X520) |
| 操作系统 | Windows Server 2016 Datacenter(1607,已打到最新补丁) |
设计意图:SATA SSD 用作“快速补容量”的拼接(Spanned);NVMe 单独做“条带(Striped/RAID-0)”承载热路径(临时表、缓存、写热点)。
二、为什么选“动态磁盘扩展”而非先上 Storage Spaces 或硬 RAID
时间窗口有限:不停业务扩容,动态磁盘(Dynamic Disk)可在 Windows 2016 原生完成“在线扩容与条带”,无重启、无改存储栈。
异构磁盘混挂:短期用 Spanned(跨盘拼接) 快速加容量;性能侧另建 Striped(条带/RAID-0) 给热数据。
直通 JBOD:控制器开 HBA/Non-RAID,避免“软上软”(硬 RAID 再叠动态条带)导致不可控延迟。
注意:长期视角我更推荐 Storage Spaces(或硬 RAID10) 做高可用;本文聚焦于“救火与提速”的快速落地路径,并把风险与回滚写清楚。
三、变更前健康检查与回滚预案(SOP)
确认系统/引导卷(C:)不参与跨盘扩展
Windows 动态磁盘不允许将系统/引导卷从单盘跨到其他磁盘(会变灰不可选)。C: 一律只在本盘扩容。
备份与快照
应急文件备份(最热数据 + 配置):
New-Item -ItemType Directory -Force C:\Backup
wbadmin start backup -backupTarget:E: -include:D: -quiet
逻辑备份:数据库/队列做一致性导出;Elastic/日志分片标记可再生。
一致性与坏道自检
chkdsk D: /scan
Get-Volume | ft DriveLetter,FileSystem,HealthStatus,Size,SizeRemaining
Get-Disk | ft Number,FriendlyName,PartitionStyle,OperationalStatus,Size
回滚计划
Spanned 卷任一成员盘故障即整卷不可用 → 将热数据与关键数据分卷,Spanned 仅承载可丢弃型文件(缓存、中间结果、可再生日志)。
条带卷(RAID-0)仅放可再生或可重建数据(如临时文件、ETL 落地中转、数据库 tempdb)。
四、扩容策略设计(两步走)
步骤 A:用 Spanned(跨盘拼接) 快速把 D: 扩到可用水位
目标:把新加的 1.92TB SATA SSD 加入现有 D:,业务不重启。
注意:Spanned 不提升吞吐,但能立刻把容量拉满;风险是单盘故障致全卷不可用→只放“可再生数据”。
步骤 B:用 Striped(条带/RAID-0) 在 NVMe 上做 F:,承载高 IO 路径
目标:在 2 × NVMe 上创建条带卷 F:,把写热点(临时表、缓存、落地日志)迁入,显著提升随机 IOPS 与顺序吞吐。
五、上架与初始化(带外 + OS 层)
上架后在 iDRAC 确认新盘在线、SMART 正常
控制器改 JBOD/Non-RAID 直通(已有阵列勿动)
Windows 识别硬盘
# 观察新增磁盘(假设号为 2、3、4)
Get-Disk | ft Number,FriendlyName,PartitionStyle,OperationalStatus,Size
六、把新盘转换为动态磁盘(DiskPart 批处理最稳)
PowerShell 没有官方直达 cmdlet 转“动态”,实际用 DiskPart 更可靠。
脚本:prep_dynamic.txt
select disk 2
online disk
attributes disk clear readonly
clean
convert gpt
convert dynamic
select disk 3
online disk
attributes disk clear readonly
clean
convert gpt
convert dynamic
select disk 4
online disk
attributes disk clear readonly
clean
convert gpt
convert dynamic
执行:
diskpart /s C:\scripts\prep_dynamic.txt
解释:新盘统一 GPT;convert dynamic 将其变更为动态磁盘。已有业务盘(装着 D: 的那块)若是基本磁盘,可在不停业务情况下右键“转换为动态磁盘”。
七、步骤 A:将 D: 在线扩展为 Spanned(跨盘拼接)
GUI 路径(最直观)
Win + X → 磁盘管理(Disk Management)。
右键 D:(已为动态卷的“简单卷”)→ 扩展卷…(Extend Volume)。
选择**新加的动态磁盘(Disk 2)**未分配空间,加入选择列表,设定扩展大小。
确认 → 进度条结束,D: 容量立刻增加,文件系统自动扩展(NTFS)。
DiskPart(命令行批量)
前提:D: 已是 动态卷,且另一个动态磁盘(Disk 2)存在未分配空间。
diskpart
list volume
select volume D
extend
exit
在动态卷上,extend 会把选定卷扩展到其他动态磁盘的空闲空间(默认吃到上限)。
如需精准控制大小,建议 GUI 操作;DiskPart 对跨盘精确 size 的控制不如 GUI 直观。
验证
Get-Volume -DriveLetter D | fl DriveLetter,FileSystem,Size,SizeRemaining,HealthStatus
现场坑:如果 D: 仍是基本磁盘的简单卷,扩展向导只允许用同一磁盘尾部的未分配空间,跨盘选项会变灰。解决:先把承载 D: 的磁盘转换为动态磁盘,再扩展。
八、步骤 B:在 NVMe 上创建 Striped(条带/RAID-0)卷 提升吞吐
脚本:create_nvme_stripe.txt
select disk 3
clean
convert gpt
convert dynamic
select disk 4
clean
convert gpt
convert dynamic
create volume stripe disk=3,4
format fs=ntfs label="NVMe_Stripe" unit=64k quick
assign letter=F
执行:
- diskpart /s C:\scripts\create_nvme_stripe.txt
- create volume stripe:在 Disk 3 与 Disk 4 上做条带(RAID-0)。
- unit=64k:将 NTFS 簇大小设为 64K,适合大块顺序写与数据库日志/数据文件。
把热点迁到 F:
robocopy D:\hotdata F:\hotdata /MIR /COPY:DAT /R:1 /W:1 /MT:16 /LOG:C:\Logs\robocopy_hotdata.log
迁移完成后,应用的临时/缓存/日志目录切到 F:(注意停写窗口或应用级热切换能力)。
九、基线与扩容后压测(diskspd 命令与样例数据)
工具:diskspd.exe(微软官方)
测试方式:各跑 60s,禁用缓存(-Sh),预创建 20GB 测试文件(不污染生产路径)
命令
:: 预创建测试文件
diskspd -c20G D:\bench\io.dat
diskspd -c20G F:\bench\io.dat
:: 4K 随机读(80%读 / 20%写),并发 8 线程,每线程 32 深度
diskspd -b4k -r -w20 -t8 -o32 -d60 -Sh D:\bench\io.dat
diskspd -b4k -r -w20 -t8 -o32 -d60 -Sh F:\bench\io.dat
:: 128K 顺序读
diskspd -b128k -r -w0 -t4 -o8 -d60 -Sh D:\bench\io.dat
diskspd -b128k -r -w0 -t4 -o8 -d60 -Sh F:\bench\io.dat
结果(现场样例,供参考)
| 卷 | 类型 | 4K 随机混合 IOPS | 平均延迟 | 128K 顺序读吞吐 |
|---|---|---|---|---|
| D:(扩容前) | 单盘 SATA SSD | ~38,000 | ~2.3 ms | ~520 MB/s |
| D:(Spanned 后) | Spanned(2×SATA,容量叠加) | ~39,000 | ~2.2 ms | ~520 MB/s |
| F:(新增) | Striped(2×NVMe,RAID-0) | ~620,000 | ~0.35 ms | ~6.2 GB/s |
解读:Spanned 仅解决容量,不显著增吞吐(IO 仍落在单块或非并行路径);Striped 把顺序吞吐与随机 IOPS 直接拉满,适合把写热点与临时高并发放上去。
十、线上迁移与业务无感策略
分卷治理:
D:(Spanned)仅承载可再生数据:例如压缩前日志、ETL 中间结果、临时对象。
F:(Striped)承载热点:数据库 tempdb、应用缓存目录、打点/落地队列。
应用配置切换:
数据库:修改 tempdb 数据文件与日志路径到 F:,计划重启服务窗口。
日志:NLog/Log4j/Serilog 路径平滑切换;双写 1h 后停旧路径。
监控阈值:
基于盘符维度的 SizeRemaining 告警;IOPS/延迟趋势看 perfmon 指标(\PhysicalDisk(*)\Avg. Disk sec/Read 等)。
数据生命期:
D: 定期清理,Logstash/Fluentd 采集到对象存储/归档后即删。
十一、踩坑与解决(当场记录)
坑 1:C:(系统盘)无法跨盘扩展
现象:扩展向导中无法选其他磁盘,按钮变灰。
解决:不要试图把系统/引导卷做 Spanned/Striped。若确需扩容系统盘,只能在同盘留白、或做系统迁移。
坑 2:控制器仍是硬 RAID,叠加动态条带
风险:双层条带导致不可预期的对齐与写放大。
解决:新盘一律 JBOD/Non-RAID 直通;已有阵列不动。
坑 3:Spanned 宕一盘全卷丢
规避:Spanned 只放可再生数据;核心数据放硬 RAID10 或动态镜像(Mirrored);或后续迁至 Storage Spaces。
坑 4:不同介质混拼(SATA+NVMe)
现象:延迟被慢盘拖累。
解决:同类型盘做 Spanned/Striped;NVMe 只与 NVMe 组条带。
坑 5:对齐与簇大小
现象:小簇在大顺序写场景下放大碎片。
解决:大文件/数据库类卷用 64K 簇(见前述 format 参数)。
坑 6:在线扩容后未刷新容量
解决:Get-Volume 检查;如应用仍读旧容量,重启对应服务或触发重新打开句柄。
十二、运维小抄(命令合集)
# 查看磁盘/卷/分区
Get-Disk | ft Number,FriendlyName,PartitionStyle,OperationalStatus,Size
Get-Partition | ft DiskNumber,PartitionNumber,DriveLetter,Type,Size
Get-Volume | ft DriveLetter,FileSystemLabel,FileSystem,HealthStatus,Size,SizeRemaining
# 快速查看延迟/IOPS(PerfMon 计数器名参考)
typeperf "\PhysicalDisk(_Total)\Avg. Disk sec/Read" -sc 5
typeperf "\PhysicalDisk(_Total)\Avg. Disk sec/Write" -sc 5
# 检查 VSS(扩容前最好确认)
vssadmin list writers
vssadmin list shadows
# robocopy 常用(迁移热点)
robocopy D:\hotdata F:\hotdata /MIR /COPY:DAT /R:1 /W:1 /MT:16 /LOG:C:\Logs\robocopy_hotdata.log
十三、什么时候该上“镜像/RAID-5/Storage Spaces”?
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Spanned(拼接) | 最快扩容,不停机 | 任何一盘坏→全卷不可用 | 可再生数据、临时中转 |
| Striped(RAID-0) | 最大吞吐/IOPS | 无冗余 | 热路径、临时/缓存 |
| Mirrored(镜像) | 单盘坏不丢卷 | 容量减半 | 关键数据,写多读多 |
| RAID-5(动态盘) | 容量/冗余折中 | 写入有校验开销 | 读多写少场景 |
| Storage Spaces | 策略灵活、可脱离动态盘 | 需要规划/学习曲线 | 中长期规范化治理 |
十四、复盘与收益
容量:D: 从 1.92TB → 3.84TB(Spanned),报警消失,ETL 不再打满。
性能:F:(2×NVMe RAID-0)把顺序吞吐提到 6GB/s 级别、混合 4K IOPS 达 60 万+,写热点切走后,D: 的平均写延迟从 8-12ms 降到 2-3ms。
风险可控:严格数据分层(可再生 vs. 关键),并预留后续把 D: 迁到 Storage Spaces/RAID10 的窗口。
十五、标准变更记录模板(可直接套用)
变更目的:D 盘容量告急 + 吞吐不足,采用动态磁盘扩容(Spanned)+ NVMe 条带(Striped)方案。
影响范围:无停机,日志/缓存路径迁移 1 小时双写。
风险评估:Spanned 任一盘故障致卷不可用;条带无冗余;通过数据分层+备份规避。
回滚方案:保留原路径,双写期间可切回;保留备份;必要时卸载条带卷、恢复旧配置。
验证点:Get-Volume 容量/健康;diskspd 压测;业务延迟与错误率监控。
十六、结尾:凌晨 2:15 的电梯口
做完最后一轮 diskspd,日志落地延迟稳定在 20ms 内。机房电梯缓慢上行,我把工单备注补齐:Spanned 只装中间结果,NVMe 条带跑热点;下周窗口把长期可靠性迁到 Storage Spaces。手机屏幕上,客户回了个“👌”。这活儿并不华丽,但在不停机的前提下,容量顶住了、性能抬上去了、风险被写清楚了——这就是运维该有的节奏感。
第二天早上,我把这份记录整理出来——希望你在凌晨被叫醒的时候,也能有条不紊地把一套动态磁盘扩展走到位。
附:执行顺序速记(TL;DR)
- 备份 + 自检(wbadmin / chkdsk / Get-Volume)
- 新盘转 GPT + Dynamic(diskpart 脚本)
- D: 转动态并 Spanned 扩容(GUI 或 extend)
- 2×NVMe 建 Striped/RAID-0 → F:(create volume stripe,unit=64k)
- 热数据迁移到 F:(robocopy 双写/平滑切换)
- 压测与监控(diskspd / perfmon / 告警阈值)
- 复盘与长期方案(Storage Spaces/RAID10 规划)