wireshark 分析 tcp 传输之文件上传速率问题

在https://xie.infoq.cn/article/34ede3dd88624ab8317ea4365那一节里,我提到了查看系统网络瓶颈的方法以及排查丢包问题的手段。但就此分析网络问题还不够精细,有时网络资源并没有达到瓶颈,或者并没有丢包产生,但是网络传输速率就是很慢,或者有丢包产生,但无法知道丢包的详细过程,无法知道整个 tcp 传输过程的具体情况。
如何更加精细的查看网络包传输过程,答案就是抓包。
这一节我将用上传文件的抓包文件举例,用 wireshark 来分析 tcp 的传输过程以及文件传输速率慢的问题。
概念模型
传输过程简单的可概括为,三次握手,慢启动,拥塞避免,快速恢复,四次挥手。三次握手,四次挥手的过程一般我们都比较熟,这里我不会特别来讲,着重来看下其他几个阶段。
其他几个阶段涉及到 tcp 里的窗口概念,我们首先来分下。
滑动窗口
tcp 的发送和接收数据是一个滑动窗口的模型,在 tcp 协议里,发送数据的滑动窗口叫发送窗口,接收数据的滑动窗口叫接收窗口。
发送窗口大小受制于对端接收窗口的大小和拥塞窗口的大小。
拥塞窗口
tcp 发送窗口受对端接收窗口的大小能动态调整,这种情况在局域网里面是可行的,但是在广域网里,数据传输过程中很有可能经过很多路由器或者交换机,如果中途设备网络处理能力变差,即使对端接收窗口能力大依然会造成严重的丢包,此时发送端即不应该继续发送数据包。
所以,拥塞窗口产生了,它有着能够动态感知网络拥塞情况来调整发送窗口的功能。
如何衡量拥塞情况
当发送重传的时候即认为此时网络产生了拥塞的情况。重传又分为快速重传和超时重传,拥塞窗口的大小会根据这两种重传方式做出不同的策略
超时重传
数据包在发送数据到对端时,会收到一个 ack 标志的数据包回来,当在一定时间内,发送端没有收到对端的 ack 包,那么发送端就会认为数据包丢掉了,会重新传递相同数据包到对端。这样的重传叫做超时重传。
快速重传
每次都等到超时再重传,会增大端与端的时延, 所以快速重传认为如果收到对端三次重复的 ack,那么即认为包丢失了,然后将丢失的包马上传递到对端,不用等超时定时器触发。
对端重复 ack 是如何产生的?
tcp 发包是一组一组的发往对端,如果一组当中某个包丢失了,对端接收到的是丢失后的包,那么回应的 ack 将会是丢包前最大的 ack 序号。

慢启动阶段
连接建立后,每次收到一个 ack,那么拥塞窗口能发送的最大 MSS(一个 tcp 包最大发送的字节数)就会翻倍。当最大发送数据到达 ssthresh,就会进入拥塞避免阶段。
拥塞避免
每过一个 RTT(往返延时) ,拥塞窗口就会新增一个 MSS 大小。当碰到拥塞时,传输又会进入慢启动或者快速恢复阶段。那么如何衡量拥塞,当发生重传时即认为发送了拥塞。
快速恢复
快速恢复是为了避免每次碰到拥塞时,就进入慢启动阶段,让传输效率极剧降低这种情况出现。所以快速恢复采用遇到快速重传时,让拥塞窗口减半,然后 MSS 增长方式采用和拥塞避免阶段一样的低斜率线性增长的方式。然后当遇到超时重传时,整个传输过程依然会进入慢启动阶段。

tcp stream graphs 分析 tcp 传输过程
慢启动阶段
慢启动阶段的特点,单位时间内,发包的数量在呈现指数级的增长。wireshark 可以通过 tcp 时序图 Stevens 来看到这种增长的变化。x 轴是时间,y 轴是包的序列号。

为什么慢启动之后会有比之前 seq num 还低的点出现

