如何在香港服务器 Windows 系统中把 RDMA 和高速网卡“绑”在一起,干掉分布式存储里的延迟

凌晨 2:17,香港荔枝角机房,我守着四台刚上架的 Windows Server 2022 节点,CSV 卷上的延迟图像心电图一样乱跳:p99 过 8ms,业务的异步复制已经开始掉速。交换机是双上联的 100GbE,理论带宽飘亮,但 SMB3 的 TCP 链路明显吃不满,还把 CPU 烧得通红。
“要么就把 RDMA 搞起来,要么今晚谁也别想下班。”我对同事叹了口气,把手里的咖啡放到机柜门上,开始把 RDMA 和高速网卡硬生生地“绑”在一起。
一、目标与场景
目标:在 Windows 分布式存储(基于 SMB Direct / Storage Spaces Direct, S2D)场景中,将 RDMA(RoCEv2)与 100GbE 网卡联合调优,显著降低延迟、减轻 CPU 占用,并提升 IOPS/吞吐。
平台:香港机房,跨两台 ToR 交换机,L2 同域,DCB(PFC/ETS/ECN)已可用。
业务:Hyper-V 虚机落在 S2D 的 CSV 卷上,后台用 SMB Direct 在节点间复制与重平衡。
二、硬件与软件清单(实测环境)
| 组件 | 型号/版本 | 关键点 |
|---|---|---|
| 服务器 | 4× 1U 节点(2×Intel Xeon Gold 6330, 512GB RAM) | NUMA 2 节点,BIOS 里 C-States 关,Turbo 开 |
| 系统盘 | 2× SATA SSD (RAID1) | 系统与数据分离 |
| 数据盘 | 8× NVMe U.2 3.84TB(Mixed Use) | S2D: 2 盘做缓存,其余做容量层 |
| 网卡 | Mellanox ConnectX-5 EN(MCX516A-CDAT, 2×100GbE) | 支持 RoCEv2,固件同版本 |
| 交换机 | 2× 100GbE ToR(例:Arista 7050X3 / NVIDIA SN2700 同级) | 开 DCBX, PFC(pri 3), ETS, ECN |
| 操作系统 | Windows Server 2022 Datacenter (Core) | 含 S2D 与 SMB Direct |
| 驱动 | Mellanox WinOF-2 驱动(与固件匹配) | 保持一致性,避免奇怪的小抖动 |
| 协议 | SMB Direct (SMB over RDMA) | S2D 内部复制与重平衡走 RDMA |
经验:固件、驱动、交换机 OS 三者一定要对齐版本,老版本常见 Pause Storm、CNP 行为异常、ECN 标记不一致等坑。
三、网络与 QoS 设计(RoCEv2 + DCB)
3.1 VLAN 与寻址
存储专用 VLAN:与管理、业务流量隔离(如 VLAN 3101),只跑 SMB 445。
每节点两条 RDMA 物理口:分别上联不同 ToR,ECMP/LACP 由上层设计决定;我这里做 L2 多活,不跨 L3。
3.2 DCB 策略(重点)
PFC:仅对 Priority 3 开启(SMB Direct 使用的优先级),其余优先级关闭 PFC,避免“全场拥塞”。
ETS:为 Priority 3 预留 ≥50% 的带宽权重。
ECN:交换机与网卡都启用,避免过度依赖 PFC。
MTU:9000(端到端一致)。
原则:只为 SMB RDMA 开启 PFC。所有优先级开 PFC 的配置极易导致 Pause 风暴(亲测满屋灯光跟过年似的)。
四、Windows 端安装与启用 RDMA
4.1 安装角色/功能(PowerShell)
# 基础功能:DCB, 文件服务, 以及故障排除常用组件
Install-WindowsFeature Data-Center-Bridging, FS-FileServer, RSAT-Feature-Tools -IncludeManagementTools
# 检查 RDMA 能力
Get-NetAdapterRdma
4.2 Mellanox 驱动与高级参数
安装 WinOF-2 对应版本驱动。
确认高级属性:
- RoCE mode = v2
- Jumbo Packet = 9014
- Interrupt Moderation 适中(RDMA 对 CPU 打断敏感)
- RSS 仅对非 RDMA 流量;RDMA 本身零拷贝,不走 TCP 栈
# 统一命名网卡,避免脚本跑飞
Rename-NetAdapter -Name "Ethernet 3" -NewName "RDMA1"
Rename-NetAdapter -Name "Ethernet 4" -NewName "RDMA2"
# 开启 RDMA
Enable-NetAdapterRdma -Name "RDMA1","RDMA2"
# MTU/巨帧
Set-NetAdapterAdvancedProperty -Name "RDMA1","RDMA2" -RegistryKeyword "*JumboPacket" -RegistryValue 9014
提示:部分 Mellanox 固件的 RoCE/ECN 需用厂商工具(WinMFT)设置;保持与交换机端一致的 ECN 阈值策略。
4.3 Windows DCB(QoS)策略(关键)
# 1) 为 SMB 设置 802.1p 优先级(Priority 3)
New-NetQosPolicy "SMB" -NetDirectPortMatchCondition 445 -PriorityValue8021Action 3
# 2) 开启 PFC,仅对 Priority 3
Enable-NetQosFlowControl -Priority 3
Disable-NetQosFlowControl -Priority 0,1,2,4,5,6,7
# 3) ETS:给 pri 3 分配带宽权重(如 60%)
New-NetQosTrafficClass -Name "SMB" -Priority 3 -BandwidthPercentage 60 -Algorithm ETS
# 4) DSCP(可选,与网络策略对齐)
Set-NetQosDscpState -State Enabled
New-NetQosPolicy "SMB-DSCP" -NetDirectPortMatchCondition 445 -DSCPAction 3
4.4 SMB Direct 校验
# 看看 RDMA 是否可用
Get-SmbClientNetworkInterface | ft InterfaceFriendlyName,RdmaCapable,RssCapable,IpAddresses
Get-SmbServerNetworkInterface | ft InterfaceAlias,RdmaCapable,IPAddress
# 建连后确认:
Get-SmbMultichannelConnection | ft ClientRSSCapable,ServerRdmaCapable,ClientRdmaCapable,ServerName,InterfaceIndex,State
若 ClientRdmaCapable/ServerRdmaCapable = True 且 State = Established,说明 SMB Direct 已走 RDMA。
五、S2D(Storage Spaces Direct)落地步骤摘要
我用的是 4 节点“对等架构”,每节点 NVMe 混合(Cache + Capacity),用 ReFS/CSVFS。
# 1) 建群集(假定已正确解析主机名)
New-Cluster -Name HK-S2D -Node HK01,HK02,HK03,HK04 -StaticAddress 10.10.31.10 -NoStorage
Test-Cluster -Node HK01,HK02,HK03,HK04
# 2) 开启 S2D
Enable-ClusterS2D -Confirm:$false
# 3) 建虚拟磁盘与卷(两层存储示例)
# 先找出存储池与可用层
Get-StoragePool -IsPrimordial $false
Get-StorageTier | ft FriendlyName,MediaType,ResiliencySettingName
# 示例:创建 2 个层(性能/容量)并组合
$perf = Get-StorageTier -FriendlyName *Performance*
$cap = Get-StorageTier -FriendlyName *Capacity*
New-Volume -FriendlyName "CSV-01" `
-StorageTierFriendlyNames $perf.FriendlyName,$cap.FriendlyName `
-StorageTierSizes 2TB,10TB -FileSystem CSVFS_ReFS
小技巧:SMB Multichannel Constraint 用来“钉”住 RDMA 接口,避免偶尔走到管理网卡。
# 以客户端视角约束到对端服务器特定接口(示例)
# 先查 server 的 RDMA 接口 IP
Get-SmbServerNetworkInterface -CimSession HK02
# 钉住:
Set-SmbClientConfiguration -EnableMultiChannel $true
New-SmbMultichannelConstraint -InterfaceIndex 12 -ServerName "HK02"
六、基准与对比(真实跑过的典型数值)
工具:DiskSpd(远端 SMB 共享/CSV 上压测),30s 预热 + 180s 运行;Windows 性能计数器记录 CPU;多轮求中位数。
6.1 4K 随机读(8 线程 * 深度 32)
| 模式 | p50 延迟 | p99 延迟 | IOPS | 节点总 CPU |
|---|---|---|---|---|
| TCP@100GbE(无 RDMA) | 1.8 ms | 6.3 ms | 520K | 48% |
| RDMA@100GbE(RoCEv2) | 0.42 ms | 1.1 ms | 1.15M | 18% |
6.2 64K 顺序读(8 线程 * 深度 8)
| 模式 | 吞吐 | p99 延迟 | 节点总 CPU |
|---|---|---|---|
| TCP@100GbE(无 RDMA) | 7.2 GB/s | 4.8 ms | 62% |
| RDMA@100GbE(RoCEv2) | 11.8 GB/s | 1.7 ms | 27% |
观察:RDMA 把 TCP 栈绕开后,延迟腰斩不止,CPU 释放立竿见影;多通道(两口 100G)拉满时,瓶颈迅速转到 NVMe 阵列与 S2D 编码层。
七、最容易踩的坑(以及我是怎么在机房把它们填上的)
PFC 开太多
症状:整网时不时“凝固”,RTT 飙到几十毫秒,吞吐断崖式下降。
原因:把所有优先级都开了 PFC,Pause Storm 一来所有流量被连坐。
解决:只为 Priority 3(SMB/RDMA)开 PFC,其余全部关闭;打开 ECN,把轻微拥塞交给 ECN/CNP 去处理。
RoCEv1/ECN 不一致
症状:RDMA 能跑但抖动大,p99 偶发 10ms+。
原因:一侧网卡还是 RoCEv1、交换机/网卡未统一 ECN。
解决:统一 RoCEv2;网卡固件里把 ECN 打开;交换机上设好 ECN 阈值,与队列映射一致。
MTU 不一致
症状:90% 的流量好好的,偶尔某台节点吞吐掉一半。
原因:某一跳设备还停留在 1500 MTU。
解决:端到端 9000;Windows、交换机、上联都核对;ping -f -l 8972 很好用。
混用防火墙策略
症状:SMB 建链偶尔走 TCP,RDMA 连接建立失败。
原因:中途有 L3/主机防火墙对 445 或 DCB/LLDP 压制。
解决:存储 VLAN 内白名单 445/TCP、DCBX/LLDP;Windows 防火墙放行 文件和打印机共享(SMB-In)。
NUMA/RSS 亲和不当
症状:CPU 某一半核心爆表,另一半吃灰。
解决:对非 RDMA 流量设置 RSS Base/Max;RDMA 流量走 NIC 直达,尽量把中断和队列对齐到本地 NUMA。
Get-NetAdapterRss -Name "RDMA1","RDMA2"
Set-NetAdapterRss -Name "RDMA1" -BaseProcessorNumber 0 -MaxProcessorNumber 31
Set-NetAdapterRss -Name "RDMA2" -BaseProcessorNumber 32 -MaxProcessorNumber 63
交换机 Buffer/队列映射
症状:单口 100G 还好,双口并发就开始丢包、CNP 淹没。
解决:把 Priority 3 映射到专属队列,给足 buffer;ECMP/LAG Hash 包含 5 元组,避免倾斜。
八、现场可复用的“拷贝即用”脚本片段
8.1 一次性把 RDMA、QoS、巨帧、校验都配好
$rdmaIf = @("RDMA1","RDMA2")
# RDMA & Jumbo
Enable-NetAdapterRdma -Name $rdmaIf
Set-NetAdapterAdvancedProperty -Name $rdmaIf -RegistryKeyword "*JumboPacket" -RegistryValue 9014
# QoS 基线
if (-not (Get-WindowsFeature Data-Center-Bridging).Installed) {
Install-WindowsFeature Data-Center-Bridging -IncludeManagementTools
}
# 清理旧策略
Get-NetQosPolicy | Remove-NetQosPolicy -Confirm:$false
# SMB 优先级 & DSCP
New-NetQosPolicy "SMB" -NetDirectPortMatchCondition 445 -PriorityValue8021Action 3
Set-NetQosDscpState -State Enabled
New-NetQosPolicy "SMB-DSCP" -NetDirectPortMatchCondition 445 -DSCPAction 3
# PFC for pri 3 only
Enable-NetQosFlowControl -Priority 3
Disable-NetQosFlowControl -Priority 0,1,2,4,5,6,7
# ETS 权重
New-NetQosTrafficClass -Name "SMB" -Priority 3 -BandwidthPercentage 60 -Algorithm ETS
# 验证
Write-Host "RDMA 接口:"
Get-SmbClientNetworkInterface | ft InterfaceFriendlyName,RdmaCapable,IpAddresses
8.2 S2D 建群集到建卷(最小化示例)
$nodes = "HK01","HK02","HK03","HK04"
New-Cluster -Name HK-S2D -Node $nodes -StaticAddress 10.10.31.10 -NoStorage
Test-Cluster -Node $nodes
Enable-ClusterS2D -Confirm:$false
$perf = Get-StorageTier -FriendlyName *Performance*
$cap = Get-StorageTier -FriendlyName *Capacity*
New-Volume -FriendlyName "CSV-01" -StorageTierFriendlyNames $perf.FriendlyName,$cap.FriendlyName -StorageTierSizes 2TB,10TB -FileSystem CSVFS_ReFS
九、运维侧的观察与复盘
- 延迟:RDMA 后,4K 随机读 p50 从 1.8ms 下降到 ~0.4ms,p99 逼近 1ms。
- CPU:SMB Direct 把大量 copy/stack 开销省掉了,S2D 重平衡时 CPU 峰值从 70% 降到 30% 多一些。
- 波动:把 ECN 和 PFC 调完之后,抖动比纯 PFC 方案小得多,链路满载时也不会“闷死”。
- 运维复杂度:RDMA 最大成本是端到端一致性(固件/驱动/DCB 参数);一旦固化成自动化脚本,后续扩容就顺滑了。
十、Checklist(上线前最后 5 分钟)
- RoCEv2:网卡固件一致、网卡属性确认、驱动版本一致。
- DCB:PFC=pri 3 only,ETS≥50%,ECN 开。
- MTU:端到端 9000,一跳不差。
- SMB:Get-SmbMultichannelConnection 里 RDMA=true。
- 交换机:优先级/队列映射、Buffer 足量、DCBX on。
- 监控:p50/p99 延迟、CNP 计数、Pause 帧计数、丢包计数。
- 回滚:保留一键禁用 RDMA/恢复 TCP 的脚本,变更窗口内演练过。
凌晨 4:05,我把最后一条 Get-SmbMultichannelConnection 输出拍了张照:四条 RDMA 会话稳稳当当。重平衡任务重新跑起来,p99 老老实实趴在 1ms 左右。机房外面开始泛白,同事拍了拍我:“走,去楼下吃碗云吞面,你欠它一夜的面子。”
这次折腾的收获很简单:Windows 场景里,RDMA(RoCEv2)+100GbE 不是“锦上添花”,而是“去掉系统噪音”的一刀。当你的分布式存储把 CPU 和 TCP 栈都当成“路障”时,RDMA 这把刀能把路障削平。剩下的,就是硬盘阵列和代码层真正的实力了。
如果你也在香港、也在半夜和延迟搏斗,不妨把上面的清单和脚本照着走一遍。别怕,一切从 Priority 3 开始。