又到了三月, 处于一些众所周知的原因. 把之前没有完成的文章往出放一放, 增加一些大家对我的了解.
问题背景
有一天被 pm 小姐姐反馈网站无法打开, 一直是白屏; 我再本地打开了一下是正常的, 而且展示速度也是正常的; 查了下日志报错也没有啥问题; 这个页面中只有一个展示二维码, 扫码登录的功能;
于是开始了我的 debug 之旅:
收集了报错现场 --- 小姐姐的错误请求的 curl 以及截图; 发现请求一直 pending, 直到 30s 之后才会正常返回, 于是排除了网络导致的请求延迟之后, 开始考虑是什么因素致使请求一直被挂起呢?
收集的请求
30s 后返回
分析了一下每个请求的 Timing 之后发现: 每个请求的 Stalled 时间都很久, 但是又都可以发送成功.
image.PNG
所以要了解一下 Timing 之中各个参数的意义, 这个参数其实在优化网络请求时我们也有了解过, 顺手做一下复习:
Queuing - 资源加载的排队
Stalled/Blocking - 请求等待发送所用的时间. Queuing 中的所有原因加上代理协商所用的任何时间.
Proxy Negotiation - 与代理服务器连接协商所用的时间.
DNS Lookup - DNS 查询所用的时间
Initial Connection / Connecting - 建立连接所用的时间, 包括 TCP 握手 / 重试和协商 SSL 的时间.
SSL - 完成 SSL 握手所用的时间.
Request Sent / Sending - 发出网络请求所用的时间. 通常不到一毫秒.
Waiting (TTFB) - 等待初始响应所用的时间, 也称为至第一字节的时间.
Content Download / Downloading - 接收响应数据所用的时间.
画一画重点 请求等待发送所用的时间. Queuing 中的所有原因加上代理协商所用的任何时间.
参考链接:
- https://segmentfault.com/a/1190000015133004
- https://developers.google.com/web/tools/chrome-devtools/network/understanding-resource-timing?hl=zh-cn
在查看我的请求为何被挂起的过程中, 突然发现我的请求优先级是 medium , 话说会不会是被更高优先级的请求摆了一道呢?
在 关于请求被挂起页面加载缓慢问题的追查 这篇文章中了解到, Chrome 有 cache_lock 的机制, 并且可以通过查看 Chrome 网络日志的方式来查看, 并且在其中可以查看请求的优先级;
于是 NetLog 粉墨登场
浏览器输入 Chrome://net-export/ 打开 Chrome NetLog , 按照步骤收集, 对应时间的网络日志; 并且下载到本地;
NetLog
在 NetLog Viewer, 上传刚才下载好的网络日志 (不排除可以肉眼看出日志中想要的内容的可能, 我试了一下, 失败了).
NetLog Viewer
上传完成状态
点击左侧的 Event, 然后按需搜索就好了. 在这里我看到了我心仪已久的 priority, 发现似乎请求集美们都是 medium, 没有人比对应的请求更优秀.( 走偏
但是不太影响我们在网络日志中发现了所有请求的对应状态, 麻麻再也不怕别人问我请求中状态变化了.( 怕
priority
意识到可能不是这个原因, 还是花了点时间搞清楚了 https://juejin.im/post/5c7cc63951882562e7482c65
虽然在网络日志这里没有解决问题, 但是还是发现了一个重要的表象 ---- 校验二维码的请求怎么会这么多? ( 列文虎克
校验请求
震惊的发现在浏览器的其他 tab 下, 打开了一个闲置的登录页面, 失控了一样发送校验请求. 关掉之后, 本页面的登录, 加载也回归了正常.(如此, 我们也抓到了本次 bug 的真凶!) 可是真凶的成因不在本篇文章的了解范围内, 按下不表了.( 已手刃
探究下为什么会出现这个情况?
排除代码中的 bug 本身, 造成这个现象的原因其实是因为浏览器对同一域名请求是有最大并发数限制的. 正是因为疯狂发起的请求超过了请求阈值, 并且这个检查接口本身返回就比较慢, 造成了后续请求的挂起而不是直接失败.
不同浏览器对并发限制也不尽相同:
各浏览器并发统计
究其原因是处于多方面因素的优化考量:
对客户端操作系统而言, 过多的并发涉及到端口数量和线程切换开销.
HTTP/1.1 有 Keep Alive, 支持复用现有连接, 等请求返回回来后, 再复用连接请求可以快很多.
将所有请求一起发给服务器, 也很可能会引发服务器的并发阈值控制而被 BAN.
同样涉及到的优化方式也比较多:
domain hash: 对资源做哈希, 请求到不同的域下面. 关于域名发散与收敛, 其实要对不同场景分别做细化了.
cookie free: 前后端分离, 减少不必要的 cookie 提交.
CSS sprite: 将零星的图片整合到一张大图中, 减少请求次数.
JS/CSS combine: 资源合并, 减少请求次数, 不过也会增加文件修改的几率.
max expires time: 合理设置客户端缓存时间.
loading images on demand: 图片按需加载.
夹带一些这方面的面试题附送给各位:
https://juejin.im/post/5d59ffe46fb9a06ad0056ddf
以上.
参考:
- https://blog.csdn.net/zhang_zhenwei/article/details/90692095
- https://www.cnblogs.com/sunsky303/p/8862128.html
- https://www.zhihu.com/question/20474326
- http://www.stevesouders.com/blog/2008/03/20/roundup-on-parallel-connections/
来源: http://www.jianshu.com/p/f9da8dda2ddb