第19章 TCP的交互数据流 19.4 Nagle算法 在前一节我们看到 , 在一个R l o g i n连接上客户一般每次发送一个字节到服务器,这就产生了一些4 1字节长的分组:2 0字节的I P首部 一种简单和好的方法就是采用RFC 896 [Nagle 1984]中所建议的N a g l e算法。 19.4.1 关闭Nagle算法 有时我们也需要关闭 N a g l e算法。 插口API用户可以使用T C P _ N O D E L A Y选项来关闭Nagle算法。
Nagle 算法 2.1. 概述 Nagle 算法是一种减少 TCP/IP 网络拥塞控制的算法,主要用来解决小包问题。 Nagle 算法在确认数据发送时把数据放入缓存中,直到上一条数据被确认才会发送新的数据。 Nagle 算法保证一个 TCP 连接上最多只有一个未被确认的未完成小分组,在该分组被确认前不能发送其他小分组。 2.2. 算法规则 1. 如果包长度达到 MSS(最长报文大小),则允许发送; 2.
Nagle算法 TCP_NODELAY和TCP_CORK Nagle算法 根据创建者John Nagle命名。该算法用于对缓冲区内的一定数量的消息进行自动连接。 注:Nagle虽然解决了小封包问题,但也导致了较高的不可预测的延迟,同时降低了吞吐量。 实际上这就的你动手来自己实现以下Nagle算法了。 实际上Nagle算法并不是很复杂,他的主要职责是数据的累积,实际上有两个门槛:一个就是缓 冲区中的字节数达到了一定量,另一个就是等待了一定的时间(一般的Nagle算法都是等待200ms);这两个门槛的任何一个达到都必须发送数据了 实际上这样就已经实现了Nagle算法,而且不需要经常调用GetTickCount而降低了系统的性能。 TCP_CORK TCP链接的过程中,默认开启Nagle算法,进行小包发送的优化。 这个时候可以置位TCP_NODELAY关闭 Nagle算法,有数据包的话直接发送保证网络时效性。在进行大量数据发送的时候可以置位TCP_CORK关闭Nagle算法保证网络利用性。
一、知识准备 在nginx优化中有个经常需要设置的参数,tcp_nodelay 该参数最核心的功能,就是把小包组成成大包,提高带宽利用率也就是著名的nagle算法 tcp协议中,有一个现象:应用层数据可能很低 这种情况下大部分都是控制包的传输,既加大了带宽的消耗,带宽利用率也不高 nagle算法就是为了解决这个问题。 默认打开的功能,所以在实验中,客户端都会有延时确认的情况,要关闭客户端延迟确认,需要设置setsockopt中的TCP_QUICKACK ● 本文中主要讨论的是nginx的nagle算法,nagle算法完全由 tcp协议的ack机制决定,如果对端ACK回复很快的话,nagle事实上不会拼接太多的数据包,虽然避免了网络拥塞,网络总体的利用率依然很低 ● nagle算法在与延迟确认互相作用的情况下,会产生严重的延时效果 ,这是需要警惕的 ● nginx中是否打开nagle算法,要取决于业务场景。
在 Socket 编程中,TCP_NODELAY 选项是用来控制是否开启 Nagle 算法。在 Java 中,为 ture 表示关闭 Nagle 算法,为 false 表示打开 Nagle 算法。 你一定会问 Nagle 算法是什么? 5.2 Nagle 算法是什么鬼? Nagle 算法是一种通过减少通过网络发送的数据包数量来提高 TCP/IP 网络效率的方法。 它使用发明人 John Nagle 的名字来命名的,John Nagle 在 1984 年首次用这个算法来尝试解决福特汽车公司的网络拥塞问题。 5.4 Nagle 与 Delayed ACK 一起会发生什么化学反应? Nagle 与 Delayed ACK 都能提高网络传输的效率,但在一起会好心办坏事。 最后刨根问底对 TCP 传输的中的 Nagle 与 Delayed ACK 做了全面的讲解,更加透测的剖析了该问题案例。
在 Socket 编程中,TCP_NODELAY 选项是用来控制是否开启 Nagle 算法。在 Java 中,为 ture 表示关闭 Nagle 算法,为 false 表示打开 Nagle 算法。 你一定会问 Nagle 算法是什么? 5.2 Nagle 算法是什么鬼? Nagle 算法是一种通过减少通过网络发送的数据包数量来提高 TCP/IP 网络效率的方法。 它使用发明人 John Nagle 的名字来命名的,John Nagle 在 1984 年首次用这个算法来尝试解决福特汽车公司的网络拥塞问题。 5.4 Nagle 与 Delayed ACK 一起会发生什么化学反应? Nagle 与 Delayed ACK 都能提高网络传输的效率,但在一起会好心办坏事。 例如,以下这个场景: A 和 B 进行数据传输 : A 运行 Nagle 算法,B 运行 Delayed ACK 算法。
Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着很多小数据块。 Nagle算法的基本定义是随意时刻,最多仅仅能有一个未被确认的小段。 Nagle算法全然由TCP协议的ACK机制决定,这会带来一些问题,比方假设对端ACK回复非常快的话,Nagle其实不会拼接太多的数据包,尽管避免了网络拥塞。网络整体的利用率依旧非常低。 Nagle算法与CORK算法差别 Nagle算法和CORK算法非常类似。 实际上Nagle算法并非非常复杂。他的主要职责是数据的累积,实际上有两个门槛:一个就是缓 冲区中的字节数达到了一定量,还有一个就是等待了一定的时间(一般的Nagle算法都是等待200ms)。 假设採用默认的开启Nagle算法。
比如Delay Ack和Nagle算法。 这个原因对大家理解TCP基本的概念后能在实战中了解一些TCP其它方面的性能和影响。 Nagle算法的基本逻辑,摘自wiki: ? 这样可以优化带宽利用率(早些年带宽资源还是很宝贵的),Nagle算法也是用来优化改进tcp传输效率的。 如果client启用Nagle,并且server端启用了delay ack会有什么后果呢? (根据Nagle算法,没有没ack的包了,立即发) 100,000 bytes: 前面68个整包很快发出去也收到ack回复了,然后发了第69个整包,剩下88bytes(不够一个整包)根据Nagle算法要等一等 Nagle算法一般默认开启的
Nagle算法的初衷是这样的:应用进程调用发送方法时,可能每次只发送小块数据,造成这台机器发送了许多小的TCP报文。 Nagle算法要求一个TCP连接上最多只能有一个发送出去还没被确认的小分组,在该分组的确认到达之前不能发送其他的小分组。 内核中是通过 tcp_nagle_test方法实现该算法的。 tcp_nagle_check(tp, skb, cur_mss, nonagle)) return 1; return 0; } 再来看看tcp_nagle_check ) || //如果开启了Nagle算法 (! 使用TCP_NODELAY套接字选项就可以关闭Nagle算法。
延迟的ACK、 Nagle 算法和 Winsock 缓冲的交互的设计方案可以极大地影响性能。 以下是Nagle 算法的两个例外: 如果堆栈已合并数据的缓冲区比最大传输单位 (MTU) 大小,完整大小的数据包而无需等待来自远程主机 ACK 立即发送。 使用TCP_NODELAY 套接字选项 禁用 Nagle 算法,以便在传输较小的数据的数据包获得更低的延迟。 如果 发送端 堆栈 获取 另一个块 大于MTU , 它仍然可以 绕过 Nagle算法 。 2,如果可能,避免使用单向数据流套接字连接。 单向套接字更容易受Nagle 和DelayACK的影响。 3,如果所有的小包都要立刻发送,在发送方使用TCP_NODELAY 。
这个员工的名字叫做:Nagle。上面描述的算法就是Nagle算法。这个算法于1984年作为征求意见稿(RFC)发布。 自此Nagle算法就声名鹊起,很多的TCP的实现者们都会提供一个接口来让用户自己去设置是否开启Nagle算法。他们通常给这个参数起名叫:TCP_NODELAY。 在Netty中也有这样的配置,有时候我们希望禁用Nagle算法,就可以使用如下配置。 ChannelOption.TCP_NODELAY, true); 在服务器端是在worker的Channel端设置属性: boot.childOption(ChannelOption.TCP_NODELAY, true); Nagle
Nagle 算法是一种通过减少数据包的方式提高 TCP 传输性能的算法。 在早期的互联网中,Telnet 是被广泛使用的应用程序,然而使用 Telnet 会产生大量只有 1 字节负载的有效数据,每个数据包都会有 40 字节的额外开销,带宽的利用率只有 ~2.44%,Nagle 图 2 – Nagle 算法 几十年前还会发生网络拥塞的问题,但是今天的网络带宽资源不再像过去那么紧张,在默认情况下,Linux 内核都会使用如下的方式默认关闭 Nagle 算法: TCP_NODELAY = 1 Linux 内核中使用如下所示的 tcp_nagle_test 函数测试我们是否应该发送当前的 TCP 数据段,感兴趣的读者可以以这段代码为入口详细了解 Nagle 算法在今天的实现: static tcp_nagle_check(skb->len < cur_mss, tp, nonagle)) return true; return false; } Nagle 算法确实能够在数据包较小时提高网络带宽的利用率并减少
尝试发送大量包含少量数据的 TCP 分组 Nagle 算法试图在发送一个分组之前,将 TCP 数据绑定在一起,以提高网络效率。 Nagle 算法鼓励发送全尺寸(LAN 上分组最大约1500字节,WAN 上分组则是几百字节)的段。只有当其他分组都被确认过后,Nagle 算法才允许发送非全尺寸的分组。 启用 Nagle 算法 拓展:Nagle 算法在现代的服务器上并不推荐使用,因为它解决了细粒度对象的同时也带入了不少新的问题。 文章用较多的篇幅说明 Nagle 算法,似乎有些本末倒置。我们暂先忽略Nagle 算法利用缓冲区将细粒度数据拼装成粗粒度数据的过程,着重关心其结果 。 提出 Nagle 的模式与享元模式思想 略有差异的事实。 2、感谢简书作者九彩拼盘的勘误 由享元模式联想到 配合与逻辑的 抽象层次的享元理解。
算法 只有收到前一数据的 ACK 消息时, Nagle 算法才发送下一数据。 TCP 套接字默认使用的 Nagle 算法交换数据, 因此最大限度地进行缓冲, 直到收到 ACK。 如果不使用 Nagle 无需等待 ACK 的前提下连续传输, 大大提高传输速度. 使用 Nagle 交互图 ? ? 把图画残了。。。 当我们传输大文件, 注重传输速度时候可以禁用 Nagle 算法, 如果考虑到传输内容很小, 头部信息就有可能几十个字节, 可以使用 Nagle 算法, 减少网络传输次数。 禁用 Nagle 算法 socklen_t option; int optlen = sizeof(option); option = 1; setsockopt(serv_sock, IPPROTO_TCP
wikipedia对nagle算法的描述: https://en.wikipedia.org/wiki/Nagle%27s_algorithm 算法实现: if there is new data to tcp_nagle_test(tp, skb, mss_now,(tcp_skb_is_last(sk, skb) ? nonagle && tp->packets_out && tcp_minshall_check(tp))); } 根据上面代码,nagle算法生效的条件是: 1、当前发送的包小于mss 2、启用TCP_NAGLE_CORK 根据算法的描述可以看到:nagle算法和delayed ack都是为了减少小数据包在网路中传输的数量,优化网络性能。 如果发送方确实存在有多个小包要分别发送,并使用长连接的情况,最好是禁用nagle算法,其实这也是主流的做法,nginx在keeplive模式下就禁用了nagle算法。
学过计算机网络的朋友一般会听说过Nagle算法。在使用TCP协议进行传输时,会在有效数据前面增加大量头部信息来保证可靠传输,如果发送的有效数据非常短,增加头部带来的额外开销就非常大。 同理,接收端在接收大包时有可能会进行截断以免缓冲区放不下(断包),接收连续多个小包时会在缓冲区暂存一段时间合并成大包再处理(粘包),也就是所谓Nagle算法。 Nagle算法的优化在大部分情况下都是非常好的,但也会给接收端带来一定的麻烦,必须要正确识别和读取一个完整的包之后再处理,以免后面的功能代码无法正常工作。 如果到网上(甚至一些书上)搜索资料,会说禁用Nagle算法就可以了,也就是设置套接字属性启用TCP_NODELAY,非常简单。既然如此,那就赶紧用起来吧。 在Python中,标准库socket封装了套接字编程需要的功能,创建套接字之后可以使用setsockopt来设置当前套接字的各种属性,其中就包括禁用断包和粘包的延迟从而禁用Nagle算法。 ?
《哈佛商学院》的合著者Frank Nagle教授说:“ FOSS组件几乎是所有其他软件的基础,无论是开放的还是专有的,但我们对软件的常用性或安全性信息知之甚少。 Nagle说:“第一步是要真正了解企业所依赖的FOSS组件。无论是通过定期的安全扫描和代码审计,还是通过其数字产品采用的软件材料清单。” Nagle说:“如果这类个人账号的存储库支持的话,可以执行两因素身份验证。” 个人账号控制的常用FOSS的另一个风险是开发人员,他们有删除账号或删除有争议和分歧代码的决定权。 Nagle表示,由于FOSS可以自由修改和复制,因此可以有多个版本,分支和类似名称的存储库。为了进一步确保安全,重要的是对正在使用的FOSS组件情况以及支持和维护工作有个共识。 例如,Nagle指出了常用的PuTTY SSH软件的0.70版,该软件于2017年7月发布。将近两年后,直到2019年3月该软件的更新0.71版才发布。
Nagle算法的初衷是这样的:应用进程调用发送方法时,可能每次只发送小块数据,造成这台机器发送了许多小的TCP报文。 Nagle算法要求一个TCP连接上最多只能有一个发送出去还没被确认的小分组,在该分组的确认到达之前不能发送其他的小分组。 内核中是通过 tcp_nagle_test方法实现该算法的。 tcp_nagle_check(tp, skb, cur_mss, nonagle)) return 1; return 0; } 再来看看tcp_nagle_check ) || //如果开启了Nagle算法 (! 使用TCP_NODELAY套接字选项就可以关闭Nagle算法。
Nagle和NODELAY,视频p18 本笔记参考的视频链接:https://www.bilibili.com/video/BV1Ht411p7wx? 不要再写了 根据信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(终止、退出),所以client会退出,server也会退出 为了不影响服务端和其他客户端,可以忽略SIGPIPE Nagle Nagle算法主要是避免发送小的数据包,要求TCP连接上最多只能有一个未被确认的小分组,在该分组的确认到达之前不能发送其他的小分组。 算法只允许一个未被ACK的包存在,它并不管包的大小,所以只要有一个没收到ACK,则会一直等下去 因为Nagle要等待确认后才能发送,所以会有一定延迟 而且这里面有着ACK延迟机制,当Server端收到数据之后 算法在捣乱 TCP_NODELAY TCP_NODELAY就是禁用Nagle算法 验证Nagle和TCP_NODELAY的延迟 因为找不到muduo对应的代码,但是我又想自己看看两者的延迟,所以我自己写了一个验证
HTTP作为一种应用层协议,其事务处理要依赖于传输层的TCP协议机制的运作,所以HTTP事务处理的性能瓶颈很大程度上来源于TCP连接,体现在下面几点: TCP连接时间的消耗 TCP的慢启动机制 TCP采用的Nagle 解决方法:正是因为单次TCP连接的时延和TCP的慢启动机制,HTTP的持久连接才显得尤为重要 Nagle算法 TCP协议本身并没有有规定发送单个段的数据包大小的最小值,那让我们想想,如果我们试图在单个段中发送几个字节的数据包会怎样呢 如果这样,TCP将通过Nagle算法的机制来提高网络利用率,很显然,将包含数据量极小的段都单独发出去将会极大降低网络利用率,所以通过Nagle算法,不直接派发小数据量的段,而是选择将它们绑定在一起,当达到要求尺寸后才派发出去 Nagle算法是一把双刃剑,它提高了网络利用率,但同时造成了TCP的时延 解决方法:Nagle是可以选择关闭的,当然,前提是你得在TCP通信中写入大块的数据 参考资料: 《HTTP权威指南》作者古尔利