TCP与UDP在加速中的取舍

list 文章目录

TCP和UDP的对比往往被简化为一句话:TCP可靠,UDP不可靠。

就协议定义而言这句话没问题,却把工程上最关键的一点掩盖了:’可靠‘与’不可靠‘不存在谁更好,只看怎么取舍。TCP 取可靠,代价是排队与等待;UDP 放弃这一层保证,换来响应速度与掌控力。做加速时二者路线完全不同:TCP 一侧要消化的是可靠性的时延账单,UDP 一侧则是在’不承诺必达‘的底子上,按需补偿丢包。

两边的加速手段不能混用:把TCP那套逻辑搬到UDP上会伤同步性,把UDP那套搬到TCP上又解决不了窗口增长受限的异常。

TCP的代价:顺序交付与队头阻塞

TCP向应用层提供一个保证:数据按发送顺序到达,不丢、不重、不乱。为了维持这个保证,TCP在协议栈内部做了几件事。

接收端会维持一个用于重排的缓冲区。IP 网络里乱序是常态,不同的包很可能走了不同的路;一旦到达次序与发送次序不符,接收端就得先把缺口补齐,才能把后面的数据交给上层。这就是队头阻塞(Head-of-Line Blocking):丢一个包,后面所有已经抵达的包都被挡在缓冲区里。

队头阻塞在长 RTT 链路上尤其致命。取 RTT 为 200ms:丢一个包,接收端至少要等 200ms 才能收到补发;这 200ms 内,陆续抵达的数据全被扣留。应用层察觉到的并不是’200ms 之后慢慢恢复‘,而是’先静默 200ms,随后数据一起倒出来‘。网页上的反应是某个资源卡住后突然加载完成;放到实时场景则难以接受——200ms 之前的游戏状态早已没有价值。

TCP 的另一笔代价来自它保守的拥塞控制。慢启动期间窗口指数式膨胀看似凌厉,可一旦逼近链路容量,基于丢包的算法会主动制造一次丢包去试探上限,再把窗口收窄重新爬坡。短 RTT 上这套循环很快;到了长 RTT 链路,每次丢包之后都需要数个 RTT 才能重新跑满。

加速器如何介入TCP

TCP加速器的核心逻辑是:把TCP的代价隔离在短RTT段内。

把端到端的一条 TCP 分成两段,每一段的 RTT 都会明显下降,用户到加速节点的往返常常只剩直连时的三分之一到四分之一。队头阻塞依然存在,但它封锁的时长与 RTT 成正比,RTT 越短,解开得越快。窗口恢复也跟着提速:在 200ms RTT 上需要 2 秒才能爬完的窗口,在 50ms RTT 上 0.5 秒就走完了。

不过拆分也带来了副作用:两段 TCP 彼此独立,拥塞状态互不可见。用户侧到节点这一段可能非常宽松,窗口一路抬升;节点到目标这一段却在排队,窗口被压着。数据于是高速灌入节点,堆在它的发送缓冲区里。只要堆积量超过’节点到目标‘链路的带宽延迟积,凭空多出来的排队时延就在加速器内部产生了。

这意味着,加速器的有效运作要求节点的缓冲区管理连接规则与两段网络的吞吐上限差异匹配。一旦入口网络远快于通道出口网络(比如用户是千兆宽带,通道出口网络起因是跨洋而只有几十Mbps的有效吞吐量),节点必须主动向用户端施加反压——通过调整TCP窗口或延迟ACK来降低入口段的发送速率。不做这个优化的加速器,会在节点内部制造自己的拥塞点。

流量不设上限,安全同样不打折。狗急加速器对每条会话做加密处理,中转节点无法读取内容,也不采集访问记录。

UDP的设计:不保证,不阻塞

UDP向应用层提供的是一个完全不同的契约:数据报尽力交付,不保证到达,不保证顺序。一旦数据报丢失,UDP不重新传输。一旦数据报乱序,UDP不重排。应用层收到什么就是什么,UDP不替应用做任何决定。

恰是这个’把选择权留给应用‘的设计,让众多实时应用站到了 UDP 一侧。游戏、VoIP、实时视频这类场景,看重的是时效而非完整:语音包不见了,宁可听一段静音,也不希望 200ms 之后把已经过时的音频塞回当前时刻;游戏里丢掉一次位置更新也无妨,只要更新够密,下一包几毫秒就会把它覆盖。

UDP把可靠性决策权交给了应用层。应用得以自己实现选择性重新传输(只重新传输关键数据分片),得以实现FEC(用冗余换丢包恢复),也得以什么都不做(容忍丢包)。这种灵活性是UDP在同步场景中的核心价值。

但UDP在公网上有一个结构性的劣势:网络中间设备对它的态度。

当链路真的拥塞时,路由器的队列管理往往站在 TCP 一边。以 WRED 这类主动队列管理算法为例,它们会有选择地丢弃 UDP 数据报,原因很直接:UDP 不像 TCP 那样收到拥塞信号便主动降速。于是一条不减速的 UDP 流在拥堵链路上被视为’不合作的流量‘,优先被标记或抛弃。这也解释了高峰期 UDP 丢包率通常高于 TCP——并不是 UDP 更脆弱,而是设备策略在设计上就去维护 TCP 的公平。

加速器对UDP能做什么

加速器的路由选择

UDP加速不需先拆分连接,起因是UDP没有连接。UDP加速不需先管理拥塞窗口,起因是UDP没有窗口。那么加速器在做什么?

