查看: 125723|回复: 9

探寻影响业务性能的隐形杀手——TCP Nagle算法、延迟确认及窗口大小故障分析案例(1)

[复制链接]
发表于 2012-6-7 14:50:29 | 显示全部楼层 |阅读模式
本帖最后由 haiwanxue 于 2012-6-7 14:59 编辑

探寻影响业务性能的隐形杀手
——TCP Nagle算法、延迟确认及窗口大小故障分析案例

文章目的
深入学习TCP相关基础知识
详细了解Nagle算法和延迟确认理论
了解TCP window size对数据传输的影响
使用科来网络分析系统分析数据传输性能问题
如何解决由Window Size引起的相关网络性能问题


前言

TCP是当今互联网业务最关键的底层技术支撑和实现协议之一,这点想必毋庸置疑。但再具体一点来说,其也是应用开发和网络管理部门的分水岭。应用开发部门和TCP最为密切的位置应该是SocketSocket Option等内容,网络管理部门表面上无需知晓TCP深层内容。

实际情况往往是,应用开发部门将所有重心放在如何实现功能需求,涉及到TCP Socket的部分,一般选择基本的必须参数项即可,绝大多数不会去潜心研究每个Socket Option应该如何设置以达到最佳的性能效果。同样,网络部门的重点工作内容则是保障网络可用、稳定和安全可靠,基本上不会去研究不同的应用系统或业务系统的TCP层是如何工作的,也很少研究如何从TCP的角度来优化和提升网络和业务性能。因此,保障和支持业务系统的两个关键部门有点忽视了TCP的“真实”存在。


TCP也将应用开发和网络管理部门隔离,大家想想日常的开发和运维流程,有没有网络部门参与到应用设计或开发,或者应用开发部门参与到网络运维管理中来。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?CSNA会员注册

×
回复

使用道具 举报

 楼主| 发表于 2012-6-7 14:53:41 | 显示全部楼层
本帖最后由 haiwanxue 于 2012-6-7 15:14 编辑


一、TCP发展简述

大致看一下目前使用的TCP发展历史,了解笔者下面要分析的关于TCP内容在其发展过程中的位置。


1981年开始的RFC 793(可视为TCP v4)是现在使用的TCP基础,该RFC规范了TCP协议的基本内容和实现方式。




凡事都不会尽善尽美,RFC 793设计的TCP在历经网络快速发展的同时,IETF也在不断探索和改进其功能和一些算法。在这些改进中,几乎所有的新增功能都靠TCP Option实现。


除了TCP Flags、滑动窗口及基本SeqACK等基础知识外,网络上能够看到的相关技术类文章基本都是继1989 RFC1122后新增的功能讨论,广为人知的诸如Nagle算法、Delayed ACKScale WindowSACK、拥塞防御如Slow Start等等,因为新增功能不但填补了TCP本身缺陷,而且其底层的技术理论和实现原理都是耐人寻味的,特别是长期从数据包层面进行网络和应用性能分析、故障定位的工作人员,更在意怎样从协议本身的角度去学习去分析去使用,这里的协议学习可能是指了解和掌握某一个字段的含义,以及熟悉引起该字段变化的原因。

笔者在工作过程中发现,无论是开发人员、应用维护人员、网络管理人员或者业务使用者,其在碰到业务性能问题时,往往花很长时间都无法精确诊断问题原因,而引起此类问题的部分原因可能与TCP Nagle算法、Delayed ACK及窗口大小有关,下面讲讲两则关于Nagle 算法与Delayed ACK,以及数据在网络传输中效率影响的故事。





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?CSNA会员注册

×
回复

使用道具 举报

 楼主| 发表于 2012-6-7 14:54:27 | 显示全部楼层
本帖最后由 haiwanxue 于 2012-6-7 15:29 编辑

二、何谓Nagle算法

1989 RFC 1122定义,全名Nagle Algorithm,翻译为Nagle算法。

Nagle算法最早是由John Nagle1984年为了应对Telnet及类似应用性能问题而提出的(RFC 896)。这些应用的问题在于,它们通常都会将每次击键放在单独的数据报文中发送,这样会向网络中发起一系列“小数据报”。

