关于 TCP delayed ACK 问题

2022-10-11 11:42:42 +08:00
 iqoo

使用 HTTP 下载一个 20MB 的文件,抓包发现客户端应答了 2500 多个 ACK 包,总共 160KB 。

如果绕过 TCP 协议栈(比如 libpcap )写一个 HTTP 下载程序,客户端隔较长时间答复 ACK ,最终只应答了 60 个 ACK 包,文件同样也能传输成功,而客户端只发送了几 KB 的流量。

不知常用的系统(比如 Linux )是否可通过设置,把 ACK 应答数量减少到极致?看了下 TCP delayed ACK ,规定最大超时是 500ms ,并且收到的数据量足够时就得应答。貌似不好实现。

有些场景下,机器出流量昂贵,但入流量免费且带宽充足,因此即使对方重传包也不影响费用,而我方产生 ACK 则是计费的,因此越少越好。

2081 次点击
所在节点    程序员
17 条回复
sujin190
2022-10-11 11:55:37 +08:00
你都绕过 tcp 了,那就直接用 udp 呗,莫非你是想传输的还是 tcp 包,但是不发 ack ? tcp 是要求每个 ip 包都必须有 ack 的吧,因为丢包可能只是中间某个包丢了,前后都没问题,没收到 ack 的 ip 包就是丢包了需要重传,tcp 协议似乎并不能处理你说的这种可以跳 ack 的情况,所以如果你想要这样那你似乎要同时自己实现 client 和 server ,不过既然你都这样干了,直接用 raw socket 就行吧
sujin190
2022-10-11 11:58:20 +08:00
TCP delayed ACK 好像说的是稍微延迟 ack ,然后把多个 ack 放在一个 ip 包里发送,用于减少 ip 包的数量,并没有说可以跳过中间的 ack 直接发送最后一个就行
tool2d
2022-10-11 12:02:20 +08:00
可以写一个 ip filter 网卡驱动过滤层,用代码去识别多余的一些 ACK IP 包,给主动过滤掉。
laozhoubuluo
2022-10-11 12:08:14 +08:00
设置估计是没啥戏,因为这个不是标准实现。
要做的话估计只能改内核实现,理论来说可以做到收到重传时才回复 ACK ,这样是最省入流量的。
iqoo
2022-10-11 13:10:20 +08:00
@laozhoubuluo 其实也不一定。重传再应答,之后对方可能会降低窗口。本来对方一次发 20 个包停止,等我的 ack ,现在可能一次只发 10 个包,就在等我的 ack 。最理想的情况是踩着对方的窗口应答,当然需提前知道对方窗口相关的参数。
newmlp
2022-10-11 13:37:24 +08:00
老老实实换 udp 吧
iqoo
2022-10-11 13:43:58 +08:00
@sujin190
@newmlp 目标服务就是 HTTP ,不可控
jedihy
2022-10-11 13:44:15 +08:00
LS 有人说过了,写一个 filter driver 丢弃一些 ACK 是可行的,或者合并一些累计确认也是可以的。

除非你的出口流量真的贵,不然的话有一些缺点:
1. 会造成发送方流量突发。因为每个 ACK 能够"clock"的数据量变大了。
2. ACK return 路径上的丢包会更容易导致发送发重传( RTO/TLP )进而降速。
3. 某一些 TCPIP 实现,每个 ACK 能够增加的 cwnd 有限制。如 Windows 的 TCP ,每个 ACK 只能增加 8MSS 的 cwnd 。过少的 ACK 会导致慢启动阶段非常慢。
zhs227
2022-10-11 14:19:48 +08:00
TCP 如果没有足够的 ACK 会窗口打不开,如果有丢包的话没办法快速的收敛到新的带宽大小上,有很多问题, 只适用于极有限的场景。不过单向数据发送这种场景,另一侧的 Ack 是冗余量较大的,之前试过反向丢掉 70%都没太大影响。
iqoo
2022-10-11 14:51:07 +08:00
@zhs227 下载速度不敏感的场景可以尝试,比如后台的文件下载任务。如果连接数多,总吞吐反而更高。
wangritian
2022-10-11 15:50:30 +08:00
查了些文章,据说 centos 可以通过 echo 500 > /proc/sys/net/ipv4/tcpdelackmin 设置 ack 的定时器间隔
如果收到多个数据包会强制触发 ack ,不知道在交换机上对入网数据包拼装成巨型帧能否解决?
lysS
2022-10-11 16:00:25 +08:00
ack 的频率越高,流控、拥塞避免越接近算法的理论表现。tcp 在低速情况下每收到一个包都回复 ack ,在稳定的高速情况下,可能收到几个数据包才回复一个 ack ,我测得的最大值是 3 。

其实那点流量不算什么,主要是频繁调用的 net io 导致 cpu“浪费”比较严重
cubecube
2022-10-11 16:33:22 +08:00
@sujin190 你理解得不对,就是跳过。对端只关心你 ack 的序号。tcpdump 看看就明白了
gam2046
2022-10-11 17:18:42 +08:00
优化方向是不是值得重新考虑,如果这点流量都需要算计出来,那 HTTP 头的浪费可远比这些大多了。
sujin190
2022-10-11 17:36:17 +08:00
@cubecube #13 好吧,记错了,seq 是数据流的 offset ,那确实可以合并跳过
iqoo
2022-10-11 19:34:42 +08:00
@gam2046 HTTP 头不过 100 字节,ACK 都有 160KB 了( 20MB 的文件)
Defined
2022-10-12 14:15:43 +08:00
打 ko 改协议栈?一直不回 ack 的话 client 端的窗口很容易就满了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/886029

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX