Zhang_Jiawen
4 Beryllium

Re: 如果看了这个你还是不会用Wireshark,那就来找我吧(6月16日更新)

一站式学习Wireshark(五):TCP窗口与拥塞处理

转载请在文首保留原文出处:EMC中文支持论坛https://community.emc.com/go/chinese image001.gif

介绍

TCP通过滑动窗口机制检测丢包,并在丢包发生时调整数据传输速率。滑动窗口机制利用数据接收端的接收窗口来控制数据流。

接收窗口值由数据接收端指定,以字节数形式存储于TCP报文头,并告知传输设备有多少数据将会存储在TCP缓冲区。缓冲区就是数据暂时放置的地方,直至传递至应用层协议等待处理。因此,发送端每次只能发送Window Size字段指定的数据量。为了使发送端继续传送数据,接收端必须发送确认信息:之前的数据接收到了。同时必须对占用缓冲区的数据进行处理以释放缓存空间。下图显示了接收窗口是如何工作的:

image002.jpg

上图中,客户端向服务器发送数据,服务器接收窗口是5000字节。客户端发送了2500字节,服务器缓冲区还剩2500字节,之后又发送了2000字节,从而缓冲区只剩500字节。服务器发送确认信息。对缓存中数据进行处理并清空缓存。此过程重复进行,客户端又发送3000字节和1000字节,服务器缓存减少至1000字节,客户端再次确认数据并处理缓存中内容。

更多信息

调整窗口大小:

TCP堆栈接收到数据的时候,生成一个确认信息并以回复的方式发送,但是放置在接收端缓存中的数据并不总是立即被处理。当服务器忙于处理从多个客户端接收的报文,服务器很有可能因为清理缓存而变得缓慢,无法腾出空间接收新的数据,如果没有流控,则可能会造成丢包和数据损坏。好在,接收窗口所设定的速率无法使服务器正常处理数据时,能够调整接收窗口大小。通过减小返回给发送端的ACK报文的TCP头窗口大小值来实现。如下图所示:

image003.jpg

上图中,服务器初始窗口大小为5000字节。客户端发送2000字节,之后又发送了2000字节,缓冲区中只有1000字节可用。服务器意识到缓冲区正在快速填满,它知道如果数据继续以此速率传输,很快会有报文丢失。为了防止报文丢失,服务器发送确认信息给客户端,更新窗口大小为1000字节。结果,客户端减少数据发送,服务器以可以接受的速率处理缓存内容,即保持数据流以稳定的速率传输。

调整窗口大小在两个方向都是可行的。当服务器能够更加快速的处理报文时,它会发送一个较大窗口的ACK报文。

零窗口暂停数据流:

某些情况下,服务器无法再处理从客户端发送的数据。可能是由于内存不足,处理能力不够,或其他原因。这可能会造成数据被丢弃以及传输暂停,但接收窗口能够帮助减小负面影响。

当上述情况发生时,服务器会发送窗口为0的报文。当客户端接收到此报文时,它会暂停所有数据传输,但会保持与服务器的连接以传输探测(keep-alive)报文。探测报文在客户端以稳定间隙发送,以查看服务器接收窗口状态。一旦服务器能够再次处理数据,将会返回非零值窗口大小,传输会恢复。下图示例了零窗口通知过程。

image004.jpg

服务器初始接收数据窗口为5000字节大小。从客户端接收4000字节数据之后,服务器负载变得非常繁重,无法继续处理客户端任何数据。服务器于是发送窗口大小值为0的报文。客户端暂停数据传输并发送一个探测报文。探测报文之后,服务器回复以告知客户端现在可以接收数据的报文,以及窗口大小为1000字节。客户端恢复传送数据。

TCP滑动窗口实战:

本例中,开始从192.168.0.20发送至192.168.0.30。我们关心的是窗口大小字段,可以从Packet List面板的Info栏以及Packet DetailsTCP报文头看到。前三个报文后,可看到该值立刻减小,如下图所示:

image005.jpg

窗口大小值从第一个报文的8760字节变成第二个报文的5840字节到第三个报文的2920字节。窗口大小值的减小是主机延时的典型标志。在时间栏注意到这一过程发生的非常迅速。当窗口大小迅速减小的时候,通常就有可能下降为零。这就是第四个报文所发生的,如下图所示:

image006.jpg