很容易看出问题在哪,首先,由于最小的(没有数据的)TCP段是40字节,每个段发送一字节应用数据会造成4000%的开销。更重要的是,网络中报文数量增加会造成拥塞,拥塞会造成重传,重传会引发更严重的拥塞。在极端情况下,每个段在网络中都会有好几个副本,吞吐量将会将为正常速率的几分之一。

如果没有未经确认的数据存在(对方已ACK了发送的所有数据)。我们就说当前连接是空闲的。按照最初的构想,除非连接处于空闲状态,否则由于Nagle算法机制,不会传输任何来自应用程序的新数据。这样就可以防止连接上同时有多个未经确认的小分段存在。

RFC 1122提出的做法对此稍有放松:如果来自应用程序的数据可以构成一个完整的分段,就允许将其发送出去。也就是说,如果发送的数据至少有MSS字节大,即使连接不是空闲的,也可以将其发送出去。注意,这样并没有违反Nagle的条件:每个连接上同时最多只有一个未经确认的小分段

举例说明:以上传文件操作为例,如下图。

假设客户端每次连续发送两个数据包(实际中具体连续发送多少个由复杂因素决定,暂且不谈)。当连续的两个等于MSS大小的报文发送到接收端,接收端ACK后,发送方继续发送。但当发送方发出小于MSS的一个报文后,如果没有接收到对方对该报文的ACK,则一直等待,直到接收到ACK为止。

发送方具体等待多长时间,稍后讨论。

为了防止假设环境出现错误或发生可能的问题,假设小于MSS的报文Push字段置1,而上面的两个等于MSS的报文Push字段未置1(实际应用中,此类现象由File Block SizeSendReceive Buffer等决定,暂不讨论)。




Nagle算法自身工作很好。它可以防止应用程序向网络洪泛地发送小报文,而且在大多数情况下,其性能至少不比没有实现这个算法的TCP差。


何谓延迟确认

1989 RFC 1122定义,全名Delayed Acknowledgment,简称延迟ACK,翻译为延迟确认。

Nagle算法一样,延迟ACK的目的也是为了减少网络中传输大量的小报文数,但该报文数是针对ACK报文的。

一个来自发送端的报文到达接收端,TCP会延迟ACK的发送,希望应用程序会对刚刚收到的数据进行应答,这样就可以用新数据将ACK捎带过去。在BSD实现中这个延迟的取值通常为200msWindows操作系统应该也默认使用该量值,也可以使用TcpDelAckTicks注册项调整此时间。

RFC 1122 除了说明延迟确认值一定不能大于500ms之外,并没有规定延迟应该有多长。它还建议至少每隔一个报文要进行一次ACK

举例说明:还是以上传文件操作为例,如下图。

假设情景模式与上面Nagle算法相同。

上文说过,当发送方发出小于MSS的一个报文后,如果没有接收到对方对该报文的ACK,则一直等待,直到接收到ACK为止。

这里继续讨论该问题,如果服务器Delayed ACK时间为200ms,那么服务器端接收到小于MSS的报文后,为了避免向网络中发送过多的ACK,服务器端将等待对端的下一个报文到来,以便一起确认。当然,在等待期间,服务器端TCP也“期望”有应用数据需要发送(这里讨论的仅为一对Socket内容)。

等待时间达到200ms时,服务器端会“极不情愿”的对上面的小报文进行确认,告诉对端已收到该报文。

顺便回答一下在Nagle算法时遗留的问题,即发送端再次发送报文前,需要等待多长时间。

在忽略服务器端应用处理时间(这里的应用处理时间并不一定十分正确)的前提下,等待的时间长为RTT+200ms。其中RTTRound trip time往返时间)指报文来回时,在网络上花费的时间。





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?CSNA会员注册

×
回复

使用道具 举报

 楼主| 发表于 2012-6-7 14:55:18 | 显示全部楼层
本帖最后由 haiwanxue 于 2012-6-7 15:38 编辑

四、Nagle算法遇到Delayed ACK

从上面的讨论看到,在一个有数据传输的TCP连接中,如果只有数据发送方启用Nagle算法,在其连续发送多个小报文时,Nagle算法机制会减少网络中的小报文数量。这就意味着,同样传输相同大小的应用数据,在网络上的报文个数却不同。

