上一篇 下一篇 分享链接 返回 返回顶部

香港服务器上的Windows Server系统中,如何设置和优化QoS策略,保障实时对战类游戏的数据传输优先级?

发布人:Minchunlin 发布时间:2025-09-09 09:28 阅读量:1051


那天夜里,我刚把一批 Windows Server 2022 的补丁打完没多久,客服就把微信甩过来:“跨区对战抖成 PPT,广州和台北的玩家都在骂延迟飙。”

我用 Zabbix 和交换机队列看了眼,出向链路并不满,但 1 分钟内出现了几次短时突发(microburst)。再翻 Windows 侧的流量,发现实时对战的 UDP 小包被同机的回放上传、日志归档、镜像分发这些“笨重的 TCP”挡在队尾。那一刻我决定:不再赌网络空闲,直接在 Windows Server 上用 QoS 把实时通道抬成头等舱。

基线环境与约束

硬件与系统(真实在跑的那批)

  • 机型:Dell PowerEdge R650(1U)
  • CPU:Intel Xeon Silver 4314 × 1(16C/32T)
  • 内存:128GB DDR4-3200
  • 系统盘:Intel D3-S4510 480GB(SATA)
  • 业务盘:Samsung PM9A3 1.92TB × 2(NVMe,Raid1)
  • 网卡:Intel X710-DA2(双口 10GbE,直连 ToR)
  • 操作系统:Windows Server 2022 Datacenter(21H2,已打到当时最新补丁)
  • 虚拟化:无 Hyper-V(这台是物理直跑游戏进程;文中也给 Hyper-V 的做法)
  • 交换机:ToR 是 25G 上联的 Arista(本段只用到L2/L3 DSCP,不依赖厂商特性)

网络拓扑

上联:HKT/NTT 双线,策略路由分省份;IDC 内部三层架构

关键点:跨运营商段不保证保留 DSCP,但 机房边界和 IDC 内部我们能识别与优先转发

我们的业务端口规划(示例,可替换成你的)

流量类型 协议/端口 方向 说明
实时对战(状态同步) UDP 30000–30100 双向 66–120B 小包,高 PPS
实时语音(内置) UDP 31000–31010 双向 抖动敏感
匹配/房间 TCP 21000 出站为主 建连与少量信令
观战回放上传 TCP 28080 出站 大对象、可延迟
日志/分析上报 TCP 29000 出站 批量,非实时
运营后台/API TCP 443 双向 常规 Web

QoS 设计思路(我当晚的决策)

DSCP 标记:

  • 实时状态(UDP 30000–30100)→ EF(46)
  • 语音(UDP 31000–31010)→ AF41(34)
  • 匹配/信令(TCP 21000)→ AF31(26)
  • 回放/日志等挤占型流量 → CS1(8)(背景级,必要时限速)

最小带宽保障 + 队列优先级(可选,网卡与交换机支持时启用):

  • 在 Windows + X710 驱动 侧开启 Adapter QoS + ETS,把 EF 类别至少预留 30% 的发包口粮,避免被 TCP 拖尾。

不依赖公网的 DSCP 诉求:

  • 出 IDC 之后对方可能清洗 DSCP,但机房内/边界优先队列已足够抗住本端的突发。这点在我们的延迟 P99 里非常关键。

实施 A:单机用 PowerShell 下发 QoS(最快落地)

适用于临时加急、或你在做金丝雀验证。不需要域控。

清理试验机的旧策略(只动本地存储)

# 只查看本地策略,不动组策略
Get-NetQosPolicy -PolicyStore Local | Format-Table -Auto

# 如需清空旧规则(谨慎)
Get-NetQosPolicy -PolicyStore Local | Remove-NetQosPolicy -PolicyStore Local -Confirm:$false

创建 DSCP 策略

# 1) 实时对战:EF(46)
New-NetQosPolicy -Name "Game-RT-UDP" `
  -PolicyStore Local `
  -IPProtocolMatchCondition UDP `
  -DestinationPortMatchCondition 30000-30100 `
  -DSCPAction 46 -NetworkProfile All

# 2) 实时语音:AF41(34)
New-NetQosPolicy -Name "Game-Voice-UDP" `
  -PolicyStore Local `
  -IPProtocolMatchCondition UDP `
  -DestinationPortMatchCondition 31000-31010 `
  -DSCPAction 34 -NetworkProfile All

# 3) 匹配/信令:AF31(26)
New-NetQosPolicy -Name "Game-Match-TCP" `
  -PolicyStore Local `
  -IPProtocolMatchCondition TCP `
  -DestinationPortMatchCondition 21000 `
  -DSCPAction 26 -NetworkProfile All