因为发生了重传,发送的是之前发过的数据包。可以看到这第一波慢启动之后,又出现了好几次斜率比较陡的曲线,说明整个传输过程又经历了几次慢启动的过程,经过抓包,在 5s 到 7.5s 的这段期间,发生了大量的超时重传。

拥塞对传输速率的影响
io graph 查看整个过程的传输速率。
以 100ms 的间隔去看整个过程传输速率变化,可以看到在拥塞发生之前,传输速率呈指数级别的上涨,在好几次超时重传后,传输速率直至降低到 0 以后又开始了指数级别的上涨,虽然斜率没有第一次那么急速,但依然是指数级别,所以可以认为实际上是在经历慢启动阶段。
在第二个波峰之后,又经过了一次传输速率的下降,没有第一次下降那么陡峭,然后速率呈现固定斜率的上涨趋势,这和快速恢复阶段的特定极其相似,可能整个 tcp 传输就是在进行快速恢复阶段。

传输速率除了拥塞带来的影响,还有接收窗口大小也会影响,接收窗口太小,传输速率也会提升不上去。
那么如何肯定这里传输速率的下降不是接收窗口的影响呢?
第一,tcp 时序图 Stevens 找到对应速率下降的时间点附近在发生大量的超时重传,说明有大量丢包,进而说明网络状况不好。
第二,可以通过 wireshark window scaling 去看接收窗口随时间的变化情况。

绿色代表接收窗口的大小,蓝色的点叫 bytes out 也就是在途数据(指已经发送但是还未被确认的数据。在途数据越多,说明发送端发送的数据就越多,整个过程,接收窗口在达到 4M 的时候就基本不变了。
发送端发送数据只是在差不多 5s 的时候达到了接收窗口的瓶颈,但由于网络拥塞,发送端发现之前发的包丢了,所以没有继续发送新的数据。而旧的数据包在慢慢 ack 过程中,所以 bytes out 变小了。
并且后续,发送的数据量大小都远远小于接收窗口的大小。如果接收窗口是瓶颈,在 5s 后,整个图应该是 bytes out 和接收窗口处于一条基本重合的水平直线上,这里显然不是这样。
深入思考 如果接收窗口如果是瓶颈,该如何办?
接收窗口大小受什么影响?
TCP 接收窗口的大小在 Linux 系统中取决于 TCP receive buffer 的大小,而 TCP receive buffer 的大小默认由内核根据系统可用内存的情况和内核参数 net.ipv4.tcp_rmem 动态调节。
同时,不是 TCP receive buffer 的大小就等于 TCP 接收窗口的大小。有 bytes/2^tcp_adv_win_scale 的大小分配给应用。如果 net.ipv4.tcp_adv_win_scale 的大小为 2,表示有 1/4 的 TCP buffer 给应用,TCP 把其余的 3/4 给 TCP 接窗口。
在 tcp 报文里,留给窗口的表达式只有 16 位,这样导致,tcp 的窗口最大只能表示 64kb,所以在 tcp 窗口大于 64kb 时 需要利用 TCP Options 的 Window scale 字段。在系统内核参数设置里,对应的就是 net.ipv4.tcp_window_scaling 参数,这个参数会将 window 字段乘以 2 的 scale 次方作为实际窗口大小。
这个字段在握手的时候会告诉对方。

所以如果接收窗口是瓶颈,那么可以调大接收方的 receive buffer 以及 tcp_window_scaling 参数。
总结
这一节 主要用了 tcp stream graphs 宏观的去分析了文件上传时 tcp 的传输过程,wireshark 提供的高级功能,这一节只是冰山一角,希望能抛砖引玉。
我认为,网络抓包无处不在,其实随手就可以抓取上网浏览的包去进行分析,然后通过 wireshark 把包传输过程的表现都用理论知识找到对应的解释,不断深挖下去,便会融会贯通。
版权声明: 本文为 InfoQ 作者【蓝胖子的编程梦】的原创文章。
原文链接:【http://xie.infoq.cn/article/a25d68ab9604a4963a7aa4c05】。文章转载请联系作者。
评论