TCP之Nagle算法

江枫思渺然 提交于 2019-12-06 09:03:57

Nagle算法

Nagle算法是为了提高带宽利用率而设计的算法,该算法主要用于避免过多小分节报文在网络中传输。比如一个20字节的TCP首部+20字节的IP首部+1个字节的数据组成的TCP数据报,有效传输通道利用率只有将近1/40。如果网络充斥着这样的小分组数据,则网络资源的利用率是相当低下的。

如果开启了这个算法 (TCP默认开启),则协议栈会累积数据直到以下两个条件之一满足的时候才真正发送出去:(1)积累的数据量达到MSS (2)有未确认的包存在时收到了一个 Ack包

Nagle算法在维基百科上用伪代码描述如下:

if there is new data to send
  if the window size >= MSS and available data is >= MSS
    send complete MSS segment now
  else
    if there is unconfirmed data still in the pipe
      enqueue data in the buffer until an acknowledge is received
    else
      send data immediately
    end if
  end if
end if

 

副作用

 

在介绍Nagle算法的副作用前要引入TCP的另外一个机制TCP Delayed Acknoledgement,这个机制也是以减少网络中小包为目标被设计出来的。它的作用就是延迟 Ack 包的发送,使得协议栈可以把Ack包和其它Ack包或数据包合并发送,提高网络性能。当然Delayed Ack是有个超时机制的,超时时间是40ms~200ms。

然而Nagle算法和TCP Delayed Ack算法的组合有可能降低网络性能:

如果一个TCP连接的A端和B端启用了 Nagle‘s Algorithm,而交互的数据包又小于MSS,则可能会出现这样的情况:A端在发送新数据前发现还有数据的ACK包没有收到,那么A端打算等到收到ACK包后再发送新数据,同时B端却因为ACK包太少延迟了这些ACK包的发送,这样有些包的耗时很有可能大于40ms。

那么如果Nagle算法和TCP Delayed Ack算法有如此大的副作用,TCP为何会默认启动它呢。因为最常见的write-read-write-read模式不会触发这个副作用,只有write-write-read模式会受影响。

write-read-write-read模式:A端第1次write,由于没有未确认的数据,数据被立刻发送出去。B端的ACK包虽然不会立刻返回,是跟随处理完的响应数据一起发回A端的,但是并不影响整个流程,因为A端反正要等待响应数据才会继续下去,之后的每次write-read交互过程都是如此。

write-write-read模式:这种场景业务逻辑层进行了分包,也就是说B端要等到A端的2个write包到达才会响应,例如爬虫把HTTP Header和Body分开发送。下面来模拟这一模式,A端第1次write,数据被立刻发送出去,第2次write因为第1次的包的Ack还没回来,被缓存了下来等待Ack,这一等很可能就是40ms甚至200ms。那B端为什么迟迟不回Ack呢?因为Ack包也被缓存下来了,准备等A端的2次write到齐了连同响应数据一起发回A端。这种情况很像操作系统死锁的循环等待条件,A端在等待B端的Ack才发第2次write,B端在等待A端的第2次write才发Ack(连同两个write的响应)。

 

解决办法

TCP_NODELAY选项

顾名思义,TCP_NODELAY套接字选项可以关闭Nagle算法,如果我们在程序的逻辑层可以避免太小包的存在,完全可以关闭Nagle算法,避免不可预期的网络延迟问题,尤其是对响应的实时性比较高的系统。

int enable = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&enable, sizeof(enable));

Nginx也有tcp_nodelay配置来关闭Nagle算法。

 

题外话

Nagle算法是为了避免太小的包占用网络带宽,而有一个选项TCP_CORK可以看做Nagle的极端版本。TCP_CORK让TCP尽可能的进行数据的合并组包,以最大MTU传输,如果发送的数据包大小过小则如果在0.6~0.8S范围内都没能组装成一个MTU时,直接发送。这个策略一般用在文件服务器等只传输大数据包的场景中。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!