如何在香港服务器上跑 Windows Server 2022 时,把 Hyper-V 虚拟交换机的性能“掰直”?

那天晚上是香港葵涌机房最常见的闷热潮湿。机柜风从脚下往上灌,像一股带着盐味的热浪。我蹲在42U机柜前,盯着一台托管的 2U 服务器:两张 25GbE,32 核 CPU,内存 256GB,Windows Server 2022 Datacenter + Hyper-V。几台北向 VM 做边界转发,几台东西向 VM 跑分布式缓存。业务刚从广州回源到香港,峰值流量贴着 40Gbps,虚机里延迟抖成锯齿,宿主机 CPU 的 0 号核被打到 100%,而其他核像在放假。值夜的小哥看我抬头,他问:“是不是 vSwitch 又在卡?”
我没回,就把随身的小凳子往机柜一塞,开干。
一、环境与目标(Baseline & Goal)
硬件/软件基线
| 项 | 配置 |
|---|---|
| 机型 | 双路 2U(2× Intel Xeon Gold,32C/64T 总计) |
| 内存 | 256GB DDR4 |
| NIC | 2× 25GbE:Mellanox ConnectX-4 Lx(RoCEv2),固件 14.x;或 Intel E810 25G(视批次) |
| 存储 | 2×NVMe(OS)+ 4×NVMe(数据盘) |
| OS | Windows Server 2022 Datacenter, 最新补丁 |
| 虚拟化 | Hyper-V,来宾系统混合(Windows/Linux) |
| 机房 | 香港,ToR 支持 VLAN Trunk;PFC/DCB 不对客户开放(常见限制) |
初始现象(未优化)
- 同一宿主机 VM 间(东西向)平均吞吐仅 11–14Gbps,PPS(小包)不稳定;
- 北向(经物理 NIC 出口)单 VM 吞吐 7–9Gbps;
- 宿主机 CPU Core#0 100%,其余核心较空;
- ping 抖动,偶发丢包;
- Live Migration 偶尔把生产网“挤”出尖峰延迟。
优化目标
- 东西向近线速(> 18Gbps/VM,合计逼近 25G 物理线速),小包稳定;
- 北向单 VM > 15Gbps;
- 让 CPU 负载均衡(RSS/vRSS/VMMQ 生效);
- Live Migration/存储/管理业务互不抢网;
- 有据可依,可复现,可回滚。
二、总体策略(一句话版)
用 SET(Switch Embedded Teaming)做外部 vSwitch,按“管理/存储/迁移/业务”拆 Host vNIC;开启 SR-IOV(能用就用)、VMMQ/vRSS/RSS、RSC/LSO/Checksum Offload、合理的 VMQ 核亲和与 VLAN 规划;以权重 QoS 管理带宽;能走 Jumbo 就全链路走;有 RDMA 环境就开 vSwitch RDMA,没有就规避半拉子配置。
三、网络拓扑与规划(先画草图再敲命令)
规划四张 Host vNIC(宿主机虚拟网卡):
| 逻辑网 | 用途 | VLAN | QoS 权重 | 备注 |
|---|---|---|---|---|
| vMgmt | 管理 | 10 | 10 | RDP/运维,仅少量流量 |
| vLM | Live Migration | 20 | 20 | 迁移时会打满,需权重 |
| vSMB | 存储/备份(SMB) | 30 | 30 | 若机房允许 DCB/PFC,可做 RDMA |
| vProd | 生产数据面 | Trunk(100–199) | 40 | VM 的主要业务流量 |
注意:香港很多托管机房不开放 DCB/PFC,即便 NIC 支持 RoCEv2,也不要半开半关。要么全链路 RDMA(ToR/上联/端到端都通),要么干脆别开 RDMA。
四、逐步落地(PowerShell 实操)
4.1 驱动/固件一致性与 NIC 基线
先做这一步,后面所有优化才不白费。
# 查看适配器与驱动
Get-NetAdapter | Format-Table Name, InterfaceDescription, Status, LinkSpeed
Get-NetAdapterAdvancedProperty -Name "NIC1","NIC2"
# 开启常见 offload(先看默认,通常不用关闭)
Enable-NetAdapterChecksumOffload -Name "NIC1","NIC2"
Enable-NetAdapterLso -Name "NIC1","NIC2"
Enable-NetAdapterRsc -Name "NIC1","NIC2"
# 开启 RSS(物理 NIC)
Enable-NetAdapterRss -Name "NIC1","NIC2"
Get-NetAdapterRss -Name "NIC1" | Format-List *
坑 1: 有些批次的 Mellanox/Intel 驱动与固件不匹配,会导致 VMQ/VMMQ 状态异常或队列数异常偏少。先升到厂商推荐“配套版本”。
4.2 用 SET 创建外部 vSwitch(别再用 LBFO)
Windows Server 2022 上,给 vSwitch 做汇聚,官方推荐 SET;LBFO 虽在,但不支持 vSwitch 的很多新特性。
$uplinks = @("NIC1","NIC2")
# 建 SET + External vSwitch,关闭 AllowManagementOS(我们手动建 Host vNIC)
New-VMSwitch -Name "vSwitch-SET-Prod" `
-NetAdapterName $uplinks `
-EnableEmbeddedTeaming $true `
-AllowManagementOS $false `
-EnableIov $true `
-BandwidthReservationMode Weight
# SET 默认是 Switch-Independent + Dynamic 负载分担,满足大多数托管场景
Get-VMSwitchTeam -Name "vSwitch-SET-Prod"
坑 2: SET 不支持 LACP(多数 ToR 也不愿跟客户做 LACP),所以保持 Switch-Independent 最稳。
4.3 划分宿主机虚拟网卡(Host vNIC)+ VLAN + QoS
# 宿主机 vNIC:分别挂到同一 vSwitch
$hostVnics = @(
@{Name="vMgmt"; VLAN=10; Weight=10},
@{Name="vLM"; VLAN=20; Weight=20},
@{Name="vSMB"; VLAN=30; Weight=30},
@{Name="vProd"; VLAN=0; Weight=40} # vProd 设为 Trunk,后面单独开 Trunk
)
foreach ($n in $hostVnics) {
Add-VMNetworkAdapter -ManagementOS -Name $n.Name -SwitchName "vSwitch-SET-Prod"
if ($n.VLAN -gt 0) {
Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName $n.Name -Access -VlanId $n.VLAN
}
Set-VMNetworkAdapter -ManagementOS -Name $n.Name -MinimumBandwidthWeight $n.Weight -VrssEnabled $true
}
# vProd 改为 Trunk(宿主机需要跑多 VLAN 的场景)
Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName "vProd" -Trunk -NativeVlanId 100 -AllowedVlanIdList "100-199"
# 为 Host vNIC 配置 IP(例)
New-NetIPAddress -InterfaceAlias "vEthernet (vMgmt)" -IPAddress 10.0.10.11 -PrefixLength 24 -DefaultGateway 10.0.10.1
New-NetIPAddress -InterfaceAlias "vEthernet (vLM)" -IPAddress 10.0.20.11 -PrefixLength 24
New-NetIPAddress -InterfaceAlias "vEthernet (vSMB)" -IPAddress 10.0.30.11 -PrefixLength 24
# vProd 可能做子接口或由上层路由/VRF 管
坑 3: VLAN Trunk 经常出错。宿主机 vNIC 与 ToR 的 Native/Allowed 要一致。如果不确定,先 Access 跑通再 Trunk。
4.4 Jumbo Frame(全路径一致才算成立)
# 物理 NIC Jumbo(视 ToR 支持,常用 9014/9216)
Set-NetAdapterAdvancedProperty -Name "NIC1","NIC2" -DisplayName "Jumbo Packet" -DisplayValue "9014 Bytes"
# vNIC/来宾 OS 也要配(Linux 倾向 9000,Windows 8996/9014),务必全链路一致
# 验证 MTU:Windows
ping <对端IP> -f -l 8972
坑 4: 机房不少 ToR 对外口 MTU 只开到 9216,下游设备再叠加封装会超。用 ping -f -l 验 MTU 是最省事的办法。
4.5 vSwitch 侧 RSC(Receive Segment Coalescing)
# vSwitch 侧软件 RSC
Set-VMSwitch -Name "vSwitch-SET-Prod" -EnableSoftwareRsc $true
# 确认
Get-VMSwitch -Name "vSwitch-SET-Prod" | fl Name,EnableSoftwareRsc
RSC 能把小包拼大包,减主机 CPU 开销,尤其在小包 PPS 高的业务里有肉眼可见的收益。
4.6 RSS / vRSS / VMMQ:把流量“撒”到多核
# 物理 NIC 保证 RSS 打开
Enable-NetAdapterRss -Name "NIC1","NIC2"
# 查看 VMQ(物理队列)状态
Get-NetAdapterVmq -Name "NIC1","NIC2"
# 为高吞吐 VM 开 VMMQ(来宾多队列)
Set-VMNetworkAdapter -VMName "Edge-VM01" -Name "Ethernet" -VmmqEnabled $true -VmmqQueuePairs 16
Set-VMNetworkAdapter -VMName "Cache-VM01" -Name "Ethernet" -VmmqEnabled $true -VmmqQueuePairs 8
# vRSS(来宾内核里的 RSS)
Set-VMNetworkAdapter -VMName "Edge-VM01" -VrssEnabled $true
Set-VMNetworkAdapter -VMName "Cache-VM01" -VrssEnabled $true
坑 5: 看到 Core#0 100% 其实是 RSS 没生效或队列没撒开。
坑 6: 某些驱动默认 VMQ 队列过少,或“自动”分配到跨 NUMA 的核,需要手动给 BaseProcessor 做亲和。
# 例:将 NIC1 的 VMQ 基线绑到 CPU#8(避开 0 号核),给 12 个核
Set-NetAdapterVmq -Name "NIC1" -BaseProcessorNumber 8 -MaxProcessors 12
Set-NetAdapterVmq -Name "NIC2" -BaseProcessorNumber 20 -MaxProcessors 12
核心思想:把物理队列与 NUMA 对齐,避免跨 NUMA 来回搬数据。
4.7 SR-IOV:给极限型 VM 一把“直通快刀”
# vSwitch 已带 -EnableIov $true
Get-NetAdapterSriov
# 为边界转发型 VM 提高 IOV 权重
Set-VMNetworkAdapter -VMName "Edge-VM01" -Name "Ethernet" -IovWeight 100
提醒:
- SET 下 SR-IOV 可用(取决于 NIC/BIOS/主板/IOMMU);
- SR-IOV 下某些 vSwitch 功能(端口镜像、ACL、捕获)不可用;
- 机房若做流量清洗或镜像,甄别是否需要 SR-IOV。
托管商常见限制:系统固件没开 VT-d/IOMMU、PCIe ACS 隔离不足、上游不让 PFC——这些会直接把 SR-IOV/ROCE“封死”。碰到就别死磕。
4.8 带宽治理(QoS):权重而非硬限优先
# vSwitch 已启用权重模式(BandwidthReservationMode=Weight)
# 我们之前给 Host vNIC 设了 Weight,这里给 VM 也设
Set-VMNetworkAdapter -VMName "Edge-VM01" -MinimumBandwidthWeight 50
Set-VMNetworkAdapter -VMName "Cache-VM01" -MinimumBandwidthWeight 30
Set-VMNetworkAdapter -VMName "Misc-VM01" -MinimumBandwidthWeight 10
# Live Migration 另行限速(避免挤生产)
Set-SmbBandwidthLimit -Category LiveMigration -BytesPerSecond 20000000000 # 20Gbps
五、验证与指标(用数据说话)
5.1 测试方法
- 东西向:同宿主机两台 VM 间 iperf3/ntttcp,分别测大包/小包,多流;
- 北向:VM→外部测试机(同 ToR 不同端口),保持单流/多流;
- CPU:PerfMon 看 Processor(_Total)\% Processor Time、Interrupts/sec、Hyper-V Virtual Switch(*) 计数器;
- 队列:Get-NetAdapterVmqQueue,确认队列散布与迁移。
5.2 样例结果(单宿主机)
优化前 vs 优化后
| 场景 | 指标 | 优化前 | 优化后 |
|---|---|---|---|
| VM↔VM(同宿主机,大包) | 吞吐 | 11–14 Gbps | 20–23 Gbps |
| VM↔VM(同宿主机,小包 512B) | PPS | 抖动严重 | 稳定提升 ~35–60% |
| VM→北向(单 VM,多流) | 吞吐 | 7–9 Gbps | 15–18 Gbps |
| 宿主机 Core#0 | 利用率 | ~100% | 20–40%(均摊到多核) |
| Ping 抖动 | RTT | 1–5ms 抖 | < 0.8ms 稳定 |
| 迁移挤压 | 业务延迟尖峰 | 偶发 | 控制在可接受范围 |
这组数据是在 RSC + RSS + VMMQ 开启、Jumbo 9014 全链路打通、SR-IOV 对关键 VM 打开 的前提下测得。
六、典型“坑”与现场排障过程(真事儿)
Core#0 爆满
症状:业务延迟抖、丢包;
排查:Get-NetAdapterRss 显示已开启,但 Get-NetAdapterVmq 队列少且 BaseProcessor=0;
操作:给 NIC1/NIC2 分别设 BaseProcessor & MaxProcessors,让队列远离 0 号核并靠近对应 NUMA;同时打开 VMMQ/vRSS;
结果:Core#0 降到 30% 左右,吞吐/PPS 稳了。
“Jumbo 开了反而更差”
症状:吞吐忽高忽低;
排查:ToR 口 MTU=9216,但上游采集/清洗盒子分片阈值与 DSCP 政策冲突;
操作:协调网络侧统一链路 MTU,ping -f -l 8972 验证沿途无碎片;
结果:RSC 生效明显,小包场景稳定。
SR-IOV 打不开
症状:Get-NetAdapterSriov 显示不支持;
排查:BIOS 里 VT-d 关闭;
操作:停机维护窗口开 VT-d,更新 NIC 固件到建议版本;
结果:SR-IOV 正常;但因上游要镜像,我们最后只给边界 VM 用,其他 VM 维持 vSwitch 路径。
Live Migration 抢带宽
症状:半夜迁移时业务延迟突刺;
操作:给 Live Migration 设 SMB 带宽上限 + vSwitch 权重;
结果:迁移时间略增,但生产延迟稳定。
七、推荐的“标准落地脚本”(可复制粘贴后按需改)
按你的 VLAN/IP/VM 名称替换即可。
# 1) 变量
$uplinks = @("NIC1","NIC2")
$switch = "vSwitch-SET-Prod"
# 2) NIC 基线
Enable-NetAdapterChecksumOffload -Name $uplinks
Enable-NetAdapterLso -Name $uplinks
Enable-NetAdapterRsc -Name $uplinks
Enable-NetAdapterRss -Name $uplinks
Set-NetAdapterAdvancedProperty -Name $uplinks -DisplayName "Jumbo Packet" -DisplayValue "9014 Bytes"
# 3) 创建 SET vSwitch
New-VMSwitch -Name $switch -NetAdapterName $uplinks -EnableEmbeddedTeaming $true -AllowManagementOS $false -EnableIov $true -BandwidthReservationMode Weight
Set-VMSwitch -Name $switch -EnableSoftwareRsc $true
# 4) Host vNIC + VLAN + QoS
Add-VMNetworkAdapter -ManagementOS -Name "vMgmt" -SwitchName $switch
Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName "vMgmt" -Access -VlanId 10
Set-VMNetworkAdapter -ManagementOS -Name "vMgmt" -MinimumBandwidthWeight 10 -VrssEnabled $true
Add-VMNetworkAdapter -ManagementOS -Name "vLM" -SwitchName $switch
Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName "vLM" -Access -VlanId 20
Set-VMNetworkAdapter -ManagementOS -Name "vLM" -MinimumBandwidthWeight 20 -VrssEnabled $true
Add-VMNetworkAdapter -ManagementOS -Name "vSMB" -SwitchName $switch
Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName "vSMB" -Access -VlanId 30
Set-VMNetworkAdapter -ManagementOS -Name "vSMB" -MinimumBandwidthWeight 30 -VrssEnabled $true
Add-VMNetworkAdapter -ManagementOS -Name "vProd" -SwitchName $switch
Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName "vProd" -Trunk -NativeVlanId 100 -AllowedVlanIdList "100-199"
Set-VMNetworkAdapter -ManagementOS -Name "vProd" -MinimumBandwidthWeight 40 -VrssEnabled $true
# 5) VM 阶段:高吞吐 VM 开 VMMQ/vRSS/SR-IOV 权重
$perfVMs = @("Edge-VM01","Cache-VM01")
foreach ($vm in $perfVMs) {
Set-VMNetworkAdapter -VMName $vm -VmmqEnabled $true -VmmqQueuePairs 8 -VrssEnabled $true -IovWeight 80
}
# 6) VMQ CPU 亲和
Set-NetAdapterVmq -Name "NIC1" -BaseProcessorNumber 8 -MaxProcessors 12
Set-NetAdapterVmq -Name "NIC2" -BaseProcessorNumber 20 -MaxProcessors 12
# 7) SMB/迁移限速(按需)
Set-SmbBandwidthLimit -Category LiveMigration -BytesPerSecond 20000000000
八、何时该“收手”与“上刀”:取舍原则
- 追稳定 > 追极限:香港链路复杂、上游策略多,优先 RSC/RSS/VMMQ/SET/QoS 的“常规四件套”。
- SR-IOV 给边界型或 超低延迟 VM,用在刀刃上;
- RDMA 只有在 端到端 可控时才开启;
- Jumbo 必须全链路一致;
- 能测就测:iperf3、ntttcp、PerfMon、Get-* 系列输出留存,便于回归。
九、收尾(机房门口的风比机柜里凉快)
凌晨三点半,我把最后一条 PowerShell 敲完,PerfMon 的线一条条顺了下来。Core#0 不再抓狂,虚机间的吞吐上了 20Gbps,北向单 VM 也跑到了 15Gbps 以上。Live Migration 开始的时候,生产曲线只是轻轻一荡。
我把凳子抽出来,背靠着冷通道的墙坐了会儿,机柜门上还能看到之前画 VLAN 的记号笔印。值夜的小哥递过来一瓶水,我顺口把这套“配方”讲给他听:SET、VMMQ/vRSS、RSC、Jumbo、QoS、队列亲和、SR-IOV,再加上一点对机房脾气的了解。
第二天早上八点,业务方只发了四个字:“这次稳了。”
十、速查清单(Checklist)
- 驱动/固件配套,Enable-*Offload、Enable-NetAdapterRss、Enable-NetAdapterRsc
- 用 SET 建外部 vSwitch(-EnableEmbeddedTeaming)
- Host vNIC 分层:管理/迁移/存储/生产 + VLAN + 权重
- RSC 开启(Set-VMSwitch -EnableSoftwareRsc $true)
- RSS/vRSS/VMMQ/SR-IOV:按 VM 类型启用
- VMQ 队列与 CPU/NUMA 亲和(Set-NetAdapterVmq)
- Jumbo 全链路一致(ping -f -l 验证)
- Live Migration/SMB 限速(Set-SmbBandwidthLimit)
- 用 iperf3/ntttcp/PerfMon 验证并留档
如果你也在香港的机房里为 Hyper-V 的 vSwitch 跑数而烦躁,照着这篇做一遍,先把 80% 的通用优化吃满。剩下 20%,就看你机房的个性与业务的脾气了。