第四个报文从192.168.0.20发送至192.168.0.30,目的是告诉192.168.0.30它不再接收任何数据。0值见于TCP报文头WiresharkPacket List面板Info栏,以及TCP报文头的SEQ/ACK Analysis字段也告诉我们这是一个0窗口报文。

一旦发送了零窗口报文,192.168.0.30的设备不会再发送任何数据,直到收到从192.168.0.20的窗口更新,告知窗口大小已经增加了。本例中导致零窗口的问题是暂时的,所以在下一个报文中发送了窗口更新信息,如下图所示。

image007.jpg

本例中,窗口大小增加到一个非常健康的数值64240字节Wireshark再次在SEQ/ACK Analysis告诉我们这是一个窗口更新。

一旦收到更新报文,192.168.0.30的主机就再次开始发送数据,在报文6和报文7中。这一过程发生很快。如果它持续时间再长一点,就可能会导致网络的潜在中断,引起数据传输减慢或失败。

下一个关于滑动窗口的例子,第一个报文是正常HTTP,从195.81.202.68172.31.136.85。此报文之后立刻跟随一个从172.31.136.85发送的零窗口报文,如下图所示:

image008.jpg

这与上一个例子中的零窗口报文十分类似,但结果显著不同,172.31.136.85主机不是发送一个窗口更新并回复通讯,而是一个探测报文,如下图所示:

image009.jpg

此报文被Wireshark标注为探测报文。时间栏告诉我们这一报文发生于最后一个接收到的报文3.4秒之后。这一过程持续若干次,一端发送零窗口报文另一端发送探测报文,如下图所示:

image010.jpg

探测报文发送间隙为3.46.813.5秒。这一过程可能会持续相当长一段时间,取决于通讯设备的操作系统。该情况下,把时间栏的值加起来,通讯暂停了25秒。

TCP差错控制和流控排查总结:

重传报文

重传的发生是由于客户端检测到服务器没有接收到它所发送的数据。因此,取决于你所分析的是通讯的哪一端,有可能是看不见重传的。如果从服务器端抓取数据,并且它确实没有接收到客户端所发送的和重传报文,可能会一无所获因为无法看见重传报文。如果怀疑并不是服务器端导致的报文丢失,可以考虑在客户端尝试抓取报文,以查看实际是否有重传发生。

重复ACK

可以将重复ACK看作重传的“所谓相反面”,因为它是在服务器检测到客户端发送报文丢失的时候产生的。大多数情况下,在通讯两端抓取流量时都可以看到重复ACK。需记住当接收报文乱序时会触发重复ACK。例如,如果服务器之接收到发送的第一个和第三个报文,就会导致发送重复ACK引起客户端对第二个报文的快速重传,因为你已经收到了第一个和第三个报文,因此不管导致第二个报文丢弃的原因是什么,都很有可能是暂时的,因此大多数情况下重复ACK都会成功发送和接收。当然,这种情形并不一定永远会发生,因此当你怀疑在服务器端丢失报文而又看不到任何重复ACK,考虑从通讯的客户端抓取报文。

零窗口和探测报文

滑动窗口直接与服务器无法接收和处理报文有关,任何窗口大小的缩小以及零值都是服务器问题的直接结果。所以如果你在哪里看到这两者之一发生,就应该在那里深入研究。通常应当在网络通讯两端一直主机窗口更新报文。

Zhang_Jiawen
4 Beryllium

Re: 如果看了这个你还是不会用Wireshark,那就来找我吧(6月24日更新)

一边写一边看了看整个系列,Filter的使用技巧这一部分有所缺失。写完了网络性能这节再写Filter。

Zhang_Jiawen
4 Beryllium

Re: 如果看了这个你还是不会用Wireshark,那就来找我吧(6月24日更新)

一站式学习Wireshark(六):狙击网络高延时点

转载请在文首保留原文出处:EMC中文支持论坛https://community.emc.com/go/chinese image001.gif

介绍

在某些情况下,丢包可能并不是造成延时的原因。你可能会发现尽管两台主机之间通讯速度很慢,但这种慢速并没有伴随着TCP重传或是重复ACK的征兆。在这种情况下,需要使用另一种方式来定位高延时点。

查找高延时点最有效的方法之一是检查最初的握手信号以及跟随其后的几个报文。例如,一个简单的客户端与网络服务器的连接,客户端尝试通过浏览器访问网络服务器的站点。我们只关心这一通信序列的前六个报文,包括TCP握手过程,首次HTTP GET请求,对此GET请求的确认,以及从服务器发至客户端的第一个数据报文。

