美文网首页
【tcp】TCP_NODELAY 何许人也?

【tcp】TCP_NODELAY 何许人也?

作者: Bogon | 来源:发表于2022-07-31 05:36 被阅读0次

    为什么加了 TCP_NODELAY ,时延就从 39.2ms 降低到 2.8ms?

    为什么本地测试的平均时延是 55ms,而不是 ping 的时延 26ms?

    TCP 协议究竟是怎么发送数据包的?

    TCP_NODELAY 何许人也?

    在 Socket 编程中,TCP_NODELAY 选项是用来控制是否开启 Nagle 算法。
    在 Java 中,为 ture 表示关闭 Nagle 算法,为 false 表示打开 Nagle 算法。你一定会问 Nagle 算法是什么?

    Nagle 算法是什么鬼?

    Nagle 算法是一种通过减少通过网络发送的数据包数量来提高 TCP/IP 网络效率的方法。
    它使用发明人 John Nagle 的名字来命名的,John Nagle 在 1984 年首次用这个算法来尝试解决福特汽车公司的网络拥塞问题。

    试想如果应用程序每次产生 1 个字节的数据,然后这 1 个字节数据又以网络数据包的形式发送到远端服务器,那么就很容易导致网络由于太多的数据包而过载。在这种典型情况下,传送一个只拥有1个字节有效数据的数据包,却要花费 40 个字节长包头(即 IP 头部 20 字节 + TCP 头部 20 字节)的额外开销,这种有效载荷(payload)的利用率是极其低下。

    具体的做法就是:

    如果发送内容大于等于 1 个 MSS, 立即发送;

    如果之前没有包未被 ACK, 立即发送;

    如果之前有包未被 ACK, 缓存发送内容;

    如果收到 ACK, 立即发送缓存的内容。(MSS 为 TCP 数据包每次能够传输的最大数据分段)

    Delayed ACK 又是什么玩意?

    大家都知道 TCP 协议为了保证传输的可靠性,规定在接受到数据包时需要向对方发送一个确认。
    只是单纯的发送一个确认,代价会比较高(IP 头部 20 字节 + TCP 头部 20 字节)。

    TCP Delayed ACK(延迟确认)就是为了努力改善网络性能,来解决这个问题的,它将几个 ACK 响应组合合在一起成为单个响应,或者将 ACK 响应与响应数据一起发送给对方,从而减少协议开销。

    具体的做法是:
    当有响应数据要发送时,ACK 会随响应数据立即发送给对方;

    如果没有响应数据,ACK 将会延迟发送,以等待看是否有响应数据可以一起发送。在 Linux 系统中,默认这个延迟时间是
    40ms;

    如果在等待发送 ACK 期间,对方的第二个数据包又到达了,这时要立即发送 ACK。但是如果对方的三个数据包相继到达,第三个数据段到达时是否立即发送 ACK,则取决于以上两条。

    Nagle 与 Delayed ACK 一起会发生什么化学反应?

    Nagle 与 Delayed ACK 都能提高网络传输的效率,但在一起会好心办坏事。

    例如,以下这个场景:

    A 和 B 进行数据传输 : A 运行 Nagle 算法,B 运行 Delayed ACK 算法。

    如果 A 向 B 发一个数据包,B 由于 Delayed ACK 不会立即响应。而

    A 使用 Nagle 算法,A 就会一直等 B 的 ACK,ACK 不来一直不发送第二个数据包,如果这两个数据包是应对同一个请求,那这个请求就会被耽误了 40ms。

    我们来抓个包验证下,在后端HTTP服务上执行以下脚本,就可以轻松完成抓包过程。

    tcpdump -i eth0 tcp  and host  10.48.159.165  -s  0  -w traffic.pcap
    

    如下图,这是使用 Wireshark 分析包内容的展示,红框内是一个完整的 POST 请求处理过程,看 130 序号和 149 序号之间相差 40ms(0.1859 - 0.1448 = 0.0411s = 41ms),这个就是 Nagle 与 Delayed ACK 一起发送的化学反应,其中 10.48.159.165 运行的是 Delayed ACK,10.22.29.180 运行的是 Nagle 算法。

    10.22.29.180 在等 ACK,而 10.48.159.165 触发了 Delayed ACK,这样傻傻等了 40ms。

    这也就解释了为什么测试环境耗时是 39.2ms,因为大部分都被 Delayed ACK 的 40ms 给耽误了。

    但是本地复现时,为什么本地测试的平均时延是 55ms,而不是 ping 的时延 26ms?

    如下图,红框内是一个完整的 POST 请求处理过程,看 8 序号和 9 序号之间相差 25ms 左右,再减去网络延时约是ping延时的一半 13ms,因此 Delayed Ack 约 12ms 左右(由于本地是 MAC 系统与 Linux 有些差异)。

    image.png

    Linux 使用的是 /proc/sys/net/ipv4/tcp_delack_min 这个系统配置来控制 Delayed ACK 的时间,Linux 默认是 40ms。

    为什么 TCP_NODELAY 能够解决问题?

    TCP_NODELAY 关闭了 Nagle 算法,即使上个数据包的 ACK 没有到达,也会发送下个数据包,进而打破 Delayed ACK 造成的影响。

    一般在网络编程中,强烈建议开启 TCPNODELAY,来提升响应速度。

    当然也可以通过 Delayed ACK 相关系统的配置来解决问题,但由于需要修改机器配置,很不方便,因此,这种方式不太推荐。

    相关文章

      网友评论

          本文标题:【tcp】TCP_NODELAY 何许人也?

          本文链接:https://www.haomeiwen.com/subject/azigmrtx.html