V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iqoo
V2EX  ›  程序员

关于 TCP delayed ACK 问题

  •  
  •   iqoo · 2022-10-11 11:42:42 +08:00 · 2053 次点击
    这是一个创建于 772 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    第 1 条附言  ·  2022-10-11 13:47:40 +08:00
    如果我方 ACK 应答时机控制恰到好处,对方会认为带宽充足,没有丢包,每批次的包数也会增加。对方甚至会一次发几百个包,而我只需答复一个 ACK 包就行。几十字节即可换几百 KB 。
    17 条回复    2022-10-12 14:15:43 +08:00
    sujin190
        1
    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
        2
    sujin190  
       2022-10-11 11:58:20 +08:00
    TCP delayed ACK 好像说的是稍微延迟 ack ,然后把多个 ack 放在一个 ip 包里发送,用于减少 ip 包的数量,并没有说可以跳过中间的 ack 直接发送最后一个就行
    tool2d
        3
    tool2d  
       2022-10-11 12:02:20 +08:00
    可以写一个 ip filter 网卡驱动过滤层,用代码去识别多余的一些 ACK IP 包,给主动过滤掉。
    laozhoubuluo
        4
    laozhoubuluo  
       2022-10-11 12:08:14 +08:00
    设置估计是没啥戏,因为这个不是标准实现。
    要做的话估计只能改内核实现,理论来说可以做到收到重传时才回复 ACK ,这样是最省入流量的。
    iqoo
        5
    iqoo  
    OP
       2022-10-11 13:10:20 +08:00
    @laozhoubuluo 其实也不一定。重传再应答,之后对方可能会降低窗口。本来对方一次发 20 个包停止,等我的 ack ,现在可能一次只发 10 个包,就在等我的 ack 。最理想的情况是踩着对方的窗口应答,当然需提前知道对方窗口相关的参数。
    newmlp
        6
    newmlp  
       2022-10-11 13:37:24 +08:00
    老老实实换 udp 吧
    iqoo
        7
    iqoo  
    OP
       2022-10-11 13:43:58 +08:00
    @sujin190
    @newmlp 目标服务就是 HTTP ,不可控
    jedihy
        8
    jedihy  
       2022-10-11 13:44:15 +08:00   ❤️ 1
    LS 有人说过了,写一个 filter driver 丢弃一些 ACK 是可行的,或者合并一些累计确认也是可以的。

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

    其实那点流量不算什么,主要是频繁调用的 net io 导致 cpu“浪费”比较严重
    cubecube
        13
    cubecube  
       2022-10-11 16:33:22 +08:00
    @sujin190 你理解得不对,就是跳过。对端只关心你 ack 的序号。tcpdump 看看就明白了
    gam2046
        14
    gam2046  
       2022-10-11 17:18:42 +08:00
    优化方向是不是值得重新考虑,如果这点流量都需要算计出来,那 HTTP 头的浪费可远比这些大多了。
    sujin190
        15
    sujin190  
       2022-10-11 17:36:17 +08:00
    @cubecube #13 好吧,记错了,seq 是数据流的 offset ,那确实可以合并跳过
    iqoo
        16
    iqoo  
    OP
       2022-10-11 19:34:42 +08:00
    @gam2046 HTTP 头不过 100 字节,ACK 都有 160KB 了( 20MB 的文件)
    Defined
        17
    Defined  
       2022-10-12 14:15:43 +08:00
    打 ko 改协议栈?一直不回 ack 的话 client 端的窗口很容易就满了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   990 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 20:19 · PVG 04:19 · LAX 12:19 · JFK 15:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.