问题描述
过一段时间后,刷新页面,发现菜单接口超时。
发现并没有向服务端发起请求,而是停留在stalled阶段。
问题分析
请求停留在 stalled 状态,持续长达10秒。
什么是stalled呢?
参见 谷歌开发者工具文档
- Stalled. The request could be stalled for any of the reasons described in Queueing.
翻译过来如下
-停滞不前。由于排队中描述的任何原因,请求可能会停止。
也即是从TCP
连接建立完成,到真正可以传输数据之间的时间差。先让我们要分析TCP
连接为什么要等待这么久才能用?如果TCP
连接过程中有多次重传,直到达到最大重传次数后,那么连接被客户端重置。
TCP
三次握手后,发送端发送数据后,一段时间内(不同的操作系统时间段不同)接收不到服务端ACK包,就会以某一时间间隔(时间间隔一般为指数型增长)重新发送,从重传开始到接收端正确响应的时间就是stalled
阶段。而重传超过一定的次数,发送端就认为本次TCP
连接已经失败了,需要重新建立连接。
stalled
阶段是TCP
连接的检测过程,如果检测成功就会继续使用该TCP
连接发送数据,如果检测失败就会重新建立TCP
连接。
浏览器对同一个主机域名的并发连接数有限制,因此如果当前的连接数已经超过上限,那么其余请求就会被阻塞,等待新的可用连接;此外脚本也会阻塞其他组件的下载,被阻塞的请求的stalled
也会很长。
Chrome对同一个域名进行请求的最大连接数是6个。 如果同时只有6个并发连接数数量,那网页打开的时候只能依赖于这6条连接,前面如果有打开慢的内容,就会直接影响到后面的内容打开。
命令行调用接口
httpstat "https://xxx.xxx.xxx.xxx/vc/menu/list" -H 'Authorization: xxx'
分析http状况如下:
Connected to xxx.xxx.xxx.xxx:443 from 192.168.31.6:59166
HTTP/1.1 200 OK
Server: openresty/1.17.8.2
Date: Thu, 18 Mar 2021 08:27:12 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Body stored in: /var/folders/j8/crzv3y4s3kb93rny6h5gfnnr0000gn/T/tmpx519qh3q
DNS Lookup TCP Connection TLS Handshake Server Processing Content Transfer
[ 5ms | 27ms | 59ms | 33ms | 0ms ]
| | | | |
namelookup:5ms | | | |
connect:32ms | | |
pretransfer:91ms | |
starttransfer:124ms |
total:124ms
分析结果
- 在浏览器环境下,请求并没有调起API请求,而是在等待中结束了。
- 在命令行环境下,请求响应正常,从DNS解析、建立TCP连接到返回响应,共耗时124ms。
问题原因
如下图,将筛选调整到All,这时看到6个连接已经被用完了,这时候第七个连接调用菜单接口,这时候就处于stalled状态。
综上所述,并非是菜单接口响应慢,而是之前获取资源慢。
解决方案
- 资源文件使用独立的域名。
- 优化资源js文件的获取速度,这取决于带宽、文件体积等。
- 优化资源js文件的获取方式,不要一次性把js全部加载进来,用到的时候再加载即可。