# 4) 观战回放(背景级):CS1(8) + 可选限速
New-NetQosPolicy -Name "Game-Replay-Background" `
  -PolicyStore Local `
  -IPProtocolMatchCondition TCP `
  -DestinationPortMatchCondition 28080 `
  -DSCPAction 8 `
  -ThrottleRateActionBitsPerSecond 200Mb

说明:

  • -NetworkProfile All 覆盖域/专用/公用场景。
  • ThrottleRateActionBitsPerSecond 给背景类一个上限(上例 200Mb),防止高峰期把队列打爆。
  • 如果你是源端口更稳定,可改用 -SourcePortMatchCondition。
  • 如果你想绑定到进程路径(如 C:\game\server.exe),可用 -AppPathNameMatchCondition。

查看生效情况

Get-NetQosPolicy -PolicyStore Local | Format-List

实施 B:批量推送(域控 GPO / 本地策略)

生产里我用 GPO(Policy-based QoS) 批量下发。优点:可视化、审计、回滚简单。

本地策略操作(单机演示,域控同理)

打开 gpedit.msc → “计算机配置” → “Windows 设置” → “基于策略的 QoS”

右键新建策略,填:

  1. 策略名称:Game-RT-UDP
  2. 指定 DSCP 值:46;不勾选限速(实时流量不限速)
  3. 此 QoS 策略适用的应用程序:留空(按端口匹配)
  4. 此 QoS 策略适用的 IP 地址:任意
  5. 此 QoS 策略适用的协议和端口:选择 UDP,目标端口 30000-30100

用同样方法新建 Game-Voice-UDP(34), Game-Match-TCP(26), Game-Replay-Background(8, 可选限速)。

gpupdate /force,重启相关服务或淡出换班时重启机器。

注意:PowerShell 与 GPO 最终都进 ActiveStore,但存储位置不同。不要混着改,以免定位困难。

实施 C(可选):开启网卡 Adapter QoS + ETS 保障(X710/Mellanox 等)

这步是加分项,能在Windows→NIC→ToR这一跳把 EF 流量的最小口粮钉住。需要网卡/驱动支持 DCB/ETS;交换机若支持更佳。

# 1) 打开网卡级 QoS
Enable-NetAdapterQos -Name "Ethernet"

# 2) 设置 DCBX 为 “愿意(Willing)”(交换机会下发也可)
Set-NetQosDcbx -Willing $True

# 3) 建立流量类:优先级5(常用于 EF),预留30%
New-NetQosTrafficClass -Name "TC_EF" -Priority 5 -BandwidthPercentage 30 -Algorithm ETS

# 4) 将 DSCP=46 的包同时打上 802.1p 优先级5(数据链路内有效)
Set-NetQosPolicy -Name "Game-RT-UDP" -PolicyStore Local -PriorityValue8021Action 5

网卡高级属性建议(X710)

  • Interrupt Moderation:Low 或 Off(纯低延迟场景);高 PPS 时 Off 会多吃 CPU,自行权衡
  • RSS Queues:与物理核心数匹配(如 8)
  • Receive/Transmit Buffers:适度调高(如 1024/1024),防短突发丢包
  • Energy Efficient Ethernet:关闭
  • VLAN Offload/DSCP Preserve:开启保留(不同驱动名称略有差异)

Hyper-V 场景(如果你的游戏跑在 VM 里)

在 vSwitch 上启用最小带宽权重(隔离背景型 VM)

# 例:把实时游戏VM的权重调高
Set-VMNetworkAdapter -VMName "Game-VM-01" -MinimumBandwidthWeight 80
Set-VMNetworkAdapter -VMName "Log-VM-01"  -MinimumBandwidthWeight 10

DSCP 端到端保留:

  • 在 宿主 和 来宾都按上文建 QoS(GPO 更方便)
  • 新版 vSwitch 会保留 DSCP,若你的版本或某些虚拟化层会清洗,需在宿主侧再做一次 DSCP 标记兜底。

验证与观测(我当晚是这么确认的)

抓包看 DSCP 是否生效

服务器上跑 Wireshark 或 npcap + windump,过滤:

(udp.port >= 30000 && udp.port <= 30100) && ip.dsfield.dscp == 46

观察发包路径,确认 DSCP=46 已打上

交换机/路由器侧

  • ToR 上看队列统计(以厂商命令为准),确认 EF/AF41 队列在突发期无明显丢包、tx-ring 不堆积

Windows 性能计数器

  • Perfmon → Network Interface:Output Queue Length(应 ≤1)、Packets/sec
  • Processor:DPC Rate(不要持续拉高)
  • UDPv4:Datagrams/sec(验证 PPS 峰值)

对比数据(当晚抓的一个 15 分钟窗口)

指标 调整前 调整后
实时对战 RTT 中位数 19.4 ms 17.8 ms
RTT P99 118.6 ms 43.2 ms
服务器出向丢包(EF 队列) 0.12% 0.01%
观战回放平均速率 680 Mbps ~190–210 Mbps(被限速)
玩家断连率(同时段) 0.9% 0.3%

常见坑 & 处理笔记(这些都是我踩过的)

“我打了 DSCP 还是没用?”
很多公网段会清洗 DSCP。别纠结对端;只要机房内/边界优先,你已经把 80% 的突发影响打掉了。

网卡驱动“吃掉 DSCP”
少数旧驱动在封装/分片时会没保留 DSCP。升级 X710 驱动(同步 NVM)后恢复,且把 DSCP Preserve/Trust 打开。

把实时流量也限速了
别勾“限速”在实时策略上。Throttle 只用在回放、日志、镜像分发这类“能等的”。

GPO 和本地策略打架
一台机器用一种来源。定位时看 Get-NetQosPolicy -PolicyStore ActiveStore 与 -PolicyStore Local/GroupPolicy 的差异。

Hyper-V 里 DSCP 丢失
老版本 vSwitch 有保留问题;我在宿主再下发一次基于端口的 DSCP 兜底,就不丢了。

队列预留太激进
ETS 预留不是越大越好。EF 30% 已经很稳;我试过 50%,反而把 Web/API 挤得不太顺畅。

完整脚本(单机本地策略,一键创建/回滚)

create-qos.ps1

# 创建本地 QoS 策略
$pols = @(
    @{Name="Game-RT-UDP"; Store="Local"; Proto="UDP"; DstPorts="30000-30100"; DSCP=46; Throttle=$null},
    @{Name="Game-Voice-UDP"; Store="Local"; Proto="UDP"; DstPorts="31000-31010"; DSCP=34; Throttle=$null},
    @{Name="Game-Match-TCP"; Store="Local"; Proto="TCP"; DstPorts="21000"; DSCP=26; Throttle=$null},
    @{Name="Game-Replay-Background"; Store="Local"; Proto="TCP"; DstPorts="28080"; DSCP=8; Throttle=200Mb}
)

foreach($p in $pols){
    if(Get-NetQosPolicy -PolicyStore $p.Store -ErrorAction SilentlyContinue | ? Name -eq $p.Name){
        Write-Host "Exists: $($p.Name) -> skip"
        continue
    }
    $args = @{
        Name = $p.Name
        PolicyStore = $p.Store
        IPProtocolMatchCondition = $p.Proto
        DestinationPortMatchCondition = $p.DstPorts
        DSCPAction = $p.DSCP
        NetworkProfile = 'All'
    }
    if($p.Throttle){ $args['ThrottleRateActionBitsPerSecond'] = $p.Throttle }
    New-NetQosPolicy @args | Out-Null
    Write-Host "Created: $($p.Name)"
}

# 可选:开启网卡 QoS 与 ETS(如需)
# Enable-NetAdapterQos -Name "Ethernet"
# Set-NetQosDcbx -Willing $True
# New-NetQosTrafficClass -Name "TC_EF" -Priority 5 -BandwidthPercentage 30 -Algorithm ETS
# Set-NetQosPolicy -Name "Game-RT-UDP" -PolicyStore Local -PriorityValue8021Action 5

rollback-qos.ps1

# 回滚本地 QoS 策略
$names = "Game-RT-UDP","Game-Voice-UDP","Game-Match-TCP","Game-Replay-Background"
foreach($n in $names){
    $p = Get-NetQosPolicy -PolicyStore Local -ErrorAction SilentlyContinue | ? Name -eq $n
    if($p){ Remove-NetQosPolicy -Name $n -PolicyStore Local -Confirm:$false; Write-Host "Removed: $n" }
}

你可以按这个表替换成自己的端口/策略

你的流量 端口/协议 DSCP 是否限速 备注
实时对战 UDP X–Y 46(EF) 高 PPS,小包
实时语音 UDP A–B 34(AF41) 抖动敏感
匹配/信令 TCP C 26(AF31) 建连/控制
回放上传 TCP D 8(CS1) (如 200Mb) 大对象
日志/分析 TCP E 8(CS1) 视需要 批量/可延迟

那晚我把脚本跑完,抓包里 ip.dsfield.dscp == 46 的 UDP 小包像“插队卡”一样稳稳当当地先出去。ToR 的 EF 队列没有再看到丢包尖刺,游戏 RTT 的 P99 从 118ms 落到 40ms 出头。最妙的是,观战回放照样传,只是速度变成了“礼貌型”的 200Mb。玩家没再骂,我们继续喝冰的。

后来我把这套改成了域控 GPO,下发到香港、东京和新加坡几组 Windows 服务器上。QoS 不是银弹,但在 IDC 内部和边界保住队列,这件事就足以撑住大多数的“夜半惊魂”。

如果你也在为实时对战的延迟发愁,照这篇把 DSCP 标记 + 背景限速 +(可选的)ETS 预留先做起来。等你把机房里那点看不见的秩序理顺了,玩家就能把注意力放回到该放的地方:游戏本身

目录结构
全文