更多信息

正常通讯:

在讨论高延时状况之前,找一个正常的通讯作为参照。在第二节已经介绍过TCP握手过程以及HTTP通讯,这里不再赘述。在下面这张图里,我们关心的部分只有Time列:

image002.jpg

这一通讯序列是非常快速的,整个过程耗时不到0.1秒。

接下来几个抓包文件包含同样的traffic模式,但是在报文时序上有所不同。

慢速通讯——线路延时:

让我们看看下面这个报文。注意到所有报文都是相同的,除了报文25的时间延时较长:

image003.jpg

逐一分析这六个报文,立刻就会看到第一次延时。客户端(172.16.16.128)发送首次SYN报文以开始TCP握手,在服务器(74.125.95.104)返回SYN/ACK之前,有0.87秒的延时。这是线路延时的第一个信号,这是由客户端和服务器之间的设备引起的。

我们判断这是线路延时的依据是所传送的报文类型特征。当服务器接收到一个SYN报文,只需花费很少的处理过程就可发送回复,因为这一工作负载并不包含任何传输层之上的处理。即使服务器工作负载非常繁重,它通常也会快速地以SYN/ACK来回复SYN报文。这就排除了服务器是高延时的潜在原因。

客户端也被排除的原因在于,它除了接收SYN/ACK报文之外,没有进行任何处理。

这一抓包的前两个报文帮我们排除了客户端和服务器,并指出了潜在原因。

继续分析,我们发现结束三步握手信号的ACK报文快速出现,客户端发送的HTTP GET请求也是如此。产生这两个报文的所有处理在本地客户端接收到SYN/ACK之后进行,因此在客户端没有繁重的负载需要处理的情况下,这两个报文预计会很快传送。

到了报文5,我们看到另一个延时高得离谱的报文。出现在最初的HTTP GET请求发送过后,从服务器返回的ACK报文花费了1.15秒才收到。接收到HTTP GET请求之后,服务器在开始发送数据之前首先发送了一个TCP ACK,同样只需占用服务器很少的处理。这是另一个线路延时的信号。

不管何时你经历着线路延时,你几乎总是会看到:在最初的握手信号期间的SYN/ACK报文,以及整个通讯过程的ACK报文中,存在着高延时。即使这一信息并没有告诉你网络上延时的确切原因,至少让你明白客户端和服务器都不是延时点所在,因此延时发生在两者之间的设备。这时,你应当开始检查受影响主机之间的各种防火墙,路由器,以及代理,以定位罪魁祸首。

慢速通讯——客户端延时:

下一个延时场景的抓包如下图所示:

image004.jpg

这一抓包开始时很正常,TCP握手非常迅速,没有任何延时的迹象。正常状态持续至第四个报文:握手信号结束之后接收到一个HTTP GET请求。这个报文距离前一个接收到的报文有1.34秒的延时。

要确认网络的延时点,需要检查第3和第4个报文之间发生了什么。报文3是客户端发送到服务器的TCP握手信号中的最后一个ACK,报文4是从客户端发送至服务器的GET请求。这两个报文的共同之处在于都是由客户端发送,并且独立于服务器。由于所有这些操作都集中在客户端上,GET请求应当在发送了ACK之后快速传送。

不幸的是对于终端用户,从ACKGET的传送并没有快速发生。GET报文的创建与传输取决于应用层的处理,这一过程中的延时意味着客户端无法及时的执行这一功能。这表示客户端最终为通讯中的高延时负责。

慢速通讯——服务器延时:

最后一个延时场景的抓包如下图所示:

image005.jpg

在这一抓包中,两个主机之间的TCP握手过程完成得干脆利落,因此开始时并无问题。接下来几个报文也很顺利,首个GET请求及回复ACK报文也在快速交付。直到最后一个报文,我们看到了高延时的信号。

第六个报文是服务器响应客户端GET请求的第一个HTTP数据报文,但是在服务器发送GET请求的TCP ACK 0.98秒之后才到达。报文56的传送过程与我们在前一个场景所见ACKGTE请求的传送类似。但是,在这一情况下,服务器是我们关注的焦点。

报文5是服务器对从客户端接收GET请求的回应。只要该报文被发送,服务器就应当立即发送数据。这一读取,封装,传送的过程是由HTTP协议完成的,由于这是应用层协议,需要服务器参与处理过程。这一报文的延迟接收表明服务器无法在合理的时间内处理数据,最终指向服务器是延时点。