举个例子,发送端需要连续发送5个写操作(应用程序将数据写入到缓冲池的动作)的小报文,首先发送第一个,由于Nagle算法的作用,在未收到第一个报文确认前,发送端在等待写操作的同时进行读操作,接收端并未启用延迟确认(视TCP delay ACK时间为0),尽管刚收到该报文就发出确认,但由于网络延时的原因,在收集齐另外4个小报文后,发送方才收到了第一个报文的ACK,则后面的4个报文会一起发送出去(大小未超过MSS),接收端再次ACK




在上述发送5个小报文的过程中,只用了4个报文就实现了。但如果发送端未启用Nagle算法,完成整个过程则至少需要8个报文或10个报文才能实现,这里接收端未启用延迟确认,而启用Nagle算法和未启用Nagle算法的场景中,从完成数据发送的时间来看,未启用Nagle算法的方式花费的时间会更长一些。这里基本看到了Nagle算法的好处了。





还是上述数据传输场景,发送端未启用Nagle算法,但接收端延迟确认默认时间为200ms,来看看这时的情况。

RFC 1122规定,Delayed ACK对单个的小报文可以延长确认的时间,但不允许有两个连续的小报文不被确认。所以,当发送端连续发送两个报文后,接收端必须给予确认。这时的数据传输情况如下图,只有当第5个报文到达后,接收端由于延迟确认机制,会导致200ms的延时存在。





接下来看看,当Nagle算法遇到Delayed ACK时会是什么情况。按照常理推断,两种深思熟虑的功能设计,应该是1+1>2的效果。具体如何,还是请事实说话。



先继续看上面的假设场景,该场景要求发送端向接收端发送5个连续的写操作数据,但网络延时较大,同时发送端启用Nagle算法,接收端Delayed ACK默认为200ms

发送方先发出一个小报文,接收端收到后,由于延迟确认的机制,等待发送方的下一个报文到达。而发送方由于Nagle算法机制,在未接收到第一个报文的确认前,不会发送已读取到的报文。

在这种场景下,暂不考虑应用处理时间,完成整个数据传输所需时间为2RTT+400ms,貌似情况不是特别糟糕。



如果上述其他条件不变,发送方应用写操作延时稍微变大,或发送端的应用操作延时稍大,我们再看看,完成这个操作的延时情况。

发送方先发出一个小报文,接收端收到后,由于延迟确认的机制,等待发送方的下一个报文到达。由于发送方应用数据写操作延时较大,在经过RTT+200ms后,读取到了下一个需要发送的内容,此时接收到了第一个报文的确认,而网络中未有没被确认的报文,发送方需要再将第二个小报文发送出去,以此类推,直到最后一个小报文被发送,且接收到该报文的确认,此时整个数据传输过程完成。

在这种情景下,完成整个数据传输所需时间则为5RTT+5*200ms,明显增大了不少。如果相同情境下,有成千上万的小报文发送,则整体使用时间相当可观了。



在实际情况下,如果发送方程序做了一系列的写、写、读操作的现象,这样的操作都会触发Nagle和延迟ACK算法之间的交互作用,应该尽量避免。

在一些系统里,如BSD派生的系统,每200ms会检查一次所有连接的延迟ACK,这时,不管实际的延迟是多少,都会发送ACK。这就意味着实际的延迟可能在0-200ms之间,因此,可以认为平均延迟为100ms。但这时可能还有其他复杂的情况会继续影响,最终延迟确认可能还是200ms。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?CSNA会员注册

×
回复

使用道具 举报

发表于 2012-6-21 09:19:09 | 显示全部楼层
老海的东西依然这么强大,不过老海怎么变成“初学者”level啦,办坏事被抓啦?
回复

使用道具 举报

发表于 2012-6-29 17:09:44 | 显示全部楼层
这个东西很好,认真学习一下
回复

使用道具 举报

发表于 2012-7-24 21:08:26 | 显示全部楼层
写的很好,要慢慢学习
回复

使用道具 举报

发表于 2012-7-25 14:38:52 | 显示全部楼层
有点高深啊
学习。。。
回复

使用道具 举报

发表于 2012-10-19 10:22:18 | 显示全部楼层
佩服!
回复

使用道具 举报

发表于 2013-3-15 10:11:02 | 显示全部楼层
分析讲解的很透彻。值得学习。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | CSNA会员注册

本版积分规则

快速回复 返回顶部 返回列表