// 网络协议 · 深度图解
TCP over TCP
灾难性性能崩溃
当 VPN 使用 TCP 封装传输 TCP 流量时,两层拥塞控制相互干扰,造成吞吐量指数级崩溃。本文用图解方式还原这个经典问题的完整机制。
§ 01
正常单层 TCP — 丢包重传机制
CLIENT
应用层
SERVER
应用层
互联网
⚡ 1% 丢包率
SEQ=1
SEQ=2 ✗ 丢失
× 丢弃
ACK=1 ✓
⟳ 重传 SEQ=2(单次处理,快速恢复)
✓ 只有一层 TCP 退避 → cwnd/2 → 快速恢复,影响轻微
单层 TCP 的
AIMD(加法增大乘法减小)
拥塞控制:丢包时窗口减半,然后线性增长恢复。整个过程由一个控制器管理,
收敛速度快
,通常数个 RTT 内恢复正常吞吐。
§ 02
IP/TCP-in-TCP 封装结构 — VPN tun 设备如何工作
客户端
应用程序
Inner TCP
Inner IP
私网 10.x.x.x → 10.y.y.y
← tun 在此截获完整 IP 包
tun 虚拟网卡
加密 + VPN 封装
Outer TCP
Outer IP
公网 1.2.3.4 → 5.6.7.8
物理网卡
服务端
应用程序
Inner TCP
Inner IP
私网 10.x.x.x → 10.y.y.y
tun 虚拟网卡
解密 + VPN 解封装
Outer TCP
Outer IP
公网 1.2.3.4→ 5.6.7.8
物理网卡
物理网络上传输的完整数据包
Outer 层(互联网可见)
Outer IP Header
公网IP
Outer TCP Header
VPN端口
🔒 VPN 加密载荷(路由器/运营商无法读取内部)
Inner IP Header
私网IP
Inner TCP Header
应用端口
Application Data
HTTP / SSH / 任意应用数据
(已加密,外界不可见)
✦ 原图遗漏此层
互联网(路由器只能看到 Outer IP + Outer TCP)
可能发生丢包 · 延迟抖动 · 拥塞
⚠ tun 设备截获的是完整 IP 包(Inner IP + Inner TCP + Data)
Outer TCP 与 Inner TCP 各自独立维护拥塞窗口和重传计时器 — 互不知晓
正式名称应为 "IP-in-TCP","TCP over TCP" 是工程界约定俗成的简称
精确说明
:VPN 使用 tun 虚拟网卡在
网络层(L3)
拦截流量,拿到的是包含
Inner IP Header
的完整 IP 数据包,而非裸 TCP 段。因此准确名称是
"IP-in-TCP"
或
"TCP/IP over TCP"
。"TCP over TCP" 只是业界简称,强调两层 TCP 拥塞控制冲突这一核心问题。
§ 03
灾难时序 — 崩溃循环完整演示
时间
Outer TCP(VPN 隧道层)
cwnd = 拥塞窗口
Inner TCP(应用层)
cwnd = 拥塞窗口
吞吐量
T0 — 正常
cwnd = 64 (满速)
正常传输加密数据包
cwnd = 64 (满速)
正常传输应用数据
100%
▼ 网络丢包事件发生
T1 — 丢包
⚡ 检测到丢包!
cwnd: 64 → 32(减半)
启动重传,RTT 上升
RTT 开始上升...
cwnd 暂未变化
等待 ACK 超时
~50%
T2
误判丢包
Outer TCP 重传中...
cwnd = 32,持续发送
(加密隧道暂时阻塞)
⚡ ACK 超时!误以为丢包!
cwnd: 64 → 32(再次减半)
Inner TCP 也开始重传 → 加剧 Outer 积压
~25%
T3
双层退避
Inner 重传包涌入
Outer 缓冲区膨胀
cwnd: 32 → 16(再次减半)
RTT 暴增(因 Outer 积压)
再次触发超时重传
cwnd: 32 → 16 → 继续退避
~8%
T4 — 崩溃
几乎停滞
🔴 双层 TCP 同时进入 RTO 超时等待(秒级!)
Outer cwnd = 1,Inner cwnd = 1 → 吞吐量趋近于零
Inner 每次重传都要等 Outer 的 RTO,Outer 的 RTO 又被 Inner 积压撑大 → 无限循环
~1%
死亡
T5 — 恢复
缓慢爬升
两层 TCP 各自独立缓慢恢复,但任何新的丢包都会再次触发崩溃循环
恢复时间:正常 TCP ≈ 几个 RTT | TCP over TCP ≈ 数十秒甚至分钟级
~10%
⟲ 恶性循环:任意新丢包 → 重回 T1,双层退避再次叠加
由于每轮 RTO 比上一轮更长(指数退避),系统吞吐在较差网络下将长期处于崩溃态
§ 04
吞吐量对比 — 丢包事件后的恢复曲线
100%
75%
50%
25%
0%
吞吐量
0s
2s
4s
6s
8s
10s
12s
时间
⚡ 丢包事件
普通 TCP — 快速恢复
TCP over TCP — 持续崩溃
AIMD
线性恢复
双层 cwnd
同时→1,停滞
普通 TCP(单层)
TCP over TCP(VPN TCP模式)
关键差异
:普通 TCP 丢包后通过 AIMD 在数秒内恢复到 ~90% 吞吐;TCP over TCP 在相同丢包后可能需要
数十秒到数分钟
才能部分恢复,且在存在持续丢包的网络环境下(如 2G/3G、拥塞 WiFi)几乎无法维持可用吞吐。
§ 05
解决方案 — 为什么 UDP 封装解救了问题
OpenVPN
TCP 模式
Outer IP + Outer TCP(OpenVPN)
🔒 加密载荷
Inner IP
Hdr
Inner TCP
Hdr
App Data
封装协议
TCP
TCP over TCP 问题
✗ 有
丢包下性能
灾难性崩溃
防火墙穿透
易穿透 (443)
OpenVPN
UDP 模式
Outer IP + Outer UDP(OpenVPN)
🔒 加密载荷
Inner IP
Hdr
Inner TCP
Hdr
App Data
封装协议
UDP
TCP over TCP 问题
✓ 无
丢包下性能
Inner TCP 正常控制
防火墙穿透
UDP 可能被封
WireGuard
UDP 模式
Outer IP + Outer UDP(WireGuard)
🔒 加密载荷
Inner IP
Hdr
Inner TCP
Hdr
App Data
封装协议
UDP
TCP over TCP 问题
✓ 无
丢包下性能
Inner TCP 正常控制
防火墙穿透
UDP 可能被封
为什么 UDP 封装解决了问题?
Outer TCP 时:两层拥塞控制冲突
Inner IP
Inner TCP
冲突
Outer TCP
网络
丢包 → Outer TCP 重传 + cwnd 减半
Inner TCP 因延迟暴增误判丢包 → 也退避
→ 双层同时退避 → 吞吐崩溃
Outer UDP 时:控制权归还 Inner TCP
Inner IP
Inner TCP
Outer UDP
无重传逻辑
网络
丢包 → UDP 无状态,直接丢弃该 IP 包
Inner TCP 感知丢包 → 正常 AIMD 退避
→ 只有一层退避 → 正常快速恢复
核心原理
:UDP 是无状态、无重传的传输协议。当用 UDP 封装 TCP 时,Outer UDP 碰到丢包直接忽略,
把丢包的感知和处理权完全交给 Inner TCP
。于是整个系统退化为单层 TCP 行为,拥塞控制重新变得可预测和高效。
TCP OVER TCP PROBLEM // NETWORK PROTOCOL ANALYSIS
参考:OpenVPN FAQ, RFC 793, Olaf Titz "Why TCP Over TCP Is A Bad Idea" (2001)