延时定位思路:

通过六个报文,我们能够定位服务器与客户端之间的网络高延时点。这些场景可能看起来有点复杂,但是下图能使你的定位延时过程变得简单快捷。这一原则几乎能应用于任何基于TCP的通讯。

image006.jpg

happydanye
2 Bronze

Re: 如果看了这个你还是不会用Wireshark,那就来找我吧(6月24日更新)

这节很有实用意义(狙击网络高延时点)。正好最近处理问题用上了(非常感谢Zhang,Jiawen),分享下应用的思路(也有跟文中不同的地方)。

问题:业务突然变慢,客户端(确定)和服务端(应该)都没有改动。

问题定位:根据经验判断是网络质量变差,现在需要验证判断。(服务端无法协调联查,但服务端处理很多客户端,未见其他地方的客户端有同样问题)。

验证过程:首先断掉客户端重连,用wireshark抓包发现tcp三次握手都还行。客户端发数据包也很快,服务端回tcp的ack也挺快,但数据包的响应就慢了一些。客户端发大数据包的时候,干脆就没响应包回来(但也不是必然)。根据逻辑,服务端和网络都有可能有问题,客户端出问题的可能可以排除。不过业务的服务端是nb的中国移动,客户端所在的网络是中国电信的网络,因此我们基本可以把问题归结为网间互通。

有趣的问题是:小包看起来是ok的,大数据包延迟(或丢包)的现象很严重。

另外有三个问题想请教下Zhang,Jiawen:

1、在wireshark上,如何方便查一个tcp报对应的响应包(或响应包对应的原始包)。可以手工根据sequence id和ack id来判断,但是wireshark提供方便的工具么?----我们的业务是在一个tcp长连接中发很多包。

2、有没有技巧可以方便的统计延时的情况,例如某时间段中,发包到收到ack的延时超过1s的数据包数量?

3、有没有技巧可以方便的统计丢包的情况,例如某时间段中,发出去的包没收到ack的有多少?

0 项奖励
Zhang_Jiawen
4 Beryllium

Re: 如果看了这个你还是不会用Wireshark,那就来找我吧(7月14日更新)

问题:业务突然变慢,客户端(确定)和服务端(应该)都没有改动。

问题定位:根据经验判断是网络质量变差,现在需要验证判断。(服务端无法协调联查,但服务端处理很多客户端,未见其他地方的客户端有同样问题)。

验证过程:首先断掉客户端重连,用wireshark抓包发现tcp三次握手都还行。客户端发数据包也很快,服务端回tcp的ack也挺快,但数据包的响应就慢了一些。客户端发大数据包的时候,干脆就没响应包回来(但也不是必然)。根据逻辑,服务端和网络都有可能有问题,客户端出问题的可能可以排除。不过业务的服务端是nb的中国移动,客户端所在的网络是中国电信的网络,因此我们基本可以把问题归结为网间互通。

有趣的问题是:小包看起来是ok的,大数据包延迟(或丢包)的现象很严重。

非常感谢分享.很高兴这篇文章能帮到你.从现象来看像是服务器和客户端中间的某个环节出现了问题.不知道这个问题现在解决了没有,如果有进一步发现再来一起讨论~

关于这几个问题:

1、在wireshark上,如何方便查一个tcp报对应的响应包(或响应包对应的原始包)。可以手工根据sequence id和ack id来判断,但是wireshark提供方便的工具么?

可以参考楼下大牛的回答~

2、有没有技巧可以方便的统计延时的情况,例如某时间段中,发包到收到ack的延时超过1s的数据包数量?

添加一列按照每一个报文据上一个报文的延时来显示:

扩展TCP报文头。右键Time since previous frame in the TCP stream,然后选择Apply as a Column,这样产生新的一列。

如下图所示。就可以方便的看到每一个报文距离上一个报文的延时了。然后可以根据延时从大到小来排列。

Capture.PNG.png

3、有没有技巧可以方便的统计丢包的情况,例如某时间段中,发出去的包没收到ack的有多少?

可以尝试应用display filter过滤条件,输入tcp.analysis,wireshark会列出关于TCP问题和性能的过滤条件,其中有关于重传报文(tcp.analysis.retransmission)的过滤:

Capture.PNG.png

另外给出一个TCP显示过滤条件的详细说明:

