TCP 窗口优化
不论宽带速度(例 500Mbps 或 1000Mbps),连接到一些海外服务器或物理距离遥远的数据中心或机房时,下载或传输速度有时特别的慢,与测试结果不符,
很大程度上是高网络延迟(RTT)与 TCP 协议的固有设计共同作用的结果。
1. 高延迟下的 TCP 吞吐量陷阱
所有基于 TCP 的网络传输(如网页浏览、文件下载、VPN 连接等)都依赖于一个叫作 TCP 窗口的机制。窗口的作用是限制发送方在收到接收方确认之前可以发送的数据量。
为什么高延迟是性能杀手?
根据 TCP 的设计,数据吞吐量受到以下公式的严格限制:
在跨越国家或大洲的长距离连接中,RTT 动辄超过 150 毫秒。而原始的 TCP 窗口大小只有 65535 字节(64 KiB - 1)。这意味着我们的发送方在发出少量数据后,必须等待漫长的时间(一个 RTT 周期)才能得到确认并发送下一批数据,导致带宽大量闲置。
长距离连接对窗口的需求:带宽时延积 (BDP)
为了完全跑满我们的带宽,TCP 窗口的大小必须能覆盖网络管道的实际容量,这被称为带宽时延积 (BDP):
实际计算示例:假设我们的宽带是 1 Gbps,而连接到北美西海岸服务器的 RTT 是 150 毫秒 (0.15 秒):
- 原始窗口(65535 字节)的最大理论吞吐量仅约为 3.49 Mbit/秒。
- 根据 BDP 计算,我们需要的最优 TCP 窗口大小约为 18.75 MB。只有当窗口能扩展到 18.75 MB 时,我们才有机会跑满 1 Gbps 的带宽。
2. Windows 的解法:窗口自动调优
好消息是,微软早就意识到了这个问题。自 Windows Vista 以来,Windows 系统默认启用了一项名为 “TCP 自动调优接收窗口”(Receive Window Auto-Tuning) 的功能。
自动调优的作用
- 启用窗口缩放:它利用 TCP 窗口缩放扩展(Window Scaling),打破了 64KB 的原始限制,允许窗口大小动态扩展到数 MB 甚至更高(最高可达 1 GiB)。
- 动态匹配 BDP:Windows 系统会持续监测当前的网络 RTT 和应用程序的数据处理速度,智能地将 TCP 窗口大小调整到尽可能接近 BDP 的最优值。(当然是理论上)
如何检查自动调优状态?
我们可以通过 PowerShell 或 CMD 运行以下命令,查看我们的 TCP 全局参数。请关注 “Receive Window Auto-Tuning Level” 的值。
# 在 Windows 10/11 的 PowerShell 或 CMD 中执行netsh interface tcp show global
如果其值为 normal
,则表示自动调优已开启并处于正常工作状态。如果是 disabled
,执行下面的命令。
# 启用自动调优(仅在确认被禁用时使用)netsh interface tcp set global autotuninglevel=normal
3. RFC 1323 TCP 扩展
RFC 1323(TCP Extensions for High Performance)是 TCP 的经典标准。定义了三个关键扩展,让 TCP 在高带宽、高时延(高 BDP)的情况保持一定的性能。
窗口缩放(Window Scaling):
原始 TCP 的窗口字段只有 16 位,最多 65535 字节,在高 BDP 场景下(如 1Gbps 带宽 + 150ms RTT)根本不够用——窗口太小,数据流动缓慢。RFC 1323 引入窗口缩放选项,将窗口定义扩展到 32 位(约 4GB),通过一个缩放因子(scale factor,0-14,对应 2^0 到 2^14 倍)在 SYN 包中协商。
- 协商机制:连接建立时(SYN 段),发送方在 TCP 选项中声明 Window Scale(WSOPT,Kind=3,Length=3,Shift.cnt=缩放值)。接收方如果支持,也在 SYN-ACK 中回应相同的选项。
- 性能益处:拿我们上面的示例来说(BDP=18.75MB),如果 Shift.cnt=14(16384 倍),16 位字段只需 1146(18.75MB / 16384)就可以覆盖整个Tunnel,避免带宽闲置。
Tips:用 Wireshark 抓包查看 SYN 包的选项字段是否有 WSOPT ,确认缩放是否生效。
TCP 时间戳(Timestamps):
高延迟网络下,RTT 估算不准会导致拥塞控制失灵,窗口调整迟钝。RFC 1323 的时间戳选项(TSOPT,Kind=8)在每个段中嵌入 32 位时间戳(TSval)和回显值(TSecr),用于两个目的:
- RTT 测量(RTTM):接收方回显发送方的 TSval,发送方计算精确 RTT(不受重传干扰),优化窗口增长和重传超时。
- 序列号包装保护(PAWS):在高吞吐量的情况下,32 位序列号容易wrap around,通过时间戳检查,过时的包会被丢弃,保证序列正常。
Tips:时间戳虽然增加了 12 字节的开销,但感觉是利大于弊 —— Red Hat 等系统默认启用,能更好地估算 RTT , Windows 也默认支持。
时间戳可能泄露系统时钟,但 RFC 建议随机偏移来防止时序攻击,要自己考量
路径 MTU 发现(Path MTU Discovery)
虽然不是 RFC 1323 核心,但1323更新了 RFC 1191 的 PMTUD,支持了 DF(Don’t Fragment)位和 ICMP 反馈,动态寻找链路里最大的传输单元(MTU)。这防止了分片开销,在高延迟链路中减少重传的次数。当我们用 VPN , MTU 也不会乱序匹配,这确保了包大小自适应,避免“黑洞”路由出现。
RFC 1323 已于 2015 年被 RFC 7323 更新(obsoleted),但核心机制不变。 在 Windows 上,通过 netsh 命令来调整(比如打开 PMTUD)
4. 还有什么要说的……
常见瓶颈排查
- 路由器/ISP 限制:检查是否启用了 QoS 限制,或 ISP 的国际出口堵塞。可以用
tracert google.com
看看高延迟的节点。 - DNS:测一下延迟,建议用低延迟的非运营商 DNS 。
- 连接方式:优先用有线连接,减少 Wi-Fi 信号弱导致的衰减。
- MTU:默认 MTU 1500 适合大多数场景,但如果连续使用 VPN,可以试试修改:
netsh interface ipv4 set subinterface "以太网" mtu=1400 store=persistent
。 - 你在哪里:地区的不同导致出口延迟不同,建议肉身横渡。
额外优化
- 启用 CTCP(复合 TCP):增强拥塞控制:
netsh interface tcp set global congestionprovider=ctcp
。在高带宽高延迟场景下更高效。 - 禁用 Nagle 算法(游戏/Live):
netsh interface tcp set global nagle=disabled
。但这会增加小包开销,不适合文件传输,其实不太推荐。 - VPN 优化:如果经常用 VPN,选择 WireGuard 协议,会自动处理窗口缩放。
- 禁用代理(ProxyEnable):如果用不着代理服务器,那开启代理可能会增加额外延迟。通过注册表编辑器(regedit)导航到
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings
,将ProxyEnable
的值设置为0
(DWORD 类型)。
参考:
ietf.org
knowledge.broadcom.com
cisco.com
learn.microsoft.com
rfc-editor.org