问题背景
来自于朋友分享的一个案例,反馈服务器给客户端传输 8M 左右的文件时,需要 30 多秒,而在同一局域网下的另一台客户端访问服务器,传输同一个文件速度很快,只需要几秒,速度上差异较大。
我们就此问题讨论分析了下,其中有一些现象确实比较特别,就此分享下。
问题信息
数据包跟踪文件信息主要如下:
λ capinfos "client slow.pcapng"
File name: client slow.pcapng
File type: Wireshark/... - pcapng
File encapsulation: Ethernet
File timestamp precision: microseconds (6)
Packet size limit: file hdr: (not set)
Number of packets: 16 k
File size: 20 MB
Data size: 19 MB
Capture duration: 80.048161 seconds
First packet time: 2022-05-28 19:09:33.167685
Last packet time: 2022-05-28 19:10:53.215846
Data byte rate: 248 kBps
Data bit rate: 1986 kbps
Average packet size: 1172.93 bytes
Average packet rate: 211 packets/s
Strict time order: True
Capture hardware: Intel(R) Core(TM) i7-9700 CPU xxx
Capture oper-sys: 64-bit Windows 10 (2009), build 22000
Capture application: Dumpcap (Wireshark) 3.4.6 (v3.4.6-0-g6357ac1405b8)
Number of interfaces in file: 1
Interface
Name = \Device\NPF_{xxx}
Description = 以太网
Encapsulation = Ethernet (1 - ether)
Capture length = 262144
Time precision = microseconds (6)
Time ticks per second = 1000000
Time resolution = 0x06
Operating system = 64-bit Windows 10 (2009), build 22000
Number of stat entries = 1
Number of packets = 16943
λ
客户端为 win 10 64 位系统,通过 wireshark 捕获数据包,捕获时长 80s,数据包数量 16k,文件大小 20MB,平均速率约 1.986Mbps。
专家信息中出现数据分段未被捕获到、疑似重传以及 DUP ACK 的现象,考虑到数量较多,初步推测疑似出现了丢包问题。
问题分析
客户端行为
考虑到客户端反馈的问题和传输速度相关,简单看下 I/O Graphs ,基本在 2Mbps 左右。观察到服务器向客户端一共传输了 19M 字节,基于传输文件 8M 的大小,以及其中在 40秒左右出现的大概 2 秒完全无速度的传输间隔,猜测是客户端尝试进行了 2 次文件下载。
以 TCP Stream Graphs 中的 Time Sequence(tcptrace) 分析,粗看图示如下
放大显示后,会看到一种有规律的传输现象,每次随着慢启动开始, MSS 逐步增长,达到出现丢包(红圈标注以红短线显示),也就是出现了拥塞,此时会停顿下来,大约有 250ms 没有数据传输(红色箭头标注),之后开始又是慢启动再一次重复,一轮又一轮。
MSS 增长示意图
重传分段,以 250 ms 左右来看的话,基本上是属于超时重传现象了。
数据包分析
回到实际数据包,可以看到是使用 TLSv1.2 协议进行传输,根据 TCP 三次握手的结果,可知 RTT 约在 33ms,MSS 为 1436 。
在出现丢包的前一次传输中,可以看到服务器一共发送了共 10 个 TCP 分段,长度为 1383 字节,TLS 数据字段长度 1329 字节,在此并不是一个完整的 MSS 1460 字节。
疑似丢包和超时重传的完整数据包,图示如下:
主要现象分析:
- 在 No.100 和 No.99 之间出现了疑似丢包,提示
TCP Previous segment not captured ,根据 Seq 99027 和 Seq 93711 相差 5316 字节,为 4 个 1329 字节,确认在此丢失了 4 个 TCP 分段; - client 在 No.110 回复了 SACK ,其中 ACK 93711 标记所需丢失的分段,SLE=99027 SRE=112317 标记已收到的分段;
- 之后数据包的交互,产生了 client 触发出两次
TCP Dup ACK ,注意仅有两次,所以未能使 server 触发快速重传; - server 经过 250ms 左右才超时重传了 Seq 93711 分段,以及之后的三个分段。
之后的丢包问题依旧,所产生的问题现象类似,因为无法满足三次 TCP Dup ACK 的情况,所以每次都无法达到快速重传的条件,每一次超时重传都大概在 250ms,发生了总共 82 次,也就是 20.5 秒的时间处于空闲等待时间,所以说此次传输慢的问题,引起的根因是丢包,而造成最终速度慢的原因,确是由于不断产生出来的超时重传累积使然。
深度分析
至此,其实对于传输文件慢的根因已经分析得出,下一步需要解决的就是如何定位找到发生丢包的点了。为什么还会有深度分析?实际上这也是在数据包分析中,我觉得能不断学习不断提高的地方,就是多观察多思考。
以下些问题点,是一些特殊而暂未有明确答案的地方。
- TCP MSS
其实在 TCP 三次握手协商中,已明确了 MSS 为 1436 字节,包括在之后的 TLS 握手时也现了 1490 最大长度的数据包(1436 + 54),但在后面的数据包传输阶段,却是以 1383(1329+54)字节为一个 TCP 分段在传输,而这种交互同时增长的方式,像是 MSS 变成了 1329 字节。
真实答案:未知。
猜测答案:server 应用层控制的字节发送行为,以及更有可能的一个答案见 4 。
- TCP DUP ACK
实际在上述问题的分析中,只是阐述了现象,只有两次 DUP ACK,因此无法触发快速重传。但仔细观察的同学是否有会这样的疑问,在 No.100 之后的不连续 Seq TCP 分段,为什么没有触发客户端连续产生 DUP ACK ?而仅仅是在 No.110 处产生了一个 SACK。
需要在此注意的是时间,No.100 - No.109 Server 传输的 TCP 分段是连续无任何时间间隔的情况下一瞬间进入,所以 client 未能响应乱序包而立马生成 ack ,最后可以理解是合并生成了一个 SACK。这在之后的数据包传输过程中,都是同一个现象,分段连续无任何时间间隔的进入。
当然也会有同学有疑问,这仅仅是 win10 普通客户端,全 0 无任何时间间隔的更可能只是捕获时间精度的问题,所以在此我把它定义仍是个未定论的问题。
真实答案:未知。
猜测答案:win10 特殊乱序情况下 dup ack 的不发送。
- TCP 超时重传
可能又会有同学注意到,为什么超时重传的 4 个数据包,No.116、No.118-No.120 会有 30ms 左右,也就是一个 RTT 的间隔。在这里有实际的答案,就是在 No.99 和 No.100 之间所丢包的 4 个 TCP 原始分段,并不是在同一个 RTT 内发送出来的。
No.116 这一个重传分段的原始分段,是跟随 No.99 之后,在上一个 RTT 内由 Server 一起发出;No.118-No.120 这三个重传分段的原始分段,是在 No.100 之前,跟 No.100 一起在这一个 RTT 内由 Server 一起发出。
因此产生了 No.116、No.118-No.120 4 个 TCP 超时重传分段的时间间隔。
真实答案:需 server 侧跟踪文件最终验证。
猜测答案:server TCP 分段的发送行为引起。
- TCP SACK
在之后的丢包现象中,也出现了一个奇怪的 SACK 现象。在 No.273 和 No.274 之间显示丢失 2 个 TCP 分段之后,client No.284 SACK 标明了 SLE=291732 SRE=305022,也就是说确认收到了 No.274 和 No.275,包括之后的 No.286 和 No.288 SACK 都再次表明收到了这两个分段。
但是在 server 进行超时重传丢失的 2 个分段 No.287 和 No.289 之后,同样重传了 No.290 和 No.291,而这两个分段的 Seq Num 分别对应的就是 No.274 和 No.275,在这里意味着 server 未到正常收到 sack,或者收到忽略了这些 sack。之后 server 以 No.292 回复了一个 DSACK,说明了 SLE=291732 SRE=294390 属于重复。
实际上从丢包来看,很难理解连续 3 个 sack 都丢失的情况,而且在此期间是有正常的数据包交互,因为未能有 server 的捕获,所以只能猜测是 server 未正常收到 sack。
真实答案:未知。
猜测答案:结合上面 1 的 MSS 变化,我觉得更有可能是在 server 侧或是中间存在某类设备(代理或是安全设备),双向修改了 MSS 为 1436,而实际上 server 的 mtu 实际为 1329,同时该设备在 NAT 转换的时候,可能修改了 Seq,但是未转换 TCP OPS 里的 SLE 和 SRE,造成了 server 忽略了 SACK 。
问题总结
综上所说,在缺少对全局环境了解以及 server 侧数据包跟踪文件的情况下,有些问题确实无法得出准确答案,但这并不妨碍我们对数据包文件的一系列分析,其中一些特殊现象展开研究下来,也会不断夯实 TCP 基础知识点。
|