Wireshark · Display Filter Reference: Transmission Control Protocol

0 项奖励
bairichard1
3 Argentum

Re: 如果看了这个你还是不会用Wireshark,那就来找我吧(7月14日更新)

1, “业务突然变慢,客户端(确定)和服务端(应该)都没有改动。

[沛满]:如果怀疑是网络有问题,可以在业务慢的时候抓个500MB左右的网络包分析一下。论坛可以上传的话我也可以帮忙分析。

2,“在wireshark上,如何方便查一个tcp报对应的响应包(或响应包对应的原始包)。可以手工根据sequence id和ack id来判断,但是wireshark提供方便的工具么?----我们的业务是在一个tcp长连接中发很多包。

[沛满]:这个要从基本原理讲起。TCP的工作方式不是逐个包发送的,而是一口气发出多个包,从而提高传输效率。就像快递员会一次性携带很多包裹到我司前台一样,为的是减少消耗在路上的往返时间。接收方收到这些包之后有两个选择,既可以每个包都确认(也就是你提到的响应),也可以只确认最后一个来暗示所有包都收到了。举个例子,发送方发出了10个包,编号1至10,且没有一个丢失的,那接收方既可以回复10个确认包,也可以只回复“ack 11”,表示10以及10之前的所有包都收到了。当有丢包发生时,比如还是发送了10个包的情况,编号也是1至10,但其中10号包丢失了,那接收方可以回复9个确认包,也可以只回复“ack 10”,表示9以及9之前的包都收到了。

了解了这个原理,我们就知道在Wireshark上没有必要去对应每个ack和seq,因为大多数包即便正常收到后也不会有ack。

3,“有没有技巧可以方便的统计延时的情况,例如某时间段中,发包到收到ack的延时超过1s的数据包数量?

[沛满]:如果你只是想了解网络延时状况,那用ping最简单准确了,没有必要用Wireshark。一般我们在乎的是应用层的延时,比如向一个服务器发送读请求,到收到读响应的时间差究竟有多少。Wireshark上有提供这个功能,比如CIFS协议那就可以用“smb.time > 1”来过滤出所有超过一秒钟的延时的CIFS操作。如果是NFS,就用rpc.time(因为NFS是基于RPC的协议)。HTTP也有http.time。

4,“有没有技巧可以方便的统计丢包的情况,例如某时间段中,发出去的包没收到ack的有多少?

[沛满]:还是那句话,没有收到ack不一定是丢包了。如果是想看丢包重传的统计,那就Analyze-->Expert Info,然后看warnings or notes tab. 虽然要统计出结果很容易,不过使用者需要理解tcp的基础知识才能解读这个结果,比如一个超时重传,导致的后果远远超过一个快速重传。有启用SACK的时候,处理多个丢包的效率远高于没有启用SACK的……这个说起来太复杂了。

Zhang_Jiawen
4 Beryllium

Re: 如果看了这个你还是不会用Wireshark,那就来找我吧(7月14日更新)

感谢沛满,解释的非常清楚

0 项奖励
iamgoust
2 Iron

Re: 如果看了这个你还是不会用Wireshark,那就来找我吧(7月14日更新)

妹子的确是认真的干了这件事情,赞一个,择机转到我的个人博客www.vants.org,欢迎文章作者妹子来访切磋,本人做科来4年半,现在在合肥组织一群技术兄弟创业中

0 项奖励
Zhang_Jiawen
4 Beryllium

Re: 如果看了这个你还是不会用Wireshark,那就来找我吧(7月14日更新)

朋友也在创业,我很理解创业的辛苦不足为外人道之处,向创业的兄弟致以由衷的敬意~

拜访了你的博客,非常专业细致的总结~

0 项奖励
happydanye
2 Bronze

Re: 如果看了这个你还是不会用Wireshark,那就来找我吧(7月14日更新)

哈哈,又有高手出没,感谢解答。继续发问:

1、既然可以只确认最后一个,那么接收方的确认机制通常有哪几种?(每n个包确认一次?),如果收到1,2,3,4,5,7,8,9,10个包(包6丢了),如何回复确认消息?

2、ping这个我是知道的,但是有的服务器禁ping。另外,我还发现有ping正常的包,但是实际业务包延迟厉害。我刚测试了一下,ping的时候,包大小很有关系。900以下比较正常,超过1000的包都收不到,900和1000之间的包时好时坏。这个结果有参考意义么?

0 项奖励