从wireshark中学网络分析(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/NK_test/article/details/59491747

在上一篇文章中提到了TCP的延迟确认,延迟确认并不一定能提高性能,在某些场景下,开启延迟确认甚至会严重降低网络传输性能。

(一)下面列出几个开启延迟确认降低网络性能的场景:

场景一

想象这样一个场景,服务端开启了延迟确认,客户端在同一时刻发送了9个TCP包,其中3、4、5号因为拥塞丢失了。

那么传输过程中发生了以下事件:

  1. 到达服务器的6、7、8、9号包触发了4个“Ack 3”,于是客户端快速重传3号包,此时它并不知道4号包也丢失了。
  2. 由于服务器上开启了延迟确认,所以它收到3号包之后,等待了200ms才回复Ack 4。
  3. 客户端重传4号包,然后服务器又等待了200ms才回复Ack 5。
  4. 客户端重传5号包,然后服务器又等待了200ms才回复Ack 10。
  5. 客户端传输新的10号包,自此网络拥塞就完全恢复了。

这样不断的等待回复,造成了传输效率的大幅降低。还有另一种可能是在某个200ms的延迟过程中,那些丢包的RTO已经被触发,所以进入了超时重传阶段,由于RTO阶段网络已经拥塞,发出的包几乎都没有达到目的地,所以这段时间相当于并没有传输任何数据。无论符合哪一种可能,性能都会严重下降。

解决方案:

  1. 关闭延迟确认,这样浪费在延迟确认上的600ms就省下来了。只要RTT不是太长,那么丢包也不会触发超时重传。

  2. 启用TCP SACK(Selective Acknowledgment)功能,在Ack的时候可以告知对方自己已经收到拿些包了,这样在大量丢包的时候不需要每个重传包都确认一次,也就不怕延迟确认的影响了。

如上图,SACK在wireshark中很容易看到,只要把SACK: 694121-702161 651241-672681Ack=623101 综合起来,我们就知道623101-651240,672682-694120已经丢失。因此它只需要重传这段数据。由此可见启用SACK其实比关闭延迟确认更高效,因为它可以一次性重传多个丢包,而不用每重传一个就等待一次Ack,白费多个RTT。

场景二

从本质上看,延迟确认之所以会在大量重传时影响性能,是因为它在该场景下会多次出现,那么还有什么场景会导致延迟确认多次出现呢?当TCP窗口极小的情况下,此时启用延迟确认简直就是雪上加霜。因为假如服务器的接收窗口只有2920字节(两个MSS),客户端每发送两个包就会耗光窗口,所以不得不停下来等待服务器的确认。假如这时候服务器上启用了延迟确认,传输效率会大受影响。

场景三

Nagle和延迟确认本身都没问题,但是一起用就会影响性能。Nagle算法用程序员喜闻乐见的方式表达就是这样的:

if有新数据要发送
    if数据量超过MSS(即一个TCP包所能携带的最大数据量)
        立即发送
    else
        if之前发出去的数据尚未确认
            把新数据缓存起来,凑够MSS或确认到达后再发送
        else
            立即发送
        endif
    endif
endif

在ssh客户端等小包环境下,启用Nagle的客户端携带数据量很小的情况下(小于MSS),只能等待上一个包被确认才能接着发。但此时服务端若启用了延迟确认的话,一等就是200ms,严重影响传输效率。

(二)估算网络拥塞点

先说一个概念,在途字节数。注意,只有在数据发送方抓到的包才能用来分析在途字节数。某一时刻的计算在途字节数的公式为在途字节数=Seq+Len-Ack,其中Seq和Len是来自上一个数据发送方的包,而Ack则是来自上一个数据接收方的包。

先从Wireshark中找到一连串重传包中的第一个,再根据该重传包的Seq值找到其原始包,最后计算该原始包发送时刻的在途字节数。由于网络拥塞就是在该原始包发出去的时刻发生的,所以这个在途字节数就大致代表了拥塞点的大小。多次取样后建议选一个较小的值,参考这个值来设置窗口,从而尽量避免拥塞。

(三)奇怪的接受窗口

如下图,接收窗口为什么只有这么小?!

这里写图片描述

很多人的直觉是这个服务器存在问题,因为接收窗口太小了,肯定会影响网络性能。但是你忽略了一个重要的提示就是“window size scaling factor: -1(unknown)”,上一篇文章中的问题三,我们提及了“Window Scale”这个参数的意义,真实的接收窗口的值需要乘上2的指数(参数作为指数)。

由于这个值是在三次握手期间声明的,所以如果你在三次握手之后才开始抓包的话,wireshark无从知晓Window Scale的值,也就无法计算出系数,只好显示出没有系数时的大小,“window size scaling factor:-1(unknown)”正好提示了这种情况。所以,wireshark此时显示出的值并不是真实的接收窗口的值。

(四)网络加速器:

一般网络加速器的采用的技术手段:

  1. 启用TCP window scale。这样可以使最大接收窗口突破65535的限制,只要内存跟得上,接收窗口几乎不受限制。

  2. 监测延迟来避免拥塞。网络包是以队列的方式通过网络设备的,当拥塞即将发生时,队列变长,延迟就会显著提高。根据这一特点,我们可以让加速器在延迟明显增加时,自动放慢发送速度,从而避免拥塞的发生。这其实是TCP Vegas的理念。

  3. 利用发送窗口实现优先级控制,用户体验就会更好。

  4. 启用SACK。SACK必须在发送方和接收方都启用,这就是我们在两边各架设一台加速器的优势。单边加速器的效果很可能因为另一端没有启用SACK而大打折扣。

(五)wireshark常见提示

关于wireshark的各种常见提示,请参考以下链接,总结的很好了。
http://blog.sina.com.cn/s/blog_987e00020102wq60.html

参考资料

《wireshark网络分析的艺术》
《计算机网络》谢希仁
RFC文档

猜你喜欢

转载自blog.csdn.net/NK_test/article/details/59491747