路径选择仍然是第一位的。一旦加速器能将UDP数据分片从一条丢包率2%的公共路径迁移到一条丢包率0.2%的私有骨干网路径,实际效果直接体现在应用层的丢包减少上。这部分逻辑和TCP加速相同,但对UDP的收益往往更相当直观——起因是UDP对丢包没有自愈能力,丢一个就是一个。

在这条更优的路径之上,加速器得以在两端节点之间增加FEC。发送端在连续N个数据分片后附加M个冗余包,使得接收端在N+M个包中任意丢失不超过M个时都能完整恢复。FEC不消除丢包——物理网络上的数据分片仍然在丢失——但它让应用层感知到的丢包率降到零。

FEC 要付的账主要有两项:多出来的带宽占用,以及编码带来的时延。发送端必须攒够一定数量的数据包才能算出冗余包——高频小包(比如每秒 60 个更新包)几乎不受影响,攒 4 个包约 67ms;低频流量则可能要等上更久。这段累积时间加上运算本身的耗时,就是加速器额外带进来的处理延迟。

一边是不限流量的自由,一边是看得见的保护。全程加密与零日志策略同时生效,专线节点只负责转发,不负责记录。

在工程实践中,经常观察到一个权衡:开启FEC后,游戏内显示的丢包率回落,但基础ping值增加了3-5ms。对大多数玩家来说,丢包率从1%降到0带来的体验迎来好转远大于ping值增加5ms的代价。但对于对延迟极度敏感的场景(比如职业电竞),这个权衡需先被明确意识到。

误判:QUIC与”UDP加速”

QUIC是一个基于UDP的传输协议,它在应用层实现了类似TCP的可靠传输和拥塞控制。很多加速服务声称支持”UDP加速”,但实际测试会发现它们对QUIC的处理并不一致。

一些加速器将QUIC数据吞吐当作普通UDP处理——单纯转发,不做FEC,不做路径优化。这是合理的,起因是QUIC已经内置了拥塞控制和丢包恢复,外部的FEC可能会干扰QUIC自身的速率调节逻辑。但一旦加速器对QUIC什么都不做,用户看到的效果就和直连没有区别(除了路径可能会不同)。

另一些加速器会尝试对QUIC数据吞吐也做TCP式的分段中继——终结QUIC连接,在内部用自定义协议传输,到通道出口节点再重建QUIC连接。这种做法等于破坏了QUIC的全链路加密和认证模型,往往需先客户端安装根证书才能中间人解密。对用户来说,带来的安全风险可能会超过加速收益。

一个更容易混淆的情况是,加速器宣称”UDP加速”,但实际只优化了特定端口的UDP数据吞吐(比如常见的游戏端口),而对QUIC使用的443端口的UDP数据吞吐走的是另一套逻辑(甚至可能会被降级为直连)。用户在进行数据测速时看到UDP加速有效,但在使用QUIC的应用(比如基于HTTP/3的网站、某些视频流)时感受不到迎来好转,原因就在这里——两种UDP数据吞吐经过了不同的处理管道。

bash
# 逐项核对某个应用使用的UDP端口和协议
# QUIC往往使用UDP 443
ss -tunlp | grep 应用进程名

# 抓包观察UDP数据吞吐的行为模式
# QUIC的包往往较大,且有TLS握手的特征
tcpdump -i eth0 -n udp port 443 -c 50

协议的边界与选择

追根到底,TCP 与 UDP 在加速上的分野在于承诺不同。TCP 承诺可靠、有序,加速器只能靠分段把这些承诺附带的时延隔离开来;UDP 不作任何承诺,看似天地更宽,实则更受掣肘——不能假设包的含义、不能重排顺序、不能随便加时延,能做的只有优化路径与少量冗余。

这一点决定了谁配什么手段才合理:网页和 API 调用靠 TCP,要压的是握手时延与窗口爬升时间;游戏和实时通信靠 UDP,要压的是丢包率与路径抖动。把照着 TCP 设计的方案硬套到 UDP 上,比如强行做分段中继,要么会破坏实时性,要么因为协议对不上而干脆连不通。

反过来,一旦试图用UDP的”尽力而为”逻辑去加速TCP——比如只做路径转发不做连接分段——那等于放弃了所有TCP层面的优化可能会,退化为一个纯粹的VPN。

弄清两个协议在设计上各自放弃了什么,不是为了背一份对照表,而是拿到某个加速方案时,能够判断它的核心逻辑扎在哪一侧,以及它与你流量类型的匹配度。两者不可互换,可惜多数用户并不知道自己在跑哪个协议。与其直接对比各家标称的延迟数字,不如先把流量的协议构成摸清楚。

作者

狗急加速器技术团队

安全与性能都要兼顾

流量不设上限,安全同样不打折。狗急加速器对每条会话做加密处理,中转节点无法读取内容,也不采集访问记录。

协议选择之外,还有一层容易被忽略:加密强度与稳定性的平衡。只顾速度而忽略加密,数据就等于暴露在公共网络上;只强调加密却不看线路质量,体验又会拖垮。

狗急加速器在这两件事上没有取巧:传输全程加密,不留访问日志,同时通过专线保障跨境这一段的稳定。

自动选择不等于黑箱

有人不喜欢自动策略,理由是不知道程序替自己做了什么。这个顾虑合理,所以我们在客户端里把当前使用的协议、节点与实时质量都明确展示出来。

你可以随时查看,也可以在需要时手动固定某条线路。自动化是为了减少重复劳动,不是剥夺控制权。

同时这套策略的触发条件也很清楚:丢包或抖动超过阈值就切换。不是随机乱跳,而是有明确的判断依据。