【每日鲜蘑】API调用超时不一定是后台的错……

980 阅读3分钟

问题描述

过一段时间后,刷新页面,发现菜单接口超时。

image.png

发现并没有向服务端发起请求,而是停留在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状态。

image.png

综上所述,并非是菜单接口响应慢,而是之前获取资源慢。

解决方案

  • 资源文件使用独立的域名。
  • 优化资源js文件的获取速度,这取决于带宽、文件体积等。
  • 优化资源js文件的获取方式,不要一次性把js全部加载进来,用到的时候